nebula-cms 0.1.3 → 0.1.5

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 (381) hide show
  1. package/README.md +3 -1
  2. package/dist/astro/index.d.ts +43 -0
  3. package/dist/astro/index.d.ts.map +1 -0
  4. package/dist/astro/index.js +223 -0
  5. package/{src → dist}/client/Admin.svelte +20 -11
  6. package/dist/client/Admin.svelte.d.ts +11 -0
  7. package/dist/client/Admin.svelte.d.ts.map +1 -0
  8. package/dist/client/components/BackendPicker.svelte.d.ts +4 -0
  9. package/dist/client/components/BackendPicker.svelte.d.ts.map +1 -0
  10. package/dist/client/components/DraftChip.svelte.d.ts +10 -0
  11. package/dist/client/components/DraftChip.svelte.d.ts.map +1 -0
  12. package/dist/client/components/MetadataForm.svelte.d.ts +12 -0
  13. package/dist/client/components/MetadataForm.svelte.d.ts.map +1 -0
  14. package/dist/client/components/ThemeToggle.svelte.d.ts +19 -0
  15. package/dist/client/components/ThemeToggle.svelte.d.ts.map +1 -0
  16. package/dist/client/components/dialogs/DeleteDraftDialog.svelte.d.ts +11 -0
  17. package/dist/client/components/dialogs/DeleteDraftDialog.svelte.d.ts.map +1 -0
  18. package/{src → dist}/client/components/dialogs/FilenameDialog.svelte +1 -2
  19. package/dist/client/components/dialogs/FilenameDialog.svelte.d.ts +13 -0
  20. package/dist/client/components/dialogs/FilenameDialog.svelte.d.ts.map +1 -0
  21. package/dist/client/components/editor/EditorPane.svelte.d.ts +4 -0
  22. package/dist/client/components/editor/EditorPane.svelte.d.ts.map +1 -0
  23. package/dist/client/components/editor/EditorTabs.svelte.d.ts +8 -0
  24. package/dist/client/components/editor/EditorTabs.svelte.d.ts.map +1 -0
  25. package/dist/client/components/editor/EditorToolbar.svelte.d.ts +4 -0
  26. package/dist/client/components/editor/EditorToolbar.svelte.d.ts.map +1 -0
  27. package/dist/client/components/editor/FormatSelector.svelte.d.ts +4 -0
  28. package/dist/client/components/editor/FormatSelector.svelte.d.ts.map +1 -0
  29. package/dist/client/components/editor/Toolbar.svelte.d.ts +19 -0
  30. package/dist/client/components/editor/Toolbar.svelte.d.ts.map +1 -0
  31. package/dist/client/components/fields/ArrayField.svelte.d.ts +15 -0
  32. package/dist/client/components/fields/ArrayField.svelte.d.ts.map +1 -0
  33. package/dist/client/components/fields/ArrayItem.svelte.d.ts +28 -0
  34. package/dist/client/components/fields/ArrayItem.svelte.d.ts.map +1 -0
  35. package/dist/client/components/fields/BooleanField.svelte.d.ts +16 -0
  36. package/dist/client/components/fields/BooleanField.svelte.d.ts.map +1 -0
  37. package/dist/client/components/fields/DateField.svelte.d.ts +16 -0
  38. package/dist/client/components/fields/DateField.svelte.d.ts.map +1 -0
  39. package/dist/client/components/fields/EnumField.svelte.d.ts +17 -0
  40. package/dist/client/components/fields/EnumField.svelte.d.ts.map +1 -0
  41. package/dist/client/components/fields/FieldWrapper.svelte.d.ts +18 -0
  42. package/dist/client/components/fields/FieldWrapper.svelte.d.ts.map +1 -0
  43. package/dist/client/components/fields/NumberField.svelte.d.ts +16 -0
  44. package/dist/client/components/fields/NumberField.svelte.d.ts.map +1 -0
  45. package/dist/client/components/fields/ObjectField.svelte.d.ts +16 -0
  46. package/dist/client/components/fields/ObjectField.svelte.d.ts.map +1 -0
  47. package/dist/client/components/fields/SchemaField.svelte.d.ts +16 -0
  48. package/dist/client/components/fields/SchemaField.svelte.d.ts.map +1 -0
  49. package/dist/client/components/fields/StringField.svelte.d.ts +16 -0
  50. package/dist/client/components/fields/StringField.svelte.d.ts.map +1 -0
  51. package/{src → dist}/client/components/sidebar/AdminSidebar.svelte +2 -4
  52. package/dist/client/components/sidebar/AdminSidebar.svelte.d.ts +19 -0
  53. package/dist/client/components/sidebar/AdminSidebar.svelte.d.ts.map +1 -0
  54. package/dist/client/components/sidebar/AdminSidebarSort.svelte.d.ts +12 -0
  55. package/dist/client/components/sidebar/AdminSidebarSort.svelte.d.ts.map +1 -0
  56. package/dist/client/css/icons.css +29 -0
  57. package/dist/client/index.d.ts +2 -0
  58. package/dist/client/index.d.ts.map +1 -0
  59. package/dist/client/js/drafts/merge.svelte.d.ts +24 -0
  60. package/dist/client/js/drafts/merge.svelte.d.ts.map +1 -0
  61. package/dist/client/js/drafts/merge.svelte.js +106 -0
  62. package/dist/client/js/drafts/ops.svelte.d.ts +31 -0
  63. package/dist/client/js/drafts/ops.svelte.d.ts.map +1 -0
  64. package/dist/client/js/drafts/ops.svelte.js +182 -0
  65. package/dist/client/js/drafts/storage.d.ts +45 -0
  66. package/dist/client/js/drafts/storage.d.ts.map +1 -0
  67. package/dist/client/js/drafts/storage.js +76 -0
  68. package/dist/client/js/drafts/workers/diff.d.ts +2 -0
  69. package/dist/client/js/drafts/workers/diff.d.ts.map +1 -0
  70. package/dist/client/js/drafts/workers/diff.js +20 -0
  71. package/dist/client/js/editor/editor.svelte.d.ts +124 -0
  72. package/dist/client/js/editor/editor.svelte.d.ts.map +1 -0
  73. package/dist/client/js/editor/editor.svelte.js +294 -0
  74. package/dist/client/js/editor/languages.d.ts +11 -0
  75. package/dist/client/js/editor/languages.d.ts.map +1 -0
  76. package/dist/client/js/editor/languages.js +93 -0
  77. package/dist/client/js/editor/link-wrap.d.ts +6 -0
  78. package/dist/client/js/editor/link-wrap.d.ts.map +1 -0
  79. package/{src/client/js/editor/link-wrap.ts → dist/client/js/editor/link-wrap.js} +17 -24
  80. package/dist/client/js/editor/markdown-shortcuts.d.ts +4 -0
  81. package/dist/client/js/editor/markdown-shortcuts.d.ts.map +1 -0
  82. package/dist/client/js/editor/markdown-shortcuts.js +219 -0
  83. package/dist/client/js/handlers/admin.d.ts +64 -0
  84. package/dist/client/js/handlers/admin.d.ts.map +1 -0
  85. package/dist/client/js/handlers/admin.js +186 -0
  86. package/dist/client/js/state/dialogs.svelte.d.ts +16 -0
  87. package/dist/client/js/state/dialogs.svelte.d.ts.map +1 -0
  88. package/dist/client/js/state/dialogs.svelte.js +28 -0
  89. package/dist/client/js/state/router.svelte.d.ts +44 -0
  90. package/dist/client/js/state/router.svelte.d.ts.map +1 -0
  91. package/dist/client/js/state/router.svelte.js +141 -0
  92. package/dist/client/js/state/schema.svelte.d.ts +51 -0
  93. package/dist/client/js/state/schema.svelte.d.ts.map +1 -0
  94. package/{src/client/js/state/schema.svelte.ts → dist/client/js/state/schema.svelte.js} +55 -70
  95. package/dist/client/js/state/state.svelte.d.ts +68 -0
  96. package/dist/client/js/state/state.svelte.d.ts.map +1 -0
  97. package/dist/client/js/state/state.svelte.js +300 -0
  98. package/dist/client/js/state/theme.svelte.d.ts +24 -0
  99. package/dist/client/js/state/theme.svelte.d.ts.map +1 -0
  100. package/{src/client/js/state/theme.svelte.ts → dist/client/js/state/theme.svelte.js} +54 -91
  101. package/dist/client/js/storage/adapter.d.ts +130 -0
  102. package/dist/client/js/storage/adapter.d.ts.map +1 -0
  103. package/dist/client/js/storage/adapter.js +5 -0
  104. package/dist/client/js/storage/client.d.ts +72 -0
  105. package/dist/client/js/storage/client.d.ts.map +1 -0
  106. package/dist/client/js/storage/client.js +121 -0
  107. package/dist/client/js/storage/db.d.ts +8 -0
  108. package/dist/client/js/storage/db.d.ts.map +1 -0
  109. package/dist/client/js/storage/db.js +35 -0
  110. package/dist/client/js/storage/fsa.d.ts +51 -0
  111. package/dist/client/js/storage/fsa.d.ts.map +1 -0
  112. package/dist/client/js/storage/fsa.js +91 -0
  113. package/dist/client/js/storage/github.d.ts +62 -0
  114. package/dist/client/js/storage/github.d.ts.map +1 -0
  115. package/dist/client/js/storage/github.js +216 -0
  116. package/dist/client/js/storage/storage.d.ts +32 -0
  117. package/dist/client/js/storage/storage.d.ts.map +1 -0
  118. package/dist/client/js/storage/storage.js +68 -0
  119. package/dist/client/js/storage/workers/frontmatter.d.ts +2 -0
  120. package/dist/client/js/storage/workers/frontmatter.d.ts.map +1 -0
  121. package/dist/client/js/storage/workers/frontmatter.js +253 -0
  122. package/dist/client/js/storage/workers/storage.d.ts +2 -0
  123. package/dist/client/js/storage/workers/storage.d.ts.map +1 -0
  124. package/dist/client/js/storage/workers/storage.js +167 -0
  125. package/dist/client/js/storage/workers/toml-parser.d.ts +2 -0
  126. package/dist/client/js/storage/workers/toml-parser.d.ts.map +1 -0
  127. package/dist/client/js/storage/workers/toml-parser.js +75 -0
  128. package/dist/client/js/storage/workers/yaml-parser.d.ts +2 -0
  129. package/dist/client/js/storage/workers/yaml-parser.d.ts.map +1 -0
  130. package/dist/client/js/storage/workers/yaml-parser.js +100 -0
  131. package/dist/client/js/utils/file-types.d.ts +58 -0
  132. package/dist/client/js/utils/file-types.d.ts.map +1 -0
  133. package/{src/client/js/utils/file-types.ts → dist/client/js/utils/file-types.js} +75 -107
  134. package/dist/client/js/utils/format.d.ts +8 -0
  135. package/dist/client/js/utils/format.d.ts.map +1 -0
  136. package/{src/client/js/utils/format.ts → dist/client/js/utils/format.js} +5 -6
  137. package/dist/client/js/utils/frontmatter.d.ts +12 -0
  138. package/dist/client/js/utils/frontmatter.d.ts.map +1 -0
  139. package/dist/client/js/utils/frontmatter.js +29 -0
  140. package/dist/client/js/utils/schema-utils.d.ts +110 -0
  141. package/dist/client/js/utils/schema-utils.d.ts.map +1 -0
  142. package/dist/client/js/utils/schema-utils.js +242 -0
  143. package/dist/client/js/utils/slug.d.ts +8 -0
  144. package/dist/client/js/utils/slug.d.ts.map +1 -0
  145. package/{src/client/js/utils/slug.ts → dist/client/js/utils/slug.js} +6 -7
  146. package/dist/client/js/utils/sort.d.ts +41 -0
  147. package/dist/client/js/utils/sort.d.ts.map +1 -0
  148. package/dist/client/js/utils/sort.js +65 -0
  149. package/dist/client/js/utils/stable-stringify.d.ts +8 -0
  150. package/dist/client/js/utils/stable-stringify.d.ts.map +1 -0
  151. package/dist/client/js/utils/stable-stringify.js +23 -0
  152. package/dist/client/js/utils/url-utils.d.ts +11 -0
  153. package/dist/client/js/utils/url-utils.d.ts.map +1 -0
  154. package/{src/client/js/utils/url-utils.ts → dist/client/js/utils/url-utils.js} +22 -23
  155. package/dist/client/types/browser-apis.d.ts +39 -0
  156. package/dist/types.d.ts +22 -0
  157. package/dist/types.d.ts.map +1 -0
  158. package/dist/types.js +1 -0
  159. package/package.json +13 -3
  160. package/.github/workflows/ci.yml +0 -27
  161. package/.github/workflows/publish.yml +0 -34
  162. package/.mcp.json +0 -12
  163. package/.prettierignore +0 -5
  164. package/.prettierrc.cjs +0 -22
  165. package/AGENTS.md +0 -183
  166. package/playground/astro.config.mjs +0 -7
  167. package/playground/node_modules/.bin/astro +0 -21
  168. package/playground/node_modules/.vite/deps/@astrojs_svelte_client__js.js +0 -85
  169. package/playground/node_modules/.vite/deps/@astrojs_svelte_client__js.js.map +0 -7
  170. package/playground/node_modules/.vite/deps/_metadata.json +0 -184
  171. package/playground/node_modules/.vite/deps/astro___aria-query.js +0 -6776
  172. package/playground/node_modules/.vite/deps/astro___aria-query.js.map +0 -7
  173. package/playground/node_modules/.vite/deps/astro___axobject-query.js +0 -3754
  174. package/playground/node_modules/.vite/deps/astro___axobject-query.js.map +0 -7
  175. package/playground/node_modules/.vite/deps/astro___html-escaper.js +0 -34
  176. package/playground/node_modules/.vite/deps/astro___html-escaper.js.map +0 -7
  177. package/playground/node_modules/.vite/deps/chunk-AJXJMYAF.js +0 -0
  178. package/playground/node_modules/.vite/deps/chunk-AJXJMYAF.js.map +0 -7
  179. package/playground/node_modules/.vite/deps/chunk-BUSYA2B4.js +0 -8
  180. package/playground/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +0 -7
  181. package/playground/node_modules/.vite/deps/chunk-CNYJBM5F.js +0 -21
  182. package/playground/node_modules/.vite/deps/chunk-CNYJBM5F.js.map +0 -7
  183. package/playground/node_modules/.vite/deps/chunk-DBPNBGEI.js +0 -223
  184. package/playground/node_modules/.vite/deps/chunk-DBPNBGEI.js.map +0 -7
  185. package/playground/node_modules/.vite/deps/chunk-FPEUJ7DG.js +0 -27
  186. package/playground/node_modules/.vite/deps/chunk-FPEUJ7DG.js.map +0 -7
  187. package/playground/node_modules/.vite/deps/chunk-MHDZ3SK7.js +0 -1005
  188. package/playground/node_modules/.vite/deps/chunk-MHDZ3SK7.js.map +0 -7
  189. package/playground/node_modules/.vite/deps/chunk-RBDTDTPY.js +0 -204
  190. package/playground/node_modules/.vite/deps/chunk-RBDTDTPY.js.map +0 -7
  191. package/playground/node_modules/.vite/deps/chunk-RJGEXL5C.js +0 -688
  192. package/playground/node_modules/.vite/deps/chunk-RJGEXL5C.js.map +0 -7
  193. package/playground/node_modules/.vite/deps/chunk-YL4MIWGJ.js +0 -5099
  194. package/playground/node_modules/.vite/deps/chunk-YL4MIWGJ.js.map +0 -7
  195. package/playground/node_modules/.vite/deps/chunk-ZOV3DWEJ.js +0 -4376
  196. package/playground/node_modules/.vite/deps/chunk-ZOV3DWEJ.js.map +0 -7
  197. package/playground/node_modules/.vite/deps/chunk-ZP4UNCSN.js +0 -23
  198. package/playground/node_modules/.vite/deps/chunk-ZP4UNCSN.js.map +0 -7
  199. package/playground/node_modules/.vite/deps/chunk-ZREFNRZZ.js +0 -148
  200. package/playground/node_modules/.vite/deps/chunk-ZREFNRZZ.js.map +0 -7
  201. package/playground/node_modules/.vite/deps/package.json +0 -3
  202. package/playground/node_modules/.vite/deps/smol-toml.js +0 -843
  203. package/playground/node_modules/.vite/deps/smol-toml.js.map +0 -7
  204. package/playground/node_modules/.vite/deps/svelte.js +0 -55
  205. package/playground/node_modules/.vite/deps/svelte.js.map +0 -7
  206. package/playground/node_modules/.vite/deps/svelte___clsx.js +0 -9
  207. package/playground/node_modules/.vite/deps/svelte___clsx.js.map +0 -7
  208. package/playground/node_modules/.vite/deps/svelte_animate.js +0 -57
  209. package/playground/node_modules/.vite/deps/svelte_animate.js.map +0 -7
  210. package/playground/node_modules/.vite/deps/svelte_attachments.js +0 -15
  211. package/playground/node_modules/.vite/deps/svelte_attachments.js.map +0 -7
  212. package/playground/node_modules/.vite/deps/svelte_easing.js +0 -67
  213. package/playground/node_modules/.vite/deps/svelte_easing.js.map +0 -7
  214. package/playground/node_modules/.vite/deps/svelte_events.js +0 -11
  215. package/playground/node_modules/.vite/deps/svelte_events.js.map +0 -7
  216. package/playground/node_modules/.vite/deps/svelte_internal.js +0 -5
  217. package/playground/node_modules/.vite/deps/svelte_internal.js.map +0 -7
  218. package/playground/node_modules/.vite/deps/svelte_internal_client.js +0 -402
  219. package/playground/node_modules/.vite/deps/svelte_internal_client.js.map +0 -7
  220. package/playground/node_modules/.vite/deps/svelte_internal_disclose-version.js +0 -10
  221. package/playground/node_modules/.vite/deps/svelte_internal_disclose-version.js.map +0 -7
  222. package/playground/node_modules/.vite/deps/svelte_internal_flags_async.js +0 -8
  223. package/playground/node_modules/.vite/deps/svelte_internal_flags_async.js.map +0 -7
  224. package/playground/node_modules/.vite/deps/svelte_internal_flags_legacy.js +0 -8
  225. package/playground/node_modules/.vite/deps/svelte_internal_flags_legacy.js.map +0 -7
  226. package/playground/node_modules/.vite/deps/svelte_internal_flags_tracing.js +0 -8
  227. package/playground/node_modules/.vite/deps/svelte_internal_flags_tracing.js.map +0 -7
  228. package/playground/node_modules/.vite/deps/svelte_legacy.js +0 -35
  229. package/playground/node_modules/.vite/deps/svelte_legacy.js.map +0 -7
  230. package/playground/node_modules/.vite/deps/svelte_motion.js +0 -545
  231. package/playground/node_modules/.vite/deps/svelte_motion.js.map +0 -7
  232. package/playground/node_modules/.vite/deps/svelte_reactivity.js +0 -29
  233. package/playground/node_modules/.vite/deps/svelte_reactivity.js.map +0 -7
  234. package/playground/node_modules/.vite/deps/svelte_reactivity_window.js +0 -127
  235. package/playground/node_modules/.vite/deps/svelte_reactivity_window.js.map +0 -7
  236. package/playground/node_modules/.vite/deps/svelte_store.js +0 -103
  237. package/playground/node_modules/.vite/deps/svelte_store.js.map +0 -7
  238. package/playground/node_modules/.vite/deps/svelte_transition.js +0 -208
  239. package/playground/node_modules/.vite/deps/svelte_transition.js.map +0 -7
  240. package/playground/package.json +0 -16
  241. package/playground/pnpm-lock.yaml +0 -3167
  242. package/playground/src/content/authors/jane-doe.json +0 -8
  243. package/playground/src/content/config/build.toml +0 -2
  244. package/playground/src/content/courses/web-fundamentals.json +0 -29
  245. package/playground/src/content/docs/advanced.mdx +0 -6
  246. package/playground/src/content/docs/intro.md +0 -6
  247. package/playground/src/content/guides/getting-started.mdx +0 -6
  248. package/playground/src/content/posts/hello-world.md +0 -7
  249. package/playground/src/content/products/t-shirt.json +0 -16
  250. package/playground/src/content/recipes/pancakes.mdoc +0 -8
  251. package/playground/src/content/settings/site.yml +0 -2
  252. package/playground/src/content.config.ts +0 -198
  253. package/playground/src/env.d.ts +0 -1
  254. package/playground/src/pages/index.astro +0 -11
  255. package/playground/src/pages/nebula.astro +0 -14
  256. package/pnpm-workspace.yaml +0 -2
  257. package/scripts/subset-icons.mjs +0 -178
  258. package/src/astro/index.ts +0 -295
  259. package/src/client/js/drafts/merge.svelte.ts +0 -121
  260. package/src/client/js/drafts/ops.svelte.ts +0 -227
  261. package/src/client/js/drafts/storage.ts +0 -108
  262. package/src/client/js/drafts/workers/diff.ts +0 -40
  263. package/src/client/js/editor/editor.svelte.ts +0 -343
  264. package/src/client/js/editor/languages.ts +0 -98
  265. package/src/client/js/editor/markdown-shortcuts.ts +0 -261
  266. package/src/client/js/handlers/admin.ts +0 -246
  267. package/src/client/js/state/dialogs.svelte.ts +0 -35
  268. package/src/client/js/state/router.svelte.ts +0 -156
  269. package/src/client/js/state/state.svelte.ts +0 -334
  270. package/src/client/js/storage/adapter.ts +0 -102
  271. package/src/client/js/storage/client.ts +0 -150
  272. package/src/client/js/storage/db.ts +0 -36
  273. package/src/client/js/storage/fsa.ts +0 -110
  274. package/src/client/js/storage/github.ts +0 -297
  275. package/src/client/js/storage/storage.ts +0 -83
  276. package/src/client/js/storage/workers/frontmatter.ts +0 -320
  277. package/src/client/js/storage/workers/storage.ts +0 -177
  278. package/src/client/js/storage/workers/toml-parser.ts +0 -106
  279. package/src/client/js/storage/workers/yaml-parser.ts +0 -132
  280. package/src/client/js/utils/frontmatter.ts +0 -38
  281. package/src/client/js/utils/schema-utils.ts +0 -295
  282. package/src/client/js/utils/sort.ts +0 -84
  283. package/src/client/js/utils/stable-stringify.ts +0 -27
  284. package/src/types.ts +0 -25
  285. package/svelte.config.js +0 -4
  286. package/tests/astro/build.test.ts +0 -63
  287. package/tests/astro/index.test.ts +0 -689
  288. package/tests/client/components/Admin.test.ts +0 -446
  289. package/tests/client/components/BackendPicker.test.ts +0 -239
  290. package/tests/client/components/DraftChip.test.ts +0 -53
  291. package/tests/client/components/MetadataForm.test.ts +0 -164
  292. package/tests/client/components/dialogs/DeleteDraftDialog.test.ts +0 -91
  293. package/tests/client/components/dialogs/FilenameDialog.test.ts +0 -209
  294. package/tests/client/components/dialogs/dialog-stubs.ts +0 -19
  295. package/tests/client/components/editor/EditorPane.test.ts +0 -100
  296. package/tests/client/components/editor/EditorTabs.test.ts +0 -253
  297. package/tests/client/components/editor/EditorToolbar.test.ts +0 -252
  298. package/tests/client/components/editor/fixtures.ts +0 -31
  299. package/tests/client/components/fields/ArrayField.test.ts +0 -197
  300. package/tests/client/components/fields/BooleanField.test.ts +0 -206
  301. package/tests/client/components/fields/DateField.test.ts +0 -210
  302. package/tests/client/components/fields/EnumField.test.ts +0 -246
  303. package/tests/client/components/fields/NumberField.test.ts +0 -240
  304. package/tests/client/components/fields/ObjectField.test.ts +0 -157
  305. package/tests/client/components/fields/SchemaField.test.ts +0 -190
  306. package/tests/client/components/fields/StringField.test.ts +0 -223
  307. package/tests/client/components/sidebar/AdminSidebar.test.ts +0 -285
  308. package/tests/client/components/sidebar/AdminSidebarSort.test.ts +0 -135
  309. package/tests/client/components/sidebar/sort-mock.ts +0 -23
  310. package/tests/client/js/drafts/fixtures.ts +0 -22
  311. package/tests/client/js/drafts/merge.test.ts +0 -282
  312. package/tests/client/js/drafts/ops.test.ts +0 -658
  313. package/tests/client/js/drafts/storage.test.ts +0 -200
  314. package/tests/client/js/drafts/workers/diff.test.ts +0 -165
  315. package/tests/client/js/editor/editor.test.ts +0 -616
  316. package/tests/client/js/editor/link-wrap.test.ts +0 -225
  317. package/tests/client/js/editor/markdown-shortcuts.test.ts +0 -370
  318. package/tests/client/js/handlers/admin.test.ts +0 -467
  319. package/tests/client/js/state/router.test.ts +0 -619
  320. package/tests/client/js/state/schema.test.ts +0 -266
  321. package/tests/client/js/state/state.test.ts +0 -328
  322. package/tests/client/js/storage/adapter.test.ts +0 -115
  323. package/tests/client/js/storage/client.test.ts +0 -250
  324. package/tests/client/js/storage/db.test.ts +0 -59
  325. package/tests/client/js/storage/fsa.test.ts +0 -284
  326. package/tests/client/js/storage/github.test.ts +0 -349
  327. package/tests/client/js/storage/mock-port.ts +0 -95
  328. package/tests/client/js/storage/storage.test.ts +0 -77
  329. package/tests/client/js/storage/workers/frontmatter.test.ts +0 -479
  330. package/tests/client/js/storage/workers/storage.test.ts +0 -299
  331. package/tests/client/js/storage/workers/toml-parser.test.ts +0 -169
  332. package/tests/client/js/storage/workers/yaml-parser.test.ts +0 -168
  333. package/tests/client/js/utils/file-types.test.ts +0 -268
  334. package/tests/client/js/utils/frontmatter.test.ts +0 -87
  335. package/tests/client/js/utils/schema-utils.test.ts +0 -318
  336. package/tests/client/js/utils/slug.test.ts +0 -58
  337. package/tests/client/js/utils/sort.test.ts +0 -276
  338. package/tests/client/js/utils/stable-stringify.test.ts +0 -68
  339. package/tests/client/js/utils/url-utils.test.ts +0 -70
  340. package/tests/e2e/backend-connection.test.ts +0 -301
  341. package/tests/e2e/draft-lifecycle.test.ts +0 -388
  342. package/tests/e2e/editing.test.ts +0 -355
  343. package/tests/e2e/github-adapter.test.ts +0 -330
  344. package/tests/e2e/helpers/mock-adapter.ts +0 -166
  345. package/tests/e2e/helpers/test-app.ts +0 -155
  346. package/tests/e2e/navigation.test.ts +0 -358
  347. package/tests/e2e/publishing.test.ts +0 -345
  348. package/tests/e2e/unsaved-changes.test.ts +0 -317
  349. package/tests/setup.ts +0 -2
  350. package/tests/stubs/codemirror.ts +0 -197
  351. package/tsconfig.json +0 -19
  352. package/vitest.config.ts +0 -178
  353. /package/{src → dist}/client/components/BackendPicker.svelte +0 -0
  354. /package/{src → dist}/client/components/DraftChip.svelte +0 -0
  355. /package/{src → dist}/client/components/MetadataForm.svelte +0 -0
  356. /package/{src → dist}/client/components/ThemeToggle.svelte +0 -0
  357. /package/{src → dist}/client/components/dialogs/DeleteDraftDialog.svelte +0 -0
  358. /package/{src → dist}/client/components/editor/EditorPane.svelte +0 -0
  359. /package/{src → dist}/client/components/editor/EditorTabs.svelte +0 -0
  360. /package/{src → dist}/client/components/editor/EditorToolbar.svelte +0 -0
  361. /package/{src → dist}/client/components/editor/FormatSelector.svelte +0 -0
  362. /package/{src → dist}/client/components/editor/Toolbar.svelte +0 -0
  363. /package/{src → dist}/client/components/fields/ArrayField.svelte +0 -0
  364. /package/{src → dist}/client/components/fields/ArrayItem.svelte +0 -0
  365. /package/{src → dist}/client/components/fields/BooleanField.svelte +0 -0
  366. /package/{src → dist}/client/components/fields/DateField.svelte +0 -0
  367. /package/{src → dist}/client/components/fields/EnumField.svelte +0 -0
  368. /package/{src → dist}/client/components/fields/FieldWrapper.svelte +0 -0
  369. /package/{src → dist}/client/components/fields/NumberField.svelte +0 -0
  370. /package/{src → dist}/client/components/fields/ObjectField.svelte +0 -0
  371. /package/{src → dist}/client/components/fields/SchemaField.svelte +0 -0
  372. /package/{src → dist}/client/components/fields/StringField.svelte +0 -0
  373. /package/{src → dist}/client/components/sidebar/AdminSidebarSort.svelte +0 -0
  374. /package/{src → dist}/client/css/a11y.css +0 -0
  375. /package/{src → dist}/client/css/btn.css +0 -0
  376. /package/{src → dist}/client/css/dialog.css +0 -0
  377. /package/{src → dist}/client/css/field-input.css +0 -0
  378. /package/{src → dist}/client/css/reset.css +0 -0
  379. /package/{src → dist}/client/css/theme.css +0 -0
  380. /package/{src/client/index.ts → dist/client/index.js} +0 -0
  381. /package/{src → dist}/virtual.d.ts +0 -0
