@carlonicora/nextjs-jsonapi 1.109.0 → 1.111.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 (268) hide show
  1. package/dist/{AssistantMessageInterface-Cs1yb-gF.d.ts → AssistantMessageInterface-BNzf1etU.d.ts} +14 -1
  2. package/dist/{AssistantMessageInterface-DQ3mH5L8.d.mts → AssistantMessageInterface-DrgHDjZ5.d.mts} +14 -1
  3. package/dist/{BlockNoteEditor-3XYBZLWO.js → BlockNoteEditor-7OKW6HHN.js} +19 -20
  4. package/dist/BlockNoteEditor-7OKW6HHN.js.map +1 -0
  5. package/dist/{BlockNoteEditor-EBFZG7AL.mjs → BlockNoteEditor-K7IIWM3S.mjs} +4 -5
  6. package/dist/{BlockNoteEditor-EBFZG7AL.mjs.map → BlockNoteEditor-K7IIWM3S.mjs.map} +1 -1
  7. package/dist/BlockNoteViewer-OPSCTHKJ.mjs +31 -0
  8. package/dist/BlockNoteViewer-OPSCTHKJ.mjs.map +1 -0
  9. package/dist/BlockNoteViewer-UW5VZ5UF.js +31 -0
  10. package/dist/BlockNoteViewer-UW5VZ5UF.js.map +1 -0
  11. package/dist/billing/index.d.mts +41 -41
  12. package/dist/billing/index.d.ts +41 -41
  13. package/dist/billing/index.js +346 -347
  14. package/dist/billing/index.js.map +1 -1
  15. package/dist/billing/index.mjs +3 -4
  16. package/dist/billing/index.mjs.map +1 -1
  17. package/dist/{chunk-7E3O52U5.js → chunk-6XWW67F2.js} +25 -12
  18. package/dist/chunk-6XWW67F2.js.map +1 -0
  19. package/dist/{chunk-UHO3KUUH.js → chunk-AKXUNE3A.js} +977 -850
  20. package/dist/chunk-AKXUNE3A.js.map +1 -0
  21. package/dist/{chunk-UOYIWJEJ.mjs → chunk-CWVYU4YZ.mjs} +18 -5
  22. package/dist/{chunk-UOYIWJEJ.mjs.map → chunk-CWVYU4YZ.mjs.map} +1 -1
  23. package/dist/{chunk-CRTVAQEK.mjs → chunk-TXVVZLUQ.mjs} +1388 -1261
  24. package/dist/chunk-TXVVZLUQ.mjs.map +1 -0
  25. package/dist/{chunk-CFI4WZ5R.js → chunk-U2HR57MY.js} +111 -5
  26. package/dist/chunk-U2HR57MY.js.map +1 -0
  27. package/dist/chunk-WPAQRB5Q.mjs +7 -0
  28. package/dist/chunk-WPAQRB5Q.mjs.map +1 -0
  29. package/dist/chunk-YBZVWLPH.js +7 -0
  30. package/dist/chunk-YBZVWLPH.js.map +1 -0
  31. package/dist/{chunk-MSNNAHDB.mjs → chunk-ZYPNVEHB.mjs} +112 -6
  32. package/dist/{chunk-MSNNAHDB.mjs.map → chunk-ZYPNVEHB.mjs.map} +1 -1
  33. package/dist/client/index.d.mts +3 -4
  34. package/dist/client/index.d.ts +3 -4
  35. package/dist/client/index.js +4 -5
  36. package/dist/client/index.js.map +1 -1
  37. package/dist/client/index.mjs +3 -4
  38. package/dist/components/index.d.mts +418 -415
  39. package/dist/components/index.d.ts +418 -415
  40. package/dist/components/index.js +6 -5
  41. package/dist/components/index.js.map +1 -1
  42. package/dist/components/index.mjs +5 -4
  43. package/dist/{config-CN23v3eJ.d.ts → config-BrkU_Ynz.d.ts} +2 -2
  44. package/dist/{config-gh88Qn4h.d.mts → config-snd2ToEB.d.mts} +2 -2
  45. package/dist/contexts/index.d.mts +15 -15
  46. package/dist/contexts/index.d.ts +15 -15
  47. package/dist/contexts/index.js +4 -5
  48. package/dist/contexts/index.js.map +1 -1
  49. package/dist/contexts/index.mjs +3 -4
  50. package/dist/core/index.d.mts +35 -4
  51. package/dist/core/index.d.ts +35 -4
  52. package/dist/core/index.js +2 -2
  53. package/dist/core/index.mjs +1 -1
  54. package/dist/features/help/index.d.mts +25 -66
  55. package/dist/features/help/index.d.ts +25 -66
  56. package/dist/features/help/index.js +114 -124
  57. package/dist/features/help/index.js.map +1 -1
  58. package/dist/features/help/index.mjs +95 -105
  59. package/dist/features/help/index.mjs.map +1 -1
  60. package/dist/features/help/server.d.mts +27 -65
  61. package/dist/features/help/server.d.ts +27 -65
  62. package/dist/features/help/server.js +4 -119
  63. package/dist/features/help/server.js.map +1 -1
  64. package/dist/features/help/server.mjs +4 -119
  65. package/dist/features/help/server.mjs.map +1 -1
  66. package/dist/help-content-config.interface-C5ESIod9.d.mts +13 -0
  67. package/dist/help-content-config.interface-C5ESIod9.d.ts +13 -0
  68. package/dist/index.d.mts +3 -3
  69. package/dist/index.d.ts +3 -3
  70. package/dist/index.js +3 -4
  71. package/dist/index.js.map +1 -1
  72. package/dist/index.mjs +2 -3
  73. package/dist/scripts/generate-web-module/__tests__/container.spec.d.ts +2 -0
  74. package/dist/scripts/generate-web-module/__tests__/container.spec.d.ts.map +1 -0
  75. package/dist/scripts/generate-web-module/__tests__/container.spec.js +54 -0
  76. package/dist/scripts/generate-web-module/__tests__/container.spec.js.map +1 -0
  77. package/dist/scripts/generate-web-module/__tests__/data-service.spec.d.ts +2 -0
  78. package/dist/scripts/generate-web-module/__tests__/data-service.spec.d.ts.map +1 -0
  79. package/dist/scripts/generate-web-module/__tests__/data-service.spec.js +19 -0
  80. package/dist/scripts/generate-web-module/__tests__/data-service.spec.js.map +1 -0
  81. package/dist/scripts/generate-web-module/__tests__/editor.spec.d.ts +2 -0
  82. package/dist/scripts/generate-web-module/__tests__/editor.spec.d.ts.map +1 -0
  83. package/dist/scripts/generate-web-module/__tests__/editor.spec.js +35 -0
  84. package/dist/scripts/generate-web-module/__tests__/editor.spec.js.map +1 -0
  85. package/dist/scripts/generate-web-module/__tests__/fixtures.d.ts +4 -0
  86. package/dist/scripts/generate-web-module/__tests__/fixtures.d.ts.map +1 -0
  87. package/dist/scripts/generate-web-module/__tests__/fixtures.js +45 -0
  88. package/dist/scripts/generate-web-module/__tests__/fixtures.js.map +1 -0
  89. package/dist/scripts/generate-web-module/__tests__/model-interface.spec.d.ts +2 -0
  90. package/dist/scripts/generate-web-module/__tests__/model-interface.spec.d.ts.map +1 -0
  91. package/dist/scripts/generate-web-module/__tests__/model-interface.spec.js +74 -0
  92. package/dist/scripts/generate-web-module/__tests__/model-interface.spec.js.map +1 -0
  93. package/dist/scripts/generate-web-module/__tests__/plumbing.spec.d.ts +2 -0
  94. package/dist/scripts/generate-web-module/__tests__/plumbing.spec.d.ts.map +1 -0
  95. package/dist/scripts/generate-web-module/__tests__/plumbing.spec.js +21 -0
  96. package/dist/scripts/generate-web-module/__tests__/plumbing.spec.js.map +1 -0
  97. package/dist/scripts/generate-web-module/__tests__/selector.spec.d.ts +2 -0
  98. package/dist/scripts/generate-web-module/__tests__/selector.spec.d.ts.map +1 -0
  99. package/dist/scripts/generate-web-module/__tests__/selector.spec.js +25 -0
  100. package/dist/scripts/generate-web-module/__tests__/selector.spec.js.map +1 -0
  101. package/dist/scripts/generate-web-module/__tests__/table-module-list.spec.d.ts +2 -0
  102. package/dist/scripts/generate-web-module/__tests__/table-module-list.spec.d.ts.map +1 -0
  103. package/dist/scripts/generate-web-module/__tests__/table-module-list.spec.js +55 -0
  104. package/dist/scripts/generate-web-module/__tests__/table-module-list.spec.js.map +1 -0
  105. package/dist/scripts/generate-web-module/generator.d.ts.map +1 -1
  106. package/dist/scripts/generate-web-module/generator.js +14 -11
  107. package/dist/scripts/generate-web-module/generator.js.map +1 -1
  108. package/dist/scripts/generate-web-module/templates/components/container.template.d.ts +5 -1
  109. package/dist/scripts/generate-web-module/templates/components/container.template.d.ts.map +1 -1
  110. package/dist/scripts/generate-web-module/templates/components/container.template.js +43 -63
  111. package/dist/scripts/generate-web-module/templates/components/container.template.js.map +1 -1
  112. package/dist/scripts/generate-web-module/templates/components/content.template.d.ts +7 -4
  113. package/dist/scripts/generate-web-module/templates/components/content.template.d.ts.map +1 -1
  114. package/dist/scripts/generate-web-module/templates/components/content.template.js +103 -14
  115. package/dist/scripts/generate-web-module/templates/components/content.template.js.map +1 -1
  116. package/dist/scripts/generate-web-module/templates/components/editor.template.d.ts +1 -1
  117. package/dist/scripts/generate-web-module/templates/components/editor.template.js +139 -150
  118. package/dist/scripts/generate-web-module/templates/components/editor.template.js.map +1 -1
  119. package/dist/scripts/generate-web-module/templates/components/index.d.ts +0 -1
  120. package/dist/scripts/generate-web-module/templates/components/index.d.ts.map +1 -1
  121. package/dist/scripts/generate-web-module/templates/components/index.js +1 -3
  122. package/dist/scripts/generate-web-module/templates/components/index.js.map +1 -1
  123. package/dist/scripts/generate-web-module/templates/components/list-container.template.js +2 -2
  124. package/dist/scripts/generate-web-module/templates/components/list.template.d.ts.map +1 -1
  125. package/dist/scripts/generate-web-module/templates/components/list.template.js +6 -1
  126. package/dist/scripts/generate-web-module/templates/components/list.template.js.map +1 -1
  127. package/dist/scripts/generate-web-module/templates/components/selector.template.d.ts.map +1 -1
  128. package/dist/scripts/generate-web-module/templates/components/selector.template.js +48 -52
  129. package/dist/scripts/generate-web-module/templates/components/selector.template.js.map +1 -1
  130. package/dist/scripts/generate-web-module/templates/data/interface.template.d.ts.map +1 -1
  131. package/dist/scripts/generate-web-module/templates/data/interface.template.js +38 -11
  132. package/dist/scripts/generate-web-module/templates/data/interface.template.js.map +1 -1
  133. package/dist/scripts/generate-web-module/templates/data/model.template.d.ts.map +1 -1
  134. package/dist/scripts/generate-web-module/templates/data/model.template.js +83 -26
  135. package/dist/scripts/generate-web-module/templates/data/model.template.js.map +1 -1
  136. package/dist/scripts/generate-web-module/templates/data/service.template.d.ts.map +1 -1
  137. package/dist/scripts/generate-web-module/templates/data/service.template.js +21 -1
  138. package/dist/scripts/generate-web-module/templates/data/service.template.js.map +1 -1
  139. package/dist/scripts/generate-web-module/templates/index.d.ts +1 -1
  140. package/dist/scripts/generate-web-module/templates/index.d.ts.map +1 -1
  141. package/dist/scripts/generate-web-module/templates/index.js +1 -2
  142. package/dist/scripts/generate-web-module/templates/index.js.map +1 -1
  143. package/dist/scripts/generate-web-module/templates/module.template.d.ts.map +1 -1
  144. package/dist/scripts/generate-web-module/templates/module.template.js +11 -3
  145. package/dist/scripts/generate-web-module/templates/module.template.js.map +1 -1
  146. package/dist/scripts/generate-web-module/templates/table-hook.template.js +31 -1
  147. package/dist/scripts/generate-web-module/templates/table-hook.template.js.map +1 -1
  148. package/dist/scripts/generate-web-module/transformers/import-resolver.d.ts +0 -1
  149. package/dist/scripts/generate-web-module/transformers/import-resolver.d.ts.map +1 -1
  150. package/dist/scripts/generate-web-module/transformers/import-resolver.js +0 -1
  151. package/dist/scripts/generate-web-module/transformers/import-resolver.js.map +1 -1
  152. package/dist/scripts/generate-web-module/transformers/relationship-key.d.ts +5 -0
  153. package/dist/scripts/generate-web-module/transformers/relationship-key.d.ts.map +1 -0
  154. package/dist/scripts/generate-web-module/transformers/relationship-key.js +21 -0
  155. package/dist/scripts/generate-web-module/transformers/relationship-key.js.map +1 -0
  156. package/dist/scripts/generate-web-module/transformers/relationship-resolver.d.ts.map +1 -1
  157. package/dist/scripts/generate-web-module/transformers/relationship-resolver.js +2 -0
  158. package/dist/scripts/generate-web-module/transformers/relationship-resolver.js.map +1 -1
  159. package/dist/scripts/generate-web-module/types/json-schema.interface.d.ts +21 -0
  160. package/dist/scripts/generate-web-module/types/json-schema.interface.d.ts.map +1 -1
  161. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts +17 -0
  162. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts.map +1 -1
  163. package/dist/server/index.js +3 -3
  164. package/dist/server/index.mjs +1 -1
  165. package/dist/testing/index.d.mts +1 -2
  166. package/dist/testing/index.d.ts +1 -2
  167. package/package.json +1 -6
  168. package/scripts/generate-web-module/__tests__/container.spec.ts +58 -0
  169. package/scripts/generate-web-module/__tests__/data-service.spec.ts +18 -0
  170. package/scripts/generate-web-module/__tests__/editor.spec.ts +36 -0
  171. package/scripts/generate-web-module/__tests__/fixtures.ts +43 -0
  172. package/scripts/generate-web-module/__tests__/model-interface.spec.ts +77 -0
  173. package/scripts/generate-web-module/__tests__/plumbing.spec.ts +21 -0
  174. package/scripts/generate-web-module/__tests__/selector.spec.ts +24 -0
  175. package/scripts/generate-web-module/__tests__/table-module-list.spec.ts +59 -0
  176. package/scripts/generate-web-module/generator.ts +14 -13
  177. package/scripts/generate-web-module/templates/components/container.template.ts +51 -66
  178. package/scripts/generate-web-module/templates/components/content.template.ts +107 -15
  179. package/scripts/generate-web-module/templates/components/editor.template.ts +140 -152
  180. package/scripts/generate-web-module/templates/components/index.ts +0 -1
  181. package/scripts/generate-web-module/templates/components/list-container.template.ts +2 -2
  182. package/scripts/generate-web-module/templates/components/list.template.ts +6 -1
  183. package/scripts/generate-web-module/templates/components/selector.template.ts +48 -52
  184. package/scripts/generate-web-module/templates/data/interface.template.ts +44 -12
  185. package/scripts/generate-web-module/templates/data/model.template.ts +88 -28
  186. package/scripts/generate-web-module/templates/data/service.template.ts +23 -1
  187. package/scripts/generate-web-module/templates/index.ts +0 -1
  188. package/scripts/generate-web-module/templates/module.template.ts +13 -3
  189. package/scripts/generate-web-module/templates/table-hook.template.ts +31 -2
  190. package/scripts/generate-web-module/transformers/import-resolver.ts +0 -2
  191. package/scripts/generate-web-module/transformers/relationship-key.ts +18 -0
  192. package/scripts/generate-web-module/transformers/relationship-resolver.ts +2 -0
  193. package/scripts/generate-web-module/types/json-schema.interface.ts +9 -0
  194. package/scripts/generate-web-module/types/template-data.interface.ts +7 -0
  195. package/src/client/config.ts +1 -1
  196. package/src/components/index.ts +1 -0
  197. package/src/components/viewers/BlockNoteViewer.tsx +27 -0
  198. package/src/components/viewers/BlockNoteViewerContainer.tsx +10 -0
  199. package/src/core/registry/helpStore.ts +2 -19
  200. package/src/features/assistant-message/components/parts/MessageSourcesContainer.tsx +4 -0
  201. package/src/features/assistant-message/components/parts/tabs/ContentsTab.tsx +5 -5
  202. package/src/features/assistant-message/components/parts/tabs/ReferencesTab.tsx +3 -2
  203. package/src/features/help/components/HelpArticleBody.tsx +27 -19
  204. package/src/features/help/components/HelpHint.tsx +20 -11
  205. package/src/features/help/components/HelpSearchResultRow.tsx +16 -6
  206. package/src/features/help/components/HelpSideNav.tsx +54 -19
  207. package/src/features/help/components/__tests__/HelpAskAi.spec.tsx +1 -1
  208. package/src/features/help/components/__tests__/HelpHint.spec.tsx +17 -17
  209. package/src/features/help/components/__tests__/HelpSearchResultRow.spec.tsx +18 -19
  210. package/src/features/help/components/__tests__/HelpSideNav.spec.tsx +20 -22
  211. package/src/features/help/contexts/HelpContext.spec.tsx +1 -3
  212. package/src/features/help/index.ts +3 -6
  213. package/src/features/help/interfaces/help-content-config.interface.ts +0 -5
  214. package/src/features/help/server-entry.ts +6 -15
  215. package/src/features/help/types/help-article.types.ts +2 -4
  216. package/src/features/how-to/HowToModule.ts +14 -1
  217. package/src/features/how-to/components/forms/HowToEditor.tsx +108 -4
  218. package/src/features/how-to/data/HowTo.spec.ts +43 -0
  219. package/src/features/how-to/data/HowTo.ts +47 -4
  220. package/src/features/how-to/data/HowToInterface.ts +14 -1
  221. package/src/features/how-to/data/HowToService.ts +61 -0
  222. package/dist/BlockNoteEditor-3XYBZLWO.js.map +0 -1
  223. package/dist/chunk-3J7RQBF3.js +0 -123
  224. package/dist/chunk-3J7RQBF3.js.map +0 -1
  225. package/dist/chunk-7E3O52U5.js.map +0 -1
  226. package/dist/chunk-CFI4WZ5R.js.map +0 -1
  227. package/dist/chunk-CQID6RCF.mjs +0 -38
  228. package/dist/chunk-CQID6RCF.mjs.map +0 -1
  229. package/dist/chunk-CRTVAQEK.mjs.map +0 -1
  230. package/dist/chunk-MZTKPPET.mjs +0 -123
  231. package/dist/chunk-MZTKPPET.mjs.map +0 -1
  232. package/dist/chunk-UHO3KUUH.js.map +0 -1
  233. package/dist/chunk-YQQHAFBS.js +0 -38
  234. package/dist/chunk-YQQHAFBS.js.map +0 -1
  235. package/dist/features/help/server/createHelpAssetRouteHandler.d.mts +0 -11
  236. package/dist/features/help/server/createHelpAssetRouteHandler.d.ts +0 -11
  237. package/dist/features/help/server/createHelpAssetRouteHandler.js +0 -43
  238. package/dist/features/help/server/createHelpAssetRouteHandler.js.map +0 -1
  239. package/dist/features/help/server/createHelpAssetRouteHandler.mjs +0 -43
  240. package/dist/features/help/server/createHelpAssetRouteHandler.mjs.map +0 -1
  241. package/dist/help-content-config.interface-B9L02u9i.d.mts +0 -50
  242. package/dist/help-content-config.interface-B9L02u9i.d.ts +0 -50
  243. package/dist/scripts/generate-web-module/templates/components/details.template.d.ts +0 -14
  244. package/dist/scripts/generate-web-module/templates/components/details.template.d.ts.map +0 -1
  245. package/dist/scripts/generate-web-module/templates/components/details.template.js +0 -112
  246. package/dist/scripts/generate-web-module/templates/components/details.template.js.map +0 -1
  247. package/scripts/generate-web-module/templates/components/details.template.ts +0 -116
  248. package/src/features/help/components/mdx/Callout.tsx +0 -21
  249. package/src/features/help/components/mdx/EntityRef.tsx +0 -18
  250. package/src/features/help/components/mdx/KeyBinding.tsx +0 -6
  251. package/src/features/help/components/mdx/Related.tsx +0 -33
  252. package/src/features/help/components/mdx/Screenshot.tsx +0 -9
  253. package/src/features/help/components/mdx/Steps.tsx +0 -21
  254. package/src/features/help/components/mdx/Video.tsx +0 -8
  255. package/src/features/help/components/mdx/mdx-server-components.ts +0 -23
  256. package/src/features/help/components/mdx/mdxComponents.ts +0 -9
  257. package/src/features/help/hooks/useHelpArticle.ts +0 -7
  258. package/src/features/help/hooks/useHelpManifest.ts +0 -5
  259. package/src/features/help/server/__tests__/createHelpAssetRouteHandler.spec.ts +0 -43
  260. package/src/features/help/server/createHelpAssetRouteHandler.ts +0 -35
  261. package/src/features/help/server/generateHelpArticleMetadata.ts +0 -18
  262. package/src/features/help/server/generateHelpArticleStaticParams.ts +0 -7
  263. package/src/features/help/server/generateHelpModeStaticParams.ts +0 -5
  264. package/src/features/help/server/getHelpContent.ts +0 -17
  265. package/src/features/help/server/index.ts +0 -8
  266. package/src/features/help/server/serializeHelpArticle.tsx +0 -46
  267. package/src/features/help/utils/__tests__/helpNavigation.spec.ts +0 -70
  268. package/src/features/help/utils/helpNavigation.ts +0 -29