@@ -1,689 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import {
3
- mkdtempSync,
4
- mkdirSync,
5
- writeFileSync,
6
- rmSync,
7
- existsSync,
8
- readFileSync,
9
- } from 'node:fs';
10
- import { resolve, join } from 'node:path';
11
- import { tmpdir } from 'node:os';
12
- import { pathToFileURL } from 'node:url';
13
- import NebulaCMS, { nebulaVitePlugin } from '../../src/astro/index.js';
14
- import type { AstroIntegrationLogger } from 'astro';
15
-
16
- /*
17
- //////////////////////////////
18
- // Test Helpers
19
- //////////////////////////////
20
- */
21
-
22
- /**
23
- * Creates a minimal mock satisfying the AstroIntegrationLogger interface
24
- * @return {AstroIntegrationLogger} Mock logger with a spied warn method
25
- */
26
- function createMockLogger() {
27
- return { warn: vi.fn() } as unknown as AstroIntegrationLogger;
28
- }
29
-
30
- /*
31
- //////////////////////////////
32
- // NebulaCMS integration object
33
- //////////////////////////////
34
- */
35
-
36
- describe('NebulaCMS integration object', () => {
37
- it('returns an integration with name "nebula-cms"', () => {
38
- const integration = NebulaCMS();
39
- expect(integration.name).toBe('nebula-cms');
40
- });
41
-
42
- it('registers a Vite plugin via astro:config:setup', () => {
43
- const integration = NebulaCMS();
44
- const updateConfig = vi.fn();
45
- const logger = createMockLogger();
46
-
47
- const hook = integration.hooks['astro:config:setup'] as Function;
48
- hook({ updateConfig, logger });
49
-
50
- expect(updateConfig).toHaveBeenCalledWith({
51
- vite: {
52
- plugins: [expect.objectContaining({ name: 'vite-plugin-nebula-cms' })],
53
- worker: { format: 'es' },
54
- optimizeDeps: { include: ['smol-toml'] },
55
- },
56
- });
57
- });
58
-
59
- it('accepts a valid absolute basePath', () => {
60
- const integration = NebulaCMS({ basePath: '/dashboard' });
61
- expect(integration.name).toBe('nebula-cms');
62
- });
63
-
64
- it('normalizes basePath without leading slash', () => {
65
- // Should not throw — 'admin' is normalized to '/admin'
66
- const integration = NebulaCMS({ basePath: 'admin' });
67
- expect(integration.name).toBe('nebula-cms');
68
- });
69
-
70
- it('normalizes basePath with trailing slash', () => {
71
- // Should not throw — '/admin/' is normalized to '/admin'
72
- const integration = NebulaCMS({ basePath: '/admin/' });
73
- expect(integration.name).toBe('nebula-cms');
74
- });
75
-
76
- it('throws on basePath with invalid characters', () => {
77
- expect(() => NebulaCMS({ basePath: '/admin/<script>' })).toThrow(
78
- 'Invalid basePath',
79
- );
80
- });
81
-
82
- it('accepts a valid absolute collectionsPath', () => {
83
- const integration = NebulaCMS({ collectionsPath: '/schemas' });
84
- expect(integration.name).toBe('nebula-cms');
85
- });
86
-
87
- it('normalizes collectionsPath without leading slash', () => {
88
- const integration = NebulaCMS({ collectionsPath: 'schemas' });
89
- expect(integration.name).toBe('nebula-cms');
90
- });
91
-
92
- it('normalizes collectionsPath with trailing slash', () => {
93
- const integration = NebulaCMS({ collectionsPath: '/schemas/' });
94
- expect(integration.name).toBe('nebula-cms');
95
- });
96
-
97
- it('throws on collectionsPath with invalid characters', () => {
98
- expect(() => NebulaCMS({ collectionsPath: '/my schemas' })).toThrow(
99
- 'Invalid collectionsPath',
100
- );
101
- });
102
-
103
- it('throws on empty collectionsPath', () => {
104
- expect(() => NebulaCMS({ collectionsPath: '' })).toThrow(
105
- 'Invalid collectionsPath',
106
- );
107
- });
108
-
109
- it('accepts root basePath /', () => {
110
- const integration = NebulaCMS({ basePath: '/' });
111
- expect(integration.name).toBe('nebula-cms');
112
- });
113
-
114
- it('collapses consecutive slashes in basePath', () => {
115
- // '/admin//' is normalized to '/admin' via URL API
116
- const integration = NebulaCMS({ basePath: '/admin//' });
117
- expect(integration.name).toBe('nebula-cms');
118
- });
119
-
120
- it('throws on empty basePath', () => {
121
- expect(() => NebulaCMS({ basePath: '' })).toThrow('Invalid basePath ""');
122
- });
123
-
124
- it('throws on collectionsPath set to /', () => {
125
- expect(() => NebulaCMS({ collectionsPath: '/' })).toThrow(
126
- 'Collections require a path prefix',
127
- );
128
- });
129
-
130
- it('throws on protocol-relative basePath', () => {
131
- expect(() => NebulaCMS({ basePath: '//admin' })).toThrow(
132
- 'must not start with "//"',
133
- );
134
- });
135
- });
136
-
137
- /*
138
- //////////////////////////////
139
- // resolveId hook
140
- //////////////////////////////
141
- */
142
-
143
- describe('nebulaVitePlugin resolveId', () => {
144
- it('resolves virtual:nebula/collections to the internal ID', () => {
145
- const plugin = nebulaVitePlugin(createMockLogger(), '/fake', {
146
- basePath: '/admin',
147
- collectionsPath: '/collections',
148
- });
149
- expect(plugin.resolveId('virtual:nebula/collections')).toBe(
150
- '\0virtual:nebula/collections',
151
- );
152
- });
153
-
154
- it('resolves virtual:nebula/config to the internal ID', () => {
155
- const plugin = nebulaVitePlugin(createMockLogger(), '/fake', {
156
- basePath: '/admin',
157
- collectionsPath: '/collections',
158
- });
159
- expect(plugin.resolveId('virtual:nebula/config')).toBe(
160
- '\0virtual:nebula/config',
161
- );
162
- });
163
-
164
- it('returns undefined for unrelated module IDs', () => {
165
- const plugin = nebulaVitePlugin(createMockLogger(), '/fake', {
166
- basePath: '/admin',
167
- collectionsPath: '/collections',
168
- });
169
- expect(plugin.resolveId('some-other-module')).toBeUndefined();
170
- });
171
-
172
- it('does not resolve old virtual:collections ID', () => {
173
- const plugin = nebulaVitePlugin(createMockLogger(), '/fake', {
174
- basePath: '/admin',
175
- collectionsPath: '/collections',
176
- });
177
- expect(plugin.resolveId('virtual:collections')).toBeUndefined();
178
- });
179
- });
180
-
181
- /*
182
- //////////////////////////////
183
- // configureServer middleware
184
- //////////////////////////////
185
- */
186
-
187
- describe('nebulaVitePlugin configureServer', () => {
188
- let tmpDir: string;
189
- let logger: AstroIntegrationLogger;
190
-
191
- beforeEach(() => {
192
- tmpDir = mkdtempSync(join(tmpdir(), 'nebula-test-'));
193
- logger = createMockLogger();
194
- });
195
-
196
- afterEach(() => {
197
- rmSync(tmpDir, { recursive: true, force: true });
198
- });
199
-
200
- /**
201
- * Creates a fake Connect-style middleware stack to capture registered handlers.
202
- * @return {{ use: ReturnType<typeof vi.fn>, handlers: Function[] }}
203
- */
204
- function createMiddlewareStub() {
205
- const handlers: Function[] = [];
206
- return {
207
- use: vi.fn((fn: Function) => {
208
- handlers.push(fn);
209
- }),
210
- get handlers() {
211
- return handlers;
212
- },
213
- };
214
- }
215
-
216
- /**
217
- * Simulates a middleware request/response cycle for the schema middleware.
218
- * @param {Function} handler - The middleware handler
219
- * @param {string} url - The request URL
220
- * @return {{ status: 'served' | 'skipped', body?: string, contentType?: string }}
221
- */
222
- function callSchemaMiddleware(handler: Function, url: string) {
223
- let result: { status: string; body?: string; contentType?: string } = {
224
- status: 'skipped',
225
- };
226
- const req = { url };
227
- const headers: Record<string, string> = {};
228
- const res = {
229
- setHeader: (k: string, v: string) => {
230
- headers[k] = v;
231
- },
232
- end: (body: string) => {
233
- result = {
234
- status: 'served',
235
- body,
236
- contentType: headers['Content-Type'],
237
- };
238
- },
239
- };
240
- const next = () => {
241
- result = { status: 'skipped' };
242
- };
243
- handler(req, res, next);
244
- return result;
245
- }
246
-
247
- /**
248
- * Simulates a middleware request/response cycle for the SPA rewrite middleware.
249
- * @param {Function} handler - The middleware handler
250
- * @param {string} url - The request URL
251
- * @param {string} accept - The Accept header value
252
- * @return {{ rewritten: boolean, url: string, nextCalled: boolean }}
253
- */
254
- function callRewriteMiddleware(
255
- handler: Function,
256
- url: string,
257
- accept: string,
258
- ) {
259
- const req = { url, headers: { accept } };
260
- let nextCalled = false;
261
- const next = () => {
262
- nextCalled = true;
263
- };
264
- handler(req, {}, next);
265
- return { rewritten: req.url !== url, url: req.url, nextCalled };
266
- }
267
-
268
- it('serves schema files from .astro/collections', () => {
269
- const dir = resolve(tmpDir, '.astro/collections');
270
- mkdirSync(dir, { recursive: true });
271
- writeFileSync(resolve(dir, 'posts.schema.json'), '{"type":"object"}');
272
-
273
- const plugin = nebulaVitePlugin(logger, tmpDir, {
274
- basePath: '/admin',
275
- collectionsPath: '/collections',
276
- });
277
- const mw = createMiddlewareStub();
278
- plugin.configureServer({ middlewares: mw });
279
-
280
- // First handler is the schema middleware
281
- const result = callSchemaMiddleware(
282
- mw.handlers[0],
283
- '/collections/posts.schema.json',
284
- );
285
- expect(result.status).toBe('served');
286
- expect(result.body).toBe('{"type":"object"}');
287
- expect(result.contentType).toBe('application/json');
288
- });
289
-
290
- it('calls next() for non-schema requests', () => {
291
- const plugin = nebulaVitePlugin(logger, tmpDir, {
292
- basePath: '/admin',
293
- collectionsPath: '/collections',
294
- });
295
- const mw = createMiddlewareStub();
296
- plugin.configureServer({ middlewares: mw });
297
-
298
- const result = callSchemaMiddleware(mw.handlers[0], '/some/other/path');
299
- expect(result.status).toBe('skipped');
300
- });
301
-
302
- it('calls next() when schema file does not exist', () => {
303
- const plugin = nebulaVitePlugin(logger, tmpDir, {
304
- basePath: '/admin',
305
- collectionsPath: '/collections',
306
- });
307
- const mw = createMiddlewareStub();
308
- plugin.configureServer({ middlewares: mw });
309
-
310
- const result = callSchemaMiddleware(
311
- mw.handlers[0],
312
- '/collections/missing.schema.json',
313
- );
314
- expect(result.status).toBe('skipped');
315
- });
316
-
317
- it('uses custom collectionsPath prefix', () => {
318
- const dir = resolve(tmpDir, '.astro/collections');
319
- mkdirSync(dir, { recursive: true });
320
- writeFileSync(resolve(dir, 'posts.schema.json'), '{}');
321
-
322
- const plugin = nebulaVitePlugin(logger, tmpDir, {
323
- basePath: '/admin',
324
- collectionsPath: '/schemas',
325
- });
326
- const mw = createMiddlewareStub();
327
- plugin.configureServer({ middlewares: mw });
328
-
329
- const miss = callSchemaMiddleware(
330
- mw.handlers[0],
331
- '/collections/posts.schema.json',
332
- );
333
- expect(miss.status).toBe('skipped');
334
-
335
- const hit = callSchemaMiddleware(
336
- mw.handlers[0],
337
- '/schemas/posts.schema.json',
338
- );
339
- expect(hit.status).toBe('served');
340
- });
341
-
342
- it('rewrites HTML requests under basePath to basePath', () => {
343
- const plugin = nebulaVitePlugin(logger, tmpDir, {
344
- basePath: '/admin',
345
- collectionsPath: '/collections',
346
- });
347
- const mw = createMiddlewareStub();
348
- plugin.configureServer({ middlewares: mw });
349
-
350
- // Second handler is the SPA rewrite middleware
351
- const result = callRewriteMiddleware(
352
- mw.handlers[1],
353
- '/admin/posts/my-article',
354
- 'text/html',
355
- );
356
- expect(result.rewritten).toBe(true);
357
- expect(result.url).toBe('/admin');
358
- });
359
-
360
- it('does not rewrite exact basePath requests', () => {
361
- const plugin = nebulaVitePlugin(logger, tmpDir, {
362
- basePath: '/admin',
363
- collectionsPath: '/collections',
364
- });
365
- const mw = createMiddlewareStub();
366
- plugin.configureServer({ middlewares: mw });
367
-
368
- const result = callRewriteMiddleware(mw.handlers[1], '/admin', 'text/html');
369
- expect(result.rewritten).toBe(false);
370
- });
371
-
372
- it('does not rewrite non-HTML requests under basePath', () => {
373
- const plugin = nebulaVitePlugin(logger, tmpDir, {
374
- basePath: '/admin',
375
- collectionsPath: '/collections',
376
- });
377
- const mw = createMiddlewareStub();
378
- plugin.configureServer({ middlewares: mw });
379
-
380
- const result = callRewriteMiddleware(
381
- mw.handlers[1],
382
- '/admin/posts/my-article',
383
- 'application/json',
384
- );
385
- expect(result.rewritten).toBe(false);
386
- });
387
-
388
- it('respects segment boundary — /administrator does not rewrite', () => {
389
- const plugin = nebulaVitePlugin(logger, tmpDir, {
390
- basePath: '/admin',
391
- collectionsPath: '/collections',
392
- });
393
- const mw = createMiddlewareStub();
394
- plugin.configureServer({ middlewares: mw });
395
-
396
- const result = callRewriteMiddleware(
397
- mw.handlers[1],
398
- '/administrator',
399
- 'text/html',
400
- );
401
- expect(result.rewritten).toBe(false);
402
- });
403
-
404
- it('rewrites with custom basePath', () => {
405
- const plugin = nebulaVitePlugin(logger, tmpDir, {
406
- basePath: '/nebula',
407
- collectionsPath: '/collections',
408
- });
409
- const mw = createMiddlewareStub();
410
- plugin.configureServer({ middlewares: mw });
411
-
412
- const result = callRewriteMiddleware(
413
- mw.handlers[1],
414
- '/nebula/posts/draft-12345678',
415
- 'text/html',
416
- );
417
- expect(result.rewritten).toBe(true);
418
- expect(result.url).toBe('/nebula');
419
- });
420
-
421
- it('rewrites sub-routes when basePath is /', () => {
422
- const plugin = nebulaVitePlugin(logger, tmpDir, {
423
- basePath: '/',
424
- collectionsPath: '/collections',
425
- });
426
- const mw = createMiddlewareStub();
427
- plugin.configureServer({ middlewares: mw });
428
-
429
- const result = callRewriteMiddleware(
430
- mw.handlers[1],
431
- '/posts/my-article',
432
- 'text/html',
433
- );
434
- expect(result.rewritten).toBe(true);
435
- expect(result.url).toBe('/');
436
- });
437
-
438
- it('does not rewrite root path when basePath is /', () => {
439
- const plugin = nebulaVitePlugin(logger, tmpDir, {
440
- basePath: '/',
441
- collectionsPath: '/collections',
442
- });
443
- const mw = createMiddlewareStub();
444
- plugin.configureServer({ middlewares: mw });
445
-
446
- const result = callRewriteMiddleware(mw.handlers[1], '/', 'text/html');
447
- expect(result.rewritten).toBe(false);
448
- });
449
-
450
- it('rewrites HTML requests with query strings', () => {
451
- const plugin = nebulaVitePlugin(logger, tmpDir, {
452
- basePath: '/admin',
453
- collectionsPath: '/collections',
454
- });
455
- const mw = createMiddlewareStub();
456
- plugin.configureServer({ middlewares: mw });
457
-
458
- const result = callRewriteMiddleware(
459
- mw.handlers[1],
460
- '/admin/posts?draft=true',
461
- 'text/html',
462
- );
463
- expect(result.rewritten).toBe(true);
464
- // Query string preserved during rewrite
465
- expect(result.url).toBe('/admin?draft=true');
466
- });
467
-
468
- it('rejects path traversal in schema requests', () => {
469
- const dir = resolve(tmpDir, '.astro/collections');
470
- mkdirSync(dir, { recursive: true });
471
- writeFileSync(resolve(dir, 'posts.schema.json'), '{}');
472
-
473
- const plugin = nebulaVitePlugin(logger, tmpDir, {
474
- basePath: '/admin',
475
- collectionsPath: '/collections',
476
- });
477
- const mw = createMiddlewareStub();
478
- plugin.configureServer({ middlewares: mw });
479
-
480
- const result = callSchemaMiddleware(
481
- mw.handlers[0],
482
- '/collections/../../../etc/passwd.schema.json',
483
- );
484
- expect(result.status).toBe('skipped');
485
- });
486
- });
487
-
488
- /*
489
- //////////////////////////////
490
- // astro:build:done hook
491
- //////////////////////////////
492
- */
493
-
494
- describe('NebulaCMS astro:build:done', () => {
495
- let tmpDir: string;
496
- let logger: AstroIntegrationLogger;
497
-
498
- beforeEach(() => {
499
- tmpDir = mkdtempSync(join(tmpdir(), 'nebula-test-'));
500
- logger = createMockLogger();
501
- vi.spyOn(process, 'cwd').mockReturnValue(tmpDir);
502
- });
503
-
504
- afterEach(() => {
505
- vi.restoreAllMocks();
506
- rmSync(tmpDir, { recursive: true, force: true });
507
- });
508
-
509
- it('copies schema files into the build output directory', () => {
510
- const source = resolve(tmpDir, '.astro/collections');
511
- mkdirSync(source, { recursive: true });
512
- writeFileSync(resolve(source, 'posts.schema.json'), '{"type":"object"}');
513
- writeFileSync(resolve(source, 'authors.schema.json'), '{"a":1}');
514
-
515
- const outDir = resolve(tmpDir, 'dist');
516
- mkdirSync(outDir, { recursive: true });
517
-
518
- const integration = NebulaCMS();
519
- const hook = integration.hooks['astro:build:done'] as Function;
520
- hook({ dir: pathToFileURL(outDir + '/'), logger });
521
-
522
- const target = resolve(outDir, 'collections');
523
- expect(existsSync(resolve(target, 'posts.schema.json'))).toBe(true);
524
- expect(existsSync(resolve(target, 'authors.schema.json'))).toBe(true);
525
- expect(readFileSync(resolve(target, 'posts.schema.json'), 'utf-8')).toBe(
526
- '{"type":"object"}',
527
- );
528
- });
529
-
530
- it('warns when .astro/collections does not exist', () => {
531
- const outDir = resolve(tmpDir, 'dist');
532
- mkdirSync(outDir, { recursive: true });
533
-
534
- const integration = NebulaCMS();
535
- const hook = integration.hooks['astro:build:done'] as Function;
536
- hook({ dir: pathToFileURL(outDir + '/'), logger });
537
-
538
- expect(logger.warn).toHaveBeenCalledWith(
539
- expect.stringContaining('.astro/collections'),
540
- );
541
- });
542
-
543
- it('uses custom collectionsPath for the output directory', () => {
544
- const source = resolve(tmpDir, '.astro/collections');
545
- mkdirSync(source, { recursive: true });
546
- writeFileSync(resolve(source, 'posts.schema.json'), '{}');
547
-
548
- const outDir = resolve(tmpDir, 'dist');
549
- mkdirSync(outDir, { recursive: true });
550
-
551
- const integration = NebulaCMS({ collectionsPath: '/schemas' });
552
- const hook = integration.hooks['astro:build:done'] as Function;
553
- hook({ dir: pathToFileURL(outDir + '/'), logger });
554
-
555
- expect(existsSync(resolve(outDir, 'schemas/posts.schema.json'))).toBe(true);
556
- expect(existsSync(resolve(outDir, 'collections'))).toBe(false);
557
- });
558
- });
559
-
560
- /*
561
- //////////////////////////////
562
- // load hook
563
- //////////////////////////////
564
- */
565
-
566
- describe('nebulaVitePlugin load', () => {
567
- let tmpDir: string;
568
- let logger: AstroIntegrationLogger;
569
-
570
- beforeEach(() => {
571
- tmpDir = mkdtempSync(join(tmpdir(), 'nebula-test-'));
572
- logger = createMockLogger();
573
- });
574
-
575
- afterEach(() => {
576
- rmSync(tmpDir, { recursive: true, force: true });
577
- });
578
-
579
- it('returns undefined for unrelated module IDs', () => {
580
- const plugin = nebulaVitePlugin(logger, tmpDir, {
581
- basePath: '/admin',
582
- collectionsPath: '/collections',
583
- });
584
- expect(plugin.load('some-other-id')).toBeUndefined();
585
- });
586
-
587
- it('generates config module with basePath and collectionsPath', () => {
588
- const plugin = nebulaVitePlugin(logger, tmpDir, {
589
- basePath: '/dashboard',
590
- collectionsPath: '/schemas',
591
- });
592
- const result = plugin.load('\0virtual:nebula/config');
593
-
594
- expect(result).toContain('"/dashboard"');
595
- expect(result).toContain('"/schemas"');
596
- expect(result).toContain('export default');
597
- });
598
-
599
- it('generates collections module mapping names to schema URLs', () => {
600
- const dir = resolve(tmpDir, '.astro/collections');
601
- mkdirSync(dir, { recursive: true });
602
- writeFileSync(resolve(dir, 'posts.schema.json'), '{}');
603
-
604
- const plugin = nebulaVitePlugin(logger, tmpDir, {
605
- basePath: '/admin',
606
- collectionsPath: '/collections',
607
- });
608
- const result = plugin.load('\0virtual:nebula/collections');
609
-
610
- expect(result).toContain('"posts"');
611
- expect(result).toContain('"/collections/posts.schema.json"');
612
- });
613
-
614
- it('handles multiple schema files', () => {
615
- const dir = resolve(tmpDir, '.astro/collections');
616
- mkdirSync(dir, { recursive: true });
617
- writeFileSync(resolve(dir, 'posts.schema.json'), '{}');
618
- writeFileSync(resolve(dir, 'authors.schema.json'), '{}');
619
-
620
- const plugin = nebulaVitePlugin(logger, tmpDir, {
621
- basePath: '/admin',
622
- collectionsPath: '/collections',
623
- });
624
- const result = plugin.load('\0virtual:nebula/collections');
625
-
626
- expect(result).toContain('"posts"');
627
- expect(result).toContain('"authors"');
628
- });
629
-
630
- it('ignores non-.schema.json files in the directory', () => {
631
- const dir = resolve(tmpDir, '.astro/collections');
632
- mkdirSync(dir, { recursive: true });
633
- writeFileSync(resolve(dir, 'posts.schema.json'), '{}');
634
- writeFileSync(resolve(dir, 'README.md'), '');
635
-
636
- const plugin = nebulaVitePlugin(logger, tmpDir, {
637
- basePath: '/admin',
638
- collectionsPath: '/collections',
639
- });
640
- const result = plugin.load('\0virtual:nebula/collections');
641
-
642
- expect(result).toContain('"posts"');
643
- expect(result).not.toContain('README');
644
- });
645
-
646
- it('strips .schema.json suffix for collection names', () => {
647
- const dir = resolve(tmpDir, '.astro/collections');
648
- mkdirSync(dir, { recursive: true });
649
- writeFileSync(resolve(dir, 'my-collection.schema.json'), '{}');
650
-
651
- const plugin = nebulaVitePlugin(logger, tmpDir, {
652
- basePath: '/admin',
653
- collectionsPath: '/collections',
654
- });
655
- const result = plugin.load('\0virtual:nebula/collections');
656
-
657
- expect(result).toContain('"my-collection"');
658
- expect(result).not.toContain('.schema.json":');
659
- });
660
-
661
- it('returns empty default export and warns when directory is missing', () => {
662
- const plugin = nebulaVitePlugin(logger, tmpDir, {
663
- basePath: '/admin',
664
- collectionsPath: '/collections',
665
- });
666
- const result = plugin.load('\0virtual:nebula/collections');
667
-
668
- expect(result).toBe('export default {};');
669
- expect(logger.warn).toHaveBeenCalledWith(
670
- expect.stringContaining('.astro/collections'),
671
- );
672
- });
673
-
674
- it('generates URLs with custom collectionsPath prefix', () => {
675
- const dir = resolve(tmpDir, '.astro/collections');
676
- mkdirSync(dir, { recursive: true });
677
- writeFileSync(resolve(dir, 'posts.schema.json'), '{}');
678
-
679
- const plugin = nebulaVitePlugin(logger, tmpDir, {
680
- basePath: '/admin',
681
- collectionsPath: '/schemas',
682
- });
683
- const result = plugin.load('\0virtual:nebula/collections');
684
-
685
- expect(result).toContain('"posts"');
686
- expect(result).toContain('"/schemas/posts.schema.json"');
687
- expect(result).not.toContain('/collections/');
688
- });
689
- });