@@ -1,50 +1,50 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
2
- import { render, screen } from "@testing-library/react";
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import { render, screen, waitFor } from "@testing-library/react";
3
3
  import { configureJsonApi } from "../../../../client/config";
4
4
  import { HelpProvider } from "../../contexts/HelpContext";
5
5
  import { HelpHint } from "../HelpHint";
6
+ import { HowToService } from "../../../how-to/data/HowToService";
7
+
8
+ vi.mock("../../../how-to/data/HowToService", () => ({
9
+ HowToService: { findPublished: vi.fn() },
10
+ }));
6
11
 
7
12
  const article = {
8
13
  id: "1",
9
14
  slug: "x",
10
- mode: "how-to",
11
- title: "X",
15
+ howToType: "how-to",
16
+ name: "X",
12
17
  summary: "S",
13
- order: 1,
14
- tags: [],
15
18
  contextualKeys: ["npc.editor"],
16
- aiIndexed: true,
17
19
  draft: false,
18
- contentHash: "h",
19
- path: "how-to/x.mdx",
20
- headings: [],
21
- relatedSlugs: [],
22
- lastUpdated: "2026-01-01T00:00:00Z",
23
- };
20
+ } as any;
24
21
 
25
22
  beforeEach(() => {
23
+ vi.clearAllMocks();
24
+ vi.mocked(HowToService.findPublished).mockResolvedValue([article]);
26
25
  configureJsonApi({
27
26
  apiUrl: "http://localhost",
28
- helpContent: { manifest: [article], namespaceUuid: "00000000-0000-5000-8000-000000000000" },
27
+ helpContent: { brand: { label: "narr8" } },
29
28
  });
30
29
  });
31
30
 
32
31
  describe("HelpHint", () => {
33
- it("renders null when no article matches the contextKey", () => {
32
+ it("renders null when no published article matches the contextKey", async () => {
34
33
  const { container } = render(
35
34
  <HelpProvider>
36
35
  <HelpHint contextKey="nope.absent" />
37
36
  </HelpProvider>,
38
37
  );
38
+ await waitFor(() => expect(HowToService.findPublished).toHaveBeenCalled());
39
39
  expect(container.querySelector("button")).toBeNull();
40
40
  });
41
41
 
42
- it("renders the trigger when at least one article matches", () => {
42
+ it("renders the trigger when at least one published article matches", async () => {
43
43
  render(
44
44
  <HelpProvider>
45
45
  <HelpHint contextKey="npc.editor" />
46
46
  </HelpProvider>,
47
47
  );
48
- expect(screen.getByLabelText(/help on this|hint/i)).toBeTruthy();
48
+ expect(await screen.findByLabelText(/help on this|hint/i)).toBeTruthy();
49
49
  });
50
50
  });
@@ -1,37 +1,34 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
2
- import { render, screen } from "@testing-library/react";
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import { render, screen, waitFor } from "@testing-library/react";
3
3
  import { Command, CommandList } from "../../../../shadcnui";
4
4
  import { configureJsonApi } from "../../../../client/config";
5
5
  import { HelpProvider } from "../../contexts/HelpContext";
6
6
  import { HelpSearchResultRow } from "../HelpSearchResultRow";
7
+ import { HowToService } from "../../../how-to/data/HowToService";
8
+
9
+ vi.mock("../../../how-to/data/HowToService", () => ({
10
+ HowToService: { findOne: vi.fn() },
11
+ }));
7
12
 
8
13
  const article = {
9
14
  id: "abc",
10
15
  slug: "x",
11
- mode: "how-to" as const,
12
- title: "X title",
16
+ howToType: "how-to",
17
+ name: "X title",
13
18
  summary: "S",
14
- order: 1,
15
- tags: [],
16
- contextualKeys: [],
17
- aiIndexed: true,
18
- draft: false,
19
- contentHash: "h",
20
- path: "how-to/x.mdx",
21
- headings: [],
22
- relatedSlugs: [],
23
- lastUpdated: "2026-01-01T00:00:00Z",
24
- };
19
+ } as any;
25
20
 
26
21
  beforeEach(() => {
22
+ vi.clearAllMocks();
27
23
  configureJsonApi({
28
24
  apiUrl: "http://localhost",
29
- helpContent: { manifest: [article], namespaceUuid: "00000000-0000-5000-8000-000000000000" },
25
+ helpContent: { brand: { label: "narr8" } },
30
26
  });
31
27
  });
32
28
 
33
29
  describe("HelpSearchResultRow", () => {
34
- it("renders the article title when manifest contains the id", () => {
30
+ it("renders the article title when the service returns the how-to", async () => {
31
+ vi.mocked(HowToService.findOne).mockResolvedValue(article);
35
32
  render(
36
33
  <HelpProvider>
37
34
  <Command>
@@ -41,10 +38,11 @@ describe("HelpSearchResultRow", () => {
41
38
  </Command>
42
39
  </HelpProvider>,
43
40
  );
44
- expect(screen.getByText("X title")).toBeTruthy();
41
+ expect(await screen.findByText("X title")).toBeTruthy();
45
42
  });
46
43
 
47
- it("renders disabled removed-state row when id is missing", () => {
44
+ it("renders disabled removed-state row when the service has no how-to", async () => {
45
+ vi.mocked(HowToService.findOne).mockRejectedValue(new Error("not found"));
48
46
  render(
49
47
  <HelpProvider>
50
48
  <Command>
@@ -54,6 +52,7 @@ describe("HelpSearchResultRow", () => {
54
52
  </Command>
55
53
  </HelpProvider>,
56
54
  );
55
+ await waitFor(() => expect(HowToService.findOne).toHaveBeenCalledWith({ id: "ghost" }));
57
56
  expect(screen.queryByText("X title")).toBeNull();
58
57
  });
59
58
  });
@@ -1,50 +1,48 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
2
  import { render, screen, fireEvent } from "@testing-library/react";
3
3
  import { configureJsonApi } from "../../../../client/config";
4
4
  import { HelpProvider } from "../../contexts/HelpContext";
5
5
  import { HelpSideNav } from "../HelpSideNav";
6
6
 
7
- const base = {
8
- tags: [],
9
- contextualKeys: [],
10
- aiIndexed: true,
11
- draft: false,
12
- contentHash: "h",
13
- headings: [],
14
- relatedSlugs: [],
15
- lastUpdated: "2026-01-01T00:00:00Z",
16
- };
7
+ // HelpSideNav now sources its list from the public API via
8
+ // HowToService.findPublished() (Plan 3b) instead of the help manifest, so the
9
+ // test mocks the service rather than seeding the manifest.
10
+ vi.mock("../../../how-to/data/HowToService", () => ({
11
+ HowToService: { findPublished: vi.fn() },
12
+ }));
13
+ import { HowToService } from "../../../how-to/data/HowToService";
14
+
15
+ const published = [
16
+ { id: "a", name: "Alpha", summary: "s", tags: [], howToType: "how-to", slug: "a", order: 1, draft: false },
17
+ { id: "b", name: "Beta", summary: "s", tags: [], howToType: "how-to", slug: "b", order: 2, draft: false },
18
+ ];
17
19
 
18
20
  beforeEach(() => {
19
21
  configureJsonApi({
20
22
  apiUrl: "http://localhost",
21
- helpContent: {
22
- manifest: [
23
- { ...base, id: "a", slug: "a", mode: "how-to", title: "Alpha", summary: "s", order: 1, path: "how-to/a.mdx" },
24
- { ...base, id: "b", slug: "b", mode: "how-to", title: "Beta", summary: "s", order: 2, path: "how-to/b.mdx" },
25
- ],
26
- namespaceUuid: "00000000-0000-5000-8000-000000000000",
27
- },
23
+ helpContent: { brand: { label: "narr8" } },
28
24
  });
25
+ (HowToService.findPublished as ReturnType<typeof vi.fn>).mockResolvedValue(published as any);
29
26
  });
30
27
 
31
28
  describe("HelpSideNav", () => {
32
- it("lists every non-draft article", () => {
29
+ it("lists every non-draft article", async () => {
33
30
  render(
34
31
  <HelpProvider>
35
32
  <HelpSideNav />
36
33
  </HelpProvider>,
37
34
  );
38
- expect(screen.getByText("Alpha")).toBeTruthy();
39
- expect(screen.getByText("Beta")).toBeTruthy();
35
+ expect(await screen.findByText("Alpha")).toBeTruthy();
36
+ expect(await screen.findByText("Beta")).toBeTruthy();
40
37
  });
41
38
 
42
- it("filters by query", () => {
39
+ it("filters by query", async () => {
43
40
  render(
44
41
  <HelpProvider>
45
42
  <HelpSideNav />
46
43
  </HelpProvider>,
47
44
  );
45
+ await screen.findByText("Alpha");
48
46
  fireEvent.change(screen.getByPlaceholderText(/filter/i), { target: { value: "Bet" } });
49
47
  expect(screen.queryByText("Alpha")).toBeNull();
50
48
  expect(screen.getByText("Beta")).toBeTruthy();
@@ -6,8 +6,6 @@ import { HelpProvider, useHelp } from "./HelpContext";
6
6
 
7
7
  describe("HelpProvider / useHelp", () => {
8
8
  const cfg = {
9
- manifest: [],
10
- namespaceUuid: "00000000-0000-5000-8000-000000000000",
11
9
  brand: { logo: "/logo.png", label: "Test", appHref: "/" },
12
10
  };
13
11
 
@@ -18,8 +16,8 @@ describe("HelpProvider / useHelp", () => {
18
16
  it("exposes the configured helpContent via useHelp()", () => {
19
17
  const wrapper = ({ children }: { children: ReactNode }) => <HelpProvider>{children}</HelpProvider>;
20
18
  const { result } = renderHook(() => useHelp(), { wrapper });
21
- expect(result.current.manifest).toBe(cfg.manifest);
22
19
  expect(result.current.brand?.label).toBe("Test");
20
+ expect(result.current.brand?.appHref).toBe("/");
23
21
  });
24
22
 
25
23
  it("throws when useHelp() is called outside HelpProvider", () => {
@@ -2,11 +2,11 @@
2
2
  // Consumed via `@carlonicora/nextjs-jsonapi/help`. Tsup adds a top-level
3
3
  // "use client" directive to the bundled output via clientEntries.
4
4
  //
5
- // Pair this with `@carlonicora/nextjs-jsonapi/help/server` (server) for the
6
- // pure server utilities (serializeHelpArticle, generate*StaticParams, etc.).
5
+ // Pair this with `@carlonicora/nextjs-jsonapi/help/server` for the server-safe
6
+ // HELP_MODES constant + article types (imported by server-component pages).
7
7
  // Consumers compose page shells themselves: import the client primitives below
8
8
  // (HelpProvider, HelpHeader, HelpSideNav, HelpArticleBody, HelpTOC, etc.) and
9
- // the server utilities from /help/server, then assemble pages in app routes.
9
+ // assemble pages in app routes.
10
10
 
11
11
  export { HelpProvider, useHelp } from "./contexts/HelpContext";
12
12
  export { HelpHeader } from "./components/HelpHeader";
@@ -16,9 +16,6 @@ export { HelpTOC } from "./components/HelpTOC";
16
16
  export { HelpHint } from "./components/HelpHint";
17
17
  export { HelpAskAi } from "./components/HelpAskAi";
18
18
  export { HelpSearchResultRow } from "./components/HelpSearchResultRow";
19
- export { MDX_COMPONENTS } from "./components/mdx/mdxComponents";
20
- export { useHelpManifest } from "./hooks/useHelpManifest";
21
- export { useHelpArticle } from "./hooks/useHelpArticle";
22
19
  export { useHelpFilter } from "./hooks/useHelpFilter";
23
20
  export { articleUrl, modeUrl } from "./utils/articleUrl";
24
21
  export { HELP_I18N_KEYS } from "./i18n-keys";
@@ -1,5 +1,3 @@
1
- import type { HelpArticle, HelpRedirect } from "../types/help-article.types";
2
-
3
1
  export interface HelpBrandConfig {
4
2
  /** URL of the brand logo image (served by the consuming app). */
5
3
  logo?: string;
@@ -10,8 +8,5 @@ export interface HelpBrandConfig {
10
8
  }
11
9
 
12
10
  export interface HelpContentConfig {
13
- manifest: readonly HelpArticle[];
14
- namespaceUuid: string;
15
- redirects?: readonly HelpRedirect[];
16
11
  brand?: HelpBrandConfig;
17
12
  }
@@ -1,20 +1,11 @@
1
- // Server-only public barrel for the help feature.
1
+ // Server-safe public barrel for the help feature.
2
2
  // Consumed via `@carlonicora/nextjs-jsonapi/help/server`. Must NOT receive a
3
- // "use client" directive.
3
+ // "use client" directive — server components (e.g. the /help index + mode pages)
4
+ // import HELP_MODES/HelpMode from here without pulling the client bundle.
4
5
  //
5
- // This barrel exposes only server-safe utilities (no React components). The
6
- // React Server Component / Client Component boundary is enforced by tsup-level
7
- // bundle splitting: server containers cannot directly import client components
8
- // without leaking client-only modules (react-dom/client, hook usage at module
9
- // init) into server scopes. Consumers therefore compose the page shells in
10
- // their own route files, importing client primitives from
11
- // `@carlonicora/nextjs-jsonapi/help` and server utilities from here.
6
+ // Now that help articles are served from the API (HowTo) rather than the MDX
7
+ // manifest, this barrel exposes only the shared mode constant + article types.
8
+ // Client primitives live in `@carlonicora/nextjs-jsonapi/help`.
12
9
 
13
- export { getHelpContent } from "./server/getHelpContent";
14
- export { renderHelpArticle, serializeHelpArticle } from "./server/serializeHelpArticle";
15
- export { generateHelpArticleStaticParams, generateHelpArticleMetadata, generateHelpModeStaticParams } from "./server";
16
- export { findHelpArticle, prevNextWithinMode, buildHelpNav } from "./utils/helpNavigation";
17
- export { setHelpReader } from "../../core/registry/helpStore";
18
- export type { HelpContentConfig, HelpBrandConfig } from "./interfaces/help-content-config.interface";
19
10
  export { HELP_MODES } from "./types/help-article.types";
20
11
  export type { HelpArticle, HelpHeading, HelpMode, HelpRedirect } from "./types/help-article.types";
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Local copy of the help-article types to keep this published frontend library
3
- * decoupled from `@carlonicora/nestjs-neo4jsonapi`. Must stay in sync with
4
- * `packages/nestjs-neo4jsonapi/src/foundations/help-content-sync/interfaces/help-article.interface.ts`.
2
+ * Help-article types for the frontend help feature. Self-contained the
3
+ * published frontend library stays decoupled from `@carlonicora/nestjs-neo4jsonapi`.
5
4
  */
6
5
 
7
6
  export const HELP_MODES = ["tutorial", "how-to", "reference", "explanation"] as const;
@@ -24,7 +23,6 @@ export interface HelpArticle {
24
23
  contextualKeys: readonly string[];
25
24
  aiIndexed: boolean;
26
25
  draft: boolean;
27
- contentHash: string;
28
26
  path: string;
29
27
  headings: readonly HelpHeading[];
30
28
  relatedSlugs: readonly string[];
@@ -12,7 +12,20 @@ export const HowToModule = (factory: ModuleFactory) =>
12
12
  icon: LifeBuoyIcon,
13
13
  inclusions: {
14
14
  lists: {
15
- fields: [createJsonApiInclusion("howtos", [`name`, `description`, `pages`, `helpContentSlug`])],
15
+ fields: [
16
+ createJsonApiInclusion("howtos", [
17
+ "name",
18
+ "description",
19
+ "pages",
20
+ "howToType",
21
+ "slug",
22
+ "order",
23
+ "summary",
24
+ "tags",
25
+ "contextualKeys",
26
+ "draft",
27
+ ]),
28
+ ],
16
29
  },
17
30
  },
18
31
  });
@@ -3,12 +3,12 @@
3
3
  import { zodResolver } from "@hookform/resolvers/zod";
4
4
  import { PlusIcon, SearchIcon, XIcon } from "lucide-react";
5
5
  import { useTranslations } from "next-intl";
6
- import { ReactNode, useCallback, useMemo, useState } from "react";
6
+ import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
7
7
  import { useForm } from "react-hook-form";
8
8
  import { v4 } from "uuid";
9
9
  import { z } from "zod";
10
10
 
11
- import { EditorSheet, FormInput } from "../../../../components";
11
+ import { EditorSheet, FormInput, FormSelect, FormTextarea, FormCheckbox } from "../../../../components";
12
12
  import { BlockNoteEditorContainer } from "../../../../components";
13
13
  import { ModuleRegistry, Modules } from "../../../../core";
14
14
  import { useI18nRouter } from "../../../../hooks";
@@ -27,6 +27,9 @@ import {
27
27
  import { HowTo } from "../../data/HowTo";
28
28
  import { HowToInput, HowToInterface } from "../../data/HowToInterface";
29
29
  import { HowToService } from "../../data/HowToService";
30
+ import HowToMultiSelector from "./HowToMultiSelector";
31
+
32
+ const HOW_TO_TYPES = ["tutorial", "how-to", "reference", "explanation"] as const;
30
33
 
31
34
  function PageSelector({
32
35
  value,
@@ -140,6 +143,14 @@ function HowToEditorInternal({
140
143
  name: z.string().min(1, { message: t(`howto.fields.name.error`) }),
141
144
  description: z.any(),
142
145
  pages: z.array(z.string()),
146
+ howToType: z.enum(HOW_TO_TYPES),
147
+ slug: z.string().min(1, { message: t(`howto.fields.slug.error`) }),
148
+ order: z.number().int().min(0),
149
+ summary: z.string().optional(),
150
+ tags: z.string().optional(),
151
+ contextualKeys: z.string().optional(),
152
+ draft: z.boolean().optional(),
153
+ relatedArticles: z.array(z.object({ id: z.string().uuid(), name: z.string() })).optional(),
143
154
  }),
144
155
  [t],
145
156
  );
@@ -150,6 +161,14 @@ function HowToEditorInternal({
150
161
  name: howTo?.name || "",
151
162
  description: howTo?.description || [],
152
163
  pages: HowTo.parsePagesFromString(howTo?.pages),
164
+ howToType: (howTo?.howToType as (typeof HOW_TO_TYPES)[number]) ?? "how-to",
165
+ slug: howTo?.slug ?? "",
166
+ order: howTo?.order ?? 0,
167
+ summary: howTo?.summary ?? "",
168
+ tags: (howTo?.tags ?? []).join(", "),
169
+ contextualKeys: (howTo?.contextualKeys ?? []).join(", "),
170
+ draft: howTo?.draft ?? false,
171
+ relatedArticles: [] as { id: string; name: string }[],
153
172
  }),
154
173
  [howTo],
155
174
  );
@@ -159,6 +178,26 @@ function HowToEditorInternal({
159
178
  defaultValues: getDefaultValues(),
160
179
  });
161
180
 
181
+ const initialRelatedIds = useRef<string[]>([]);
182
+ useEffect(() => {
183
+ if (!howTo?.howToType || !howTo?.slug) return;
184
+ let active = true;
185
+ HowToService.findRelated({ howToType: howTo.howToType, slug: howTo.slug })
186
+ .then((list) => {
187
+ if (!active) return;
188
+ initialRelatedIds.current = list.map((r) => r.id);
189
+ form.setValue(
190
+ "relatedArticles",
191
+ list.map((r) => ({ id: r.id, name: r.name })),
192
+ { shouldDirty: false },
193
+ );
194
+ })
195
+ .catch(() => {});
196
+ return () => {
197
+ active = false;
198
+ };
199
+ }, [howTo, form]);
200
+
162
201
  const handleDescriptionChange = useCallback(
163
202
  (content: any) => {
164
203
  form.setValue("description", content, { shouldDirty: true });
@@ -191,17 +230,40 @@ function HowToEditorInternal({
191
230
  propagateChanges={propagateChanges}
192
231
  size="lg"
193
232
  onSubmit={async (values) => {
233
+ const toList = (s?: string) =>
234
+ (s ?? "")
235
+ .split(",")
236
+ .map((x) => x.trim())
237
+ .filter(Boolean);
238
+
194
239
  const payload: HowToInput = {
195
240
  id: values.id,
196
241
  name: values.name,
197
242
  authorId: "",
198
243
  description: values.description,
199
244
  pages: HowTo.serializePagesToString(values.pages),
245
+ howToType: values.howToType,
246
+ slug: values.slug,
247
+ order: values.order,
248
+ summary: values.summary,
249
+ tags: toList(values.tags),
250
+ contextualKeys: toList(values.contextualKeys),
251
+ draft: values.draft ?? false,
200
252
  };
201
253
 
202
- const updatedHowTo = howTo ? await HowToService.update(payload) : await HowToService.create(payload);
254
+ const saved = howTo ? await HowToService.update(payload) : await HowToService.create(payload);
203
255
 
204
- return updatedHowTo;
256
+ const desired = new Set((values.relatedArticles ?? []).map((r) => r.id));
257
+ const current = new Set(initialRelatedIds.current);
258
+ for (const relatedId of desired) {
259
+ if (!current.has(relatedId)) await HowToService.addRelated({ howToId: values.id, relatedId });
260
+ }
261
+ for (const relatedId of current) {
262
+ if (!desired.has(relatedId)) await HowToService.removeRelated({ howToId: values.id, relatedId });
263
+ }
264
+ initialRelatedIds.current = Array.from(desired);
265
+
266
+ return saved;
205
267
  }}
206
268
  onReset={() => {
207
269
  return getDefaultValues();
@@ -222,6 +284,28 @@ function HowToEditorInternal({
222
284
  placeholder={t(`howto.fields.name.placeholder`)}
223
285
  isRequired
224
286
  />
287
+ <FormSelect
288
+ form={form}
289
+ id="howToType"
290
+ name={t(`howto.fields.howToType.label`)}
291
+ placeholder={t(`howto.fields.howToType.placeholder`)}
292
+ values={HOW_TO_TYPES.map((m) => ({ id: m, text: t(`howto.howToType.${m}` as any) }))}
293
+ isRequired
294
+ />
295
+ <FormInput
296
+ form={form}
297
+ id="slug"
298
+ name={t(`howto.fields.slug.label`)}
299
+ placeholder={t(`howto.fields.slug.placeholder`)}
300
+ isRequired
301
+ />
302
+ <FormInput form={form} id="order" name={t(`howto.fields.order.label`)} type="number" />
303
+ <FormTextarea
304
+ form={form}
305
+ id="summary"
306
+ name={t(`howto.fields.summary.label`)}
307
+ placeholder={t(`howto.fields.summary.placeholder`)}
308
+ />
225
309
  <div className="space-y-2">
226
310
  <Label>{t(`howto.fields.description.label`)}</Label>
227
311
  <div className="max-h-80 overflow-y-auto rounded-md border">
@@ -260,6 +344,26 @@ function HowToEditorInternal({
260
344
  </Button>
261
345
  </div>
262
346
  </div>
347
+ <FormInput
348
+ form={form}
349
+ id="tags"
350
+ name={t(`howto.fields.tags.label`)}
351
+ placeholder={t(`howto.fields.tags.placeholder`)}
352
+ />
353
+ <FormInput
354
+ form={form}
355
+ id="contextualKeys"
356
+ name={t(`howto.fields.contextualKeys.label`)}
357
+ placeholder={t(`howto.fields.contextualKeys.placeholder`)}
358
+ />
359
+ <HowToMultiSelector
360
+ id="relatedArticles"
361
+ form={form}
362
+ currentHowTo={howTo}
363
+ label={t(`howto.fields.relatedArticles.label`)}
364
+ placeholder={t(`howto.fields.relatedArticles.placeholder`)}
365
+ />
366
+ <FormCheckbox form={form} id="draft" name={t(`howto.fields.draft.label`)} />
263
367
  </div>
264
368
  </EditorSheet>
265
369
  );
@@ -0,0 +1,43 @@
1
+ import { beforeAll, describe, it, expect } from "vitest";
2
+ import { ApiRequestDataTypeInterface } from "../../../core/interfaces/ApiRequestDataTypeInterface";
3
+ import { ModuleRegistry } from "../../../core/registry/ModuleRegistry";
4
+ import { HowTo } from "./HowTo";
5
+
6
+ // createJsonApi reads Modules.HowTo.name (resolved lazily via ModuleRegistry),
7
+ // so the module must be registered before the model serialises — mirrors the
8
+ // AssistantMessage.spec setup convention in this package.
9
+ const howToModule: ApiRequestDataTypeInterface = {
10
+ name: "howtos",
11
+ model: HowTo,
12
+ } as any;
13
+
14
+ beforeAll(() => {
15
+ ModuleRegistry.register("HowTo", howToModule);
16
+ });
17
+
18
+ describe("HowTo.createJsonApi", () => {
19
+ it("serialises the new attributes", () => {
20
+ const res = new HowTo().createJsonApi({
21
+ id: "11111111-1111-4111-8111-111111111111",
22
+ name: "Add an NPC",
23
+ authorId: "",
24
+ description: [{ type: "paragraph", content: [] }],
25
+ howToType: "how-to",
26
+ slug: "add-an-npc",
27
+ order: 30,
28
+ summary: "Create a Non-Player Character.",
29
+ tags: ["world"],
30
+ contextualKeys: ["npc.editor"],
31
+ draft: false,
32
+ });
33
+ const a = res.data.attributes;
34
+ expect(a.howToType).toBe("how-to");
35
+ expect(a.slug).toBe("add-an-npc");
36
+ expect(a.order).toBe(30);
37
+ expect(a.summary).toBe("Create a Non-Player Character.");
38
+ expect(a.tags).toEqual(["world"]);
39
+ expect(a.contextualKeys).toEqual(["npc.editor"]);
40
+ expect(a.draft).toBe(false);
41
+ expect(typeof a.description).toBe("string"); // existing: BlockNote JSON stringified
42
+ });
43
+ });
@@ -5,7 +5,13 @@ import { HowToInput, HowToInterface } from "./HowToInterface";
5
5
  export class HowTo extends Content implements HowToInterface {
6
6
  private _description?: any;
7
7
  private _pages?: string;
8
- private _helpContentSlug?: string;
8
+ private _howToType?: string;
9
+ private _slug?: string;
10
+ private _order?: number;
11
+ private _summary?: string;
12
+ private _tags?: string[];
13
+ private _contextualKeys?: string[];
14
+ private _draft?: boolean;
9
15
 
10
16
  /**
11
17
  * Parse pages from backend JSON string (handles legacy single string + JSON array)
@@ -37,8 +43,32 @@ export class HowTo extends Content implements HowToInterface {
37
43
  return this._pages;
38
44
  }
39
45
 
40
- get helpContentSlug(): string | undefined {
41
- return this._helpContentSlug;
46
+ get howToType(): string | undefined {
47
+ return this._howToType;
48
+ }
49
+
50
+ get slug(): string | undefined {
51
+ return this._slug;
52
+ }
53
+
54
+ get order(): number | undefined {
55
+ return this._order;
56
+ }
57
+
58
+ get summary(): string | undefined {
59
+ return this._summary;
60
+ }
61
+
62
+ get tags(): string[] {
63
+ return this._tags ?? [];
64
+ }
65
+
66
+ get contextualKeys(): string[] {
67
+ return this._contextualKeys ?? [];
68
+ }
69
+
70
+ get draft(): boolean {
71
+ return this._draft ?? false;
42
72
  }
43
73
 
44
74
  rehydrate(data: JsonApiHydratedDataInterface): this {
@@ -60,7 +90,13 @@ export class HowTo extends Content implements HowToInterface {
60
90
  this._description = rawDescription;
61
91
  }
62
92
  this._pages = data.jsonApi.attributes.pages;
63
- this._helpContentSlug = data.jsonApi.attributes.helpContentSlug;
93
+ this._howToType = data.jsonApi.attributes.howToType;
94
+ this._slug = data.jsonApi.attributes.slug;
95
+ this._order = data.jsonApi.attributes.order;
96
+ this._summary = data.jsonApi.attributes.summary;
97
+ this._tags = data.jsonApi.attributes.tags ?? [];
98
+ this._contextualKeys = data.jsonApi.attributes.contextualKeys ?? [];
99
+ this._draft = data.jsonApi.attributes.draft ?? false;
64
100
 
65
101
  return this;
66
102
  }
@@ -81,6 +117,13 @@ export class HowTo extends Content implements HowToInterface {
81
117
 
82
118
  if (data.description !== undefined) response.data.attributes.description = JSON.stringify(data.description);
83
119
  if (data.pages !== undefined) response.data.attributes.pages = data.pages;
120
+ if (data.howToType !== undefined) response.data.attributes.howToType = data.howToType;
121
+ if (data.slug !== undefined) response.data.attributes.slug = data.slug;
122
+ if (data.order !== undefined) response.data.attributes.order = data.order;
123
+ if (data.summary !== undefined) response.data.attributes.summary = data.summary;
124
+ if (data.tags !== undefined) response.data.attributes.tags = data.tags;
125
+ if (data.contextualKeys !== undefined) response.data.attributes.contextualKeys = data.contextualKeys;
126
+ if (data.draft !== undefined) response.data.attributes.draft = data.draft;
84
127
 
85
128
  return response;
86
129
  }