@ekrist1/vulse 0.1.6-alpha.3 → 0.1.7-alpha.4

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 (264) hide show
  1. package/dist/cli/migrate.d.ts.map +1 -1
  2. package/dist/cli/migrate.js +3 -4
  3. package/dist/cli/setup.d.ts.map +1 -1
  4. package/dist/cli/setup.js +11 -10
  5. package/dist/core/blueprints/compile.d.ts +1 -1
  6. package/dist/core/blueprints/compile.d.ts.map +1 -1
  7. package/dist/core/blueprints/compile.js +3 -3
  8. package/dist/core/blueprints/mutations.js +2 -2
  9. package/dist/core/forms/rate-limit.d.ts +1 -1
  10. package/dist/core/forms/rate-limit.d.ts.map +1 -1
  11. package/dist/core/forms/rate-limit.js +3 -3
  12. package/dist/core/forms/unique.d.ts +1 -1
  13. package/dist/core/forms/unique.d.ts.map +1 -1
  14. package/dist/core/forms/unique.js +4 -4
  15. package/dist/core/globals/compile.d.ts +1 -1
  16. package/dist/core/globals/compile.d.ts.map +1 -1
  17. package/dist/core/globals/compile.js +2 -2
  18. package/dist/core/globals/definition.d.ts +1 -1
  19. package/dist/core/globals/definition.d.ts.map +1 -1
  20. package/dist/core/globals/definition.js +3 -3
  21. package/dist/core/repos/globals.js +3 -3
  22. package/dist/core/sha256.d.ts +3 -0
  23. package/dist/core/sha256.d.ts.map +1 -0
  24. package/dist/core/sha256.js +9 -0
  25. package/dist/integration/index.js +1 -1
  26. package/dist/integration/install-hook.d.ts.map +1 -1
  27. package/dist/integration/install-hook.js +6 -4
  28. package/dist/integration/wrangler-config.d.ts +12 -0
  29. package/dist/integration/wrangler-config.d.ts.map +1 -0
  30. package/dist/integration/wrangler-config.js +97 -0
  31. package/dist/integration/wrangler-patch.d.ts +1 -0
  32. package/dist/integration/wrangler-patch.d.ts.map +1 -1
  33. package/dist/integration/wrangler-patch.js +2 -1
  34. package/dist/server/routes/form-submit.js +1 -1
  35. package/dist/version.d.ts +1 -1
  36. package/dist/version.js +1 -1
  37. package/package.json +11 -3
  38. package/src/admin/assets/logo-mark.svg +5 -0
  39. package/src/admin/client/active-locale.ts +17 -0
  40. package/src/admin/client/api.ts +21 -0
  41. package/src/admin/client/form-from-zod.ts +7 -0
  42. package/src/admin/client/live-preview-enabled.ts +5 -0
  43. package/src/admin/components/AdminShell.astro +45 -0
  44. package/src/admin/components/AuthSettings.vue +60 -0
  45. package/src/admin/components/BlockEditor.vue +53 -0
  46. package/src/admin/components/BlueprintEditor.vue +1783 -0
  47. package/src/admin/components/CollectionKindIcon.vue +26 -0
  48. package/src/admin/components/CollectionTree.vue +220 -0
  49. package/src/admin/components/EntryEditorWithPreview.vue +130 -0
  50. package/src/admin/components/EntryForm.vue +411 -0
  51. package/src/admin/components/EntryList.vue +121 -0
  52. package/src/admin/components/EntryStatusBadge.vue +24 -0
  53. package/src/admin/components/FormEditor.vue +233 -0
  54. package/src/admin/components/FormList.vue +54 -0
  55. package/src/admin/components/GlobalSetEditor.vue +272 -0
  56. package/src/admin/components/GlobalSetList.vue +55 -0
  57. package/src/admin/components/LivePreviewPanel.vue +171 -0
  58. package/src/admin/components/LoginForm.vue +53 -0
  59. package/src/admin/components/MediaLibrary.vue +106 -0
  60. package/src/admin/components/MediaPicker.vue +49 -0
  61. package/src/admin/components/RevisionDiff.vue +11 -0
  62. package/src/admin/components/RevisionList.vue +134 -0
  63. package/src/admin/components/SeoFields.vue +113 -0
  64. package/src/admin/components/SetEditor.vue +137 -0
  65. package/src/admin/components/SetList.vue +32 -0
  66. package/src/admin/components/SettingsForm.vue +189 -0
  67. package/src/admin/components/SideNav.vue +152 -0
  68. package/src/admin/components/SubmissionDetail.vue +45 -0
  69. package/src/admin/components/SubmissionList.vue +89 -0
  70. package/src/admin/components/ToastHost.vue +33 -0
  71. package/src/admin/components/TreeRow.vue +163 -0
  72. package/src/admin/components/UserEditor.vue +186 -0
  73. package/src/admin/components/UserList.vue +46 -0
  74. package/src/admin/components/blocks/BlockItem.vue +32 -0
  75. package/src/admin/components/blocks/BlockToolbar.vue +12 -0
  76. package/src/admin/components/blocks/edit/CodeEdit.vue +18 -0
  77. package/src/admin/components/blocks/edit/EmbedEdit.vue +14 -0
  78. package/src/admin/components/blocks/edit/HeadingEdit.vue +19 -0
  79. package/src/admin/components/blocks/edit/ImageEdit.vue +40 -0
  80. package/src/admin/components/blocks/edit/ListEdit.vue +36 -0
  81. package/src/admin/components/blocks/edit/ParagraphEdit.vue +14 -0
  82. package/src/admin/components/blocks/edit/QuoteEdit.vue +18 -0
  83. package/src/admin/components/fields/BlocksField.vue +123 -0
  84. package/src/admin/components/fields/BlocksSetsPicker.vue +59 -0
  85. package/src/admin/components/fields/BoolField.vue +10 -0
  86. package/src/admin/components/fields/DateField.vue +22 -0
  87. package/src/admin/components/fields/EntriesField.vue +153 -0
  88. package/src/admin/components/fields/EntryField.vue +138 -0
  89. package/src/admin/components/fields/EnumField.vue +81 -0
  90. package/src/admin/components/fields/FieldRenderer.vue +87 -0
  91. package/src/admin/components/fields/GridField.vue +173 -0
  92. package/src/admin/components/fields/LinkField.vue +219 -0
  93. package/src/admin/components/fields/MediaField.vue +69 -0
  94. package/src/admin/components/fields/NumberField.vue +12 -0
  95. package/src/admin/components/fields/ObjectField.vue +18 -0
  96. package/src/admin/components/fields/RefField.vue +170 -0
  97. package/src/admin/components/fields/RepeaterField.vue +27 -0
  98. package/src/admin/components/fields/ReplicatorField.vue +121 -0
  99. package/src/admin/components/fields/TextField.vue +11 -0
  100. package/src/admin/components/fields/TextareaField.vue +11 -0
  101. package/src/admin/components/fields/VulseAccordionGroupNodeView.vue +82 -0
  102. package/src/admin/components/fields/VulseAccordionNodeView.vue +128 -0
  103. package/src/admin/components/fields/VulseCalloutNodeView.vue +81 -0
  104. package/src/admin/components/fields/VulseIframeNodeView.vue +112 -0
  105. package/src/admin/components/fields/VulseSetNodeView.vue +68 -0
  106. package/src/admin/components/fields/VulseVideoNodeView.vue +104 -0
  107. package/src/admin/components/fields/blocks-editor-extensions.ts +26 -0
  108. package/src/admin/components/fields/emoji-extension.ts +54 -0
  109. package/src/admin/components/fields/link-extension.ts +48 -0
  110. package/src/admin/components/fields/set-node-utils.ts +115 -0
  111. package/src/admin/components/fields/url-utils.ts +85 -0
  112. package/src/admin/components/fields/vulse-accordion-extension.ts +64 -0
  113. package/src/admin/components/fields/vulse-accordion-group-extension.ts +49 -0
  114. package/src/admin/components/fields/vulse-callout-extension.ts +53 -0
  115. package/src/admin/components/fields/vulse-iframe-extension.ts +96 -0
  116. package/src/admin/components/fields/vulse-set-extension.ts +66 -0
  117. package/src/admin/components/fields/vulse-video-extension.ts +65 -0
  118. package/src/admin/composables/toast.ts +35 -0
  119. package/src/admin/composables/useEntrySearch.ts +112 -0
  120. package/src/admin/composables/useSets.ts +31 -0
  121. package/src/admin/pages/collections/[name]/[id]/revisions.astro +27 -0
  122. package/src/admin/pages/collections/[name]/[id].astro +90 -0
  123. package/src/admin/pages/collections/[name]/index.astro +31 -0
  124. package/src/admin/pages/collections/[name]/new.astro +38 -0
  125. package/src/admin/pages/forms/[handle]/submissions/[id].astro +9 -0
  126. package/src/admin/pages/forms/[handle]/submissions/index.astro +9 -0
  127. package/src/admin/pages/forms/[handle].astro +9 -0
  128. package/src/admin/pages/forms/index.astro +7 -0
  129. package/src/admin/pages/forms/new.astro +7 -0
  130. package/src/admin/pages/index.astro +36 -0
  131. package/src/admin/pages/login.astro +14 -0
  132. package/src/admin/pages/media.astro +8 -0
  133. package/src/admin/pages/schema/[handle].astro +10 -0
  134. package/src/admin/pages/schema/new.astro +9 -0
  135. package/src/admin/pages/settings/auth.astro +9 -0
  136. package/src/admin/pages/settings/globals/[handle].astro +9 -0
  137. package/src/admin/pages/settings/globals/index.astro +7 -0
  138. package/src/admin/pages/settings/globals/new.astro +7 -0
  139. package/src/admin/pages/settings/index.astro +8 -0
  140. package/src/admin/pages/settings/sets/[handle].astro +9 -0
  141. package/src/admin/pages/settings/sets/index.astro +7 -0
  142. package/src/admin/pages/settings/sets/new.astro +7 -0
  143. package/src/admin/pages/users/[id].astro +10 -0
  144. package/src/admin/pages/users/index.astro +8 -0
  145. package/src/admin/styles/admin.css +166 -0
  146. package/src/core/access.ts +9 -0
  147. package/src/core/blocks/schema.ts +66 -0
  148. package/src/core/blueprints/code-to-definition.ts +156 -0
  149. package/src/core/blueprints/compile.ts +176 -0
  150. package/src/core/blueprints/define.ts +12 -0
  151. package/src/core/blueprints/definition.ts +185 -0
  152. package/src/core/blueprints/load.ts +144 -0
  153. package/src/core/blueprints/mutations.ts +236 -0
  154. package/src/core/blueprints/preview-path.ts +33 -0
  155. package/src/core/blueprints/reflect-fields.ts +305 -0
  156. package/src/core/blueprints/registry.ts +14 -0
  157. package/src/core/blueprints/seed.ts +20 -0
  158. package/src/core/blueprints/select-helpers.ts +30 -0
  159. package/src/core/blueprints/seo.ts +180 -0
  160. package/src/core/blueprints/types.ts +59 -0
  161. package/src/core/blueprints/zod-helpers.ts +86 -0
  162. package/src/core/db.ts +11 -0
  163. package/src/core/errors.ts +34 -0
  164. package/src/core/forms/compile.ts +84 -0
  165. package/src/core/forms/definition.ts +102 -0
  166. package/src/core/forms/rate-limit.ts +52 -0
  167. package/src/core/forms/unique.ts +38 -0
  168. package/src/core/globals/compile.ts +35 -0
  169. package/src/core/globals/definition.ts +27 -0
  170. package/src/core/locales.ts +45 -0
  171. package/src/core/migrations.ts +48 -0
  172. package/src/core/parse-content.ts +85 -0
  173. package/src/core/plugins/definition.ts +150 -0
  174. package/src/core/preview-content.ts +21 -0
  175. package/src/core/repos/entries.ts +504 -0
  176. package/src/core/repos/forms.ts +270 -0
  177. package/src/core/repos/globals.ts +179 -0
  178. package/src/core/repos/media.ts +106 -0
  179. package/src/core/repos/preview-sessions.ts +108 -0
  180. package/src/core/repos/revisions.ts +60 -0
  181. package/src/core/repos/settings.ts +23 -0
  182. package/src/core/schema.ts +244 -0
  183. package/src/core/sets/compile.ts +12 -0
  184. package/src/core/sets/definition.ts +10 -0
  185. package/src/core/sets/service.ts +82 -0
  186. package/src/core/sets/validate-tree.ts +57 -0
  187. package/src/core/sha256.ts +10 -0
  188. package/src/core/slug.ts +30 -0
  189. package/src/scaffold/collection-write.ts +83 -0
  190. package/src/scaffold/collection.ts +277 -0
  191. package/src/server/assets/live-preview-bridge.content.ts +2 -0
  192. package/src/server/assets/live-preview-bridge.js +535 -0
  193. package/src/server/better-auth.ts +82 -0
  194. package/src/server/cf-images.ts +34 -0
  195. package/src/server/cron.ts +37 -0
  196. package/src/server/email.ts +17 -0
  197. package/src/server/endpoints/api-auth.ts +10 -0
  198. package/src/server/endpoints/api-vulse-blueprints.ts +23 -0
  199. package/src/server/endpoints/api-vulse-entries-locales.ts +12 -0
  200. package/src/server/endpoints/api-vulse-entries-move.ts +7 -0
  201. package/src/server/endpoints/api-vulse-entries-publish.ts +7 -0
  202. package/src/server/endpoints/api-vulse-entries-tree.ts +7 -0
  203. package/src/server/endpoints/api-vulse-entries.ts +23 -0
  204. package/src/server/endpoints/api-vulse-form-handle.ts +30 -0
  205. package/src/server/endpoints/api-vulse-form-public.ts +7 -0
  206. package/src/server/endpoints/api-vulse-form-submit.ts +7 -0
  207. package/src/server/endpoints/api-vulse-form-upload.ts +7 -0
  208. package/src/server/endpoints/api-vulse-forms.ts +12 -0
  209. package/src/server/endpoints/api-vulse-globals-handle.ts +20 -0
  210. package/src/server/endpoints/api-vulse-globals-public-handle.ts +7 -0
  211. package/src/server/endpoints/api-vulse-globals-public.ts +7 -0
  212. package/src/server/endpoints/api-vulse-globals-value.ts +8 -0
  213. package/src/server/endpoints/api-vulse-globals.ts +12 -0
  214. package/src/server/endpoints/api-vulse-media-file.ts +7 -0
  215. package/src/server/endpoints/api-vulse-media-id.ts +12 -0
  216. package/src/server/endpoints/api-vulse-media.ts +12 -0
  217. package/src/server/endpoints/api-vulse-preview-bridge.ts +11 -0
  218. package/src/server/endpoints/api-vulse-preview-sessions-id.ts +10 -0
  219. package/src/server/endpoints/api-vulse-preview-sessions.ts +7 -0
  220. package/src/server/endpoints/api-vulse-preview-start.ts +7 -0
  221. package/src/server/endpoints/api-vulse-preview-stop.ts +7 -0
  222. package/src/server/endpoints/api-vulse-revisions-restore.ts +7 -0
  223. package/src/server/endpoints/api-vulse-revisions.ts +7 -0
  224. package/src/server/endpoints/api-vulse-search.ts +7 -0
  225. package/src/server/endpoints/api-vulse-sets.ts +23 -0
  226. package/src/server/endpoints/api-vulse-settings.ts +12 -0
  227. package/src/server/endpoints/api-vulse-users-id.ts +12 -0
  228. package/src/server/endpoints/api-vulse-users-reset-password.ts +7 -0
  229. package/src/server/endpoints/api-vulse-users-role.ts +9 -0
  230. package/src/server/endpoints/api-vulse-users.ts +7 -0
  231. package/src/server/endpoints/with-runtime.ts +11 -0
  232. package/src/server/env.ts +23 -0
  233. package/src/server/envelope.ts +21 -0
  234. package/src/server/forms/email.ts +11 -0
  235. package/src/server/forms/process-submission.ts +95 -0
  236. package/src/server/forms/queue.ts +25 -0
  237. package/src/server/forms/templates.ts +24 -0
  238. package/src/server/forms/webhook.ts +19 -0
  239. package/src/server/handler.ts +66 -0
  240. package/src/server/image-probe.ts +35 -0
  241. package/src/server/loader.ts +54 -0
  242. package/src/server/plugins.ts +214 -0
  243. package/src/server/preview.ts +25 -0
  244. package/src/server/r2.ts +13 -0
  245. package/src/server/routes/blueprints.ts +62 -0
  246. package/src/server/routes/entries.ts +255 -0
  247. package/src/server/routes/form-submit.ts +168 -0
  248. package/src/server/routes/form-upload.ts +100 -0
  249. package/src/server/routes/forms.ts +88 -0
  250. package/src/server/routes/globals-public.ts +30 -0
  251. package/src/server/routes/globals.ts +93 -0
  252. package/src/server/routes/media.ts +145 -0
  253. package/src/server/routes/preview-sessions.ts +76 -0
  254. package/src/server/routes/preview.ts +36 -0
  255. package/src/server/routes/revisions.ts +29 -0
  256. package/src/server/routes/search.ts +31 -0
  257. package/src/server/routes/sets.ts +40 -0
  258. package/src/server/routes/settings.ts +24 -0
  259. package/src/server/routes/users.ts +127 -0
  260. package/src/server/runtime.ts +99 -0
  261. package/src/server/sdk/collections.ts +98 -0
  262. package/src/server/sdk/index.ts +25 -0
  263. package/src/server/sdk/media.ts +11 -0
  264. package/src/server/sdk/search.ts +90 -0
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/cli/migrate.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAAG,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE;AAEpD,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAKpE"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/cli/migrate.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAAG,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE;AAEpD,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpE"}
@@ -1,10 +1,9 @@
1
- import { join, dirname } from 'node:path';
2
- import { fileURLToPath } from 'node:url';
3
1
  import { execSync } from 'node:child_process';
4
- const MIGRATIONS_DIR = join(dirname(fileURLToPath(import.meta.url)), '../../migrations');
2
+ import { ensureWranglerConfig } from '../integration/wrangler-config.js';
5
3
  export async function runMigrate(opts) {
4
+ const file = await ensureWranglerConfig(process.cwd());
6
5
  const flag = opts.remote ? '--remote' : '--local';
7
6
  const cmd = `wrangler d1 migrations apply DB ${flag}`;
8
- console.log(`> ${cmd}`);
7
+ console.log(`> ${cmd} (migrations: node_modules/@ekrist1/vulse/migrations via ${file})`);
9
8
  execSync(cmd, { stdio: 'inherit' });
10
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAiBD,6EAA6E;AAC7E,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAgBnF;AAED,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAc,GAAG,MAAM,CAK9E;AAuCD,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsJrE"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAiBD,6EAA6E;AAC7E,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAgBnF;AAED,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAc,GAAG,MAAM,CAK9E;AAuCD,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuJrE"}
package/dist/cli/setup.js CHANGED
@@ -4,7 +4,7 @@ import { randomBytes } from 'node:crypto';
4
4
  import { execSync } from 'node:child_process';
5
5
  import { createInterface } from 'node:readline/promises';
6
6
  import { stdin, stdout } from 'node:process';
7
- import { patchWranglerToml } from '../integration/wrangler-patch.js';
7
+ import { patchWranglerConfig, findWranglerConfig } from '../integration/wrangler-config.js';
8
8
  import { runMigrate } from './migrate.js';
9
9
  import { runSeedAdmin } from './seed-admin.js';
10
10
  const DEV_VARS_FILE = '.dev.vars';
@@ -117,7 +117,7 @@ export async function runSetup(opts = {}) {
117
117
  try {
118
118
  stdout.write(`\nVulse setup — local development\n\n`);
119
119
  stdout.write(`This wizard will update:\n`);
120
- stdout.write(` • ${WRANGLER_FILE} (D1 + R2 bindings)\n`);
120
+ stdout.write(` • wrangler config (D1 + R2 bindings)\n`);
121
121
  stdout.write(` • ${DEV_VARS_FILE} (local secrets — gitignored)\n`);
122
122
  stdout.write(` • ${GITIGNORE_FILE} (adds ${DEV_VARS_FILE})\n\n`);
123
123
  if (!(await prompter.confirm('Continue?', true))) {
@@ -126,10 +126,11 @@ export async function runSetup(opts = {}) {
126
126
  }
127
127
  // --- Step 1: D1 ---
128
128
  stdout.write(`\nStep 1/3 — Cloudflare D1 (database)\n`);
129
- const wranglerPath = join(cwd, WRANGLER_FILE);
130
- let wranglerToml = await readIfExists(wranglerPath);
129
+ const wranglerFile = (await findWranglerConfig(cwd)) ?? WRANGLER_FILE;
130
+ const wranglerPath = join(cwd, wranglerFile);
131
+ let wranglerConfig = await readIfExists(wranglerPath);
131
132
  const d1Name = await prompter.ask(' D1 database name', 'vulse-db');
132
- wranglerToml = patchWranglerToml(wranglerToml, { d1Name, r2Bucket: 'vulse-media' });
133
+ wranglerConfig = patchWranglerConfig(wranglerConfig, wranglerFile, { d1Name, r2Bucket: 'vulse-media' });
133
134
  let databaseId = await prompter.ask(' D1 database_id (leave blank to create one now)', '');
134
135
  if (!databaseId) {
135
136
  if (await prompter.confirm(` Run \`wrangler d1 create ${d1Name}\`?`, true)) {
@@ -152,11 +153,11 @@ export async function runSetup(opts = {}) {
152
153
  }
153
154
  }
154
155
  if (databaseId)
155
- wranglerToml = setDatabaseId(wranglerToml, databaseId);
156
+ wranglerConfig = setDatabaseId(wranglerConfig, databaseId);
156
157
  // --- Step 2: R2 ---
157
158
  stdout.write(`\nStep 2/3 — Cloudflare R2 (media storage)\n`);
158
159
  const r2Bucket = await prompter.ask(' R2 bucket name', 'vulse-media');
159
- wranglerToml = patchWranglerToml(wranglerToml, { d1Name, r2Bucket });
160
+ wranglerConfig = patchWranglerConfig(wranglerConfig, wranglerFile, { d1Name, r2Bucket });
160
161
  if (await prompter.confirm(` Run \`wrangler r2 bucket create ${r2Bucket}\`?`, true)) {
161
162
  const result = tryRun(`wrangler r2 bucket create ${r2Bucket}`);
162
163
  if (result.ok) {
@@ -170,8 +171,8 @@ export async function runSetup(opts = {}) {
170
171
  stdout.write(` Continuing — you can create it later.\n`);
171
172
  }
172
173
  }
173
- await writeFile(wranglerPath, wranglerToml, 'utf8');
174
- stdout.write(` ✓ wrote ${WRANGLER_FILE}\n`);
174
+ await writeFile(wranglerPath, wranglerConfig, 'utf8');
175
+ stdout.write(` ✓ wrote ${wranglerFile}\n`);
175
176
  // --- Step 3: Secrets + .dev.vars ---
176
177
  stdout.write(`\nStep 3/3 — Secrets\n`);
177
178
  const devVarsPath = join(cwd, DEV_VARS_FILE);
@@ -198,7 +199,7 @@ export async function runSetup(opts = {}) {
198
199
  }
199
200
  // Warn if wrangler.toml still has the placeholder BETTER_AUTH_SECRET — .dev.vars
200
201
  // overrides it in dev, but the placeholder is misleading.
201
- if (wranglerToml.includes(PLACEHOLDER_AUTH_SECRET)) {
202
+ if (wranglerConfig.includes(PLACEHOLDER_AUTH_SECRET)) {
202
203
  stdout.write(` ℹ ${WRANGLER_FILE} still contains the placeholder BETTER_AUTH_SECRET in [vars].\n` +
203
204
  ` ${DEV_VARS_FILE} takes precedence in dev — you can remove the [vars] line.\n`);
204
205
  }
@@ -6,5 +6,5 @@ export interface CompileBlueprintOptions {
6
6
  }
7
7
  export declare function compileBlueprintSchema(def: BlueprintDefinition, options?: CompileBlueprintOptions): z.ZodObject<z.ZodRawShape>;
8
8
  export declare function compileFieldObject(fields: NestedFieldDefinition[]): z.ZodObject<z.ZodRawShape>;
9
- export declare function hashDefinition(def: BlueprintDefinition): string;
9
+ export declare function hashDefinition(def: BlueprintDefinition): Promise<string>;
10
10
  //# sourceMappingURL=compile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/core/blueprints/compile.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,OAAO,KAAK,EACV,mBAAmB,EAEnB,qBAAqB,EAEtB,MAAM,iBAAiB,CAAA;AAKxB,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CAChC;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE,uBAA4B,GACpC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAS5B;AAqHD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAM9F;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,CAoB/D"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/core/blueprints/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAE7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,OAAO,KAAK,EACV,mBAAmB,EAEnB,qBAAqB,EAEtB,MAAM,iBAAiB,CAAA;AAKxB,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CAChC;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE,uBAA4B,GACpC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAS5B;AAqHD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAM9F;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB9E"}
@@ -1,5 +1,5 @@
1
- import { createHash } from 'node:crypto';
2
1
  import { z } from 'astro/zod';
2
+ import { sha256Hex } from '../sha256.js';
3
3
  import { validateSetNodes } from '../sets/validate-tree.js';
4
4
  import { LinkValueSchema } from './definition.js';
5
5
  import { seoZodSchema } from './seo.js';
@@ -130,7 +130,7 @@ export function compileFieldObject(fields) {
130
130
  }
131
131
  return z.object(shape);
132
132
  }
133
- export function hashDefinition(def) {
133
+ export async function hashDefinition(def) {
134
134
  const canonical = JSON.stringify({
135
135
  handle: def.handle,
136
136
  label: def.label,
@@ -149,5 +149,5 @@ export function hashDefinition(def) {
149
149
  validation: f.validation ?? null,
150
150
  })),
151
151
  });
152
- return createHash('sha256').update(canonical).digest('hex');
152
+ return sha256Hex(canonical);
153
153
  }
@@ -10,7 +10,7 @@ export async function createBlueprint(db, input) {
10
10
  handle: def.handle,
11
11
  label: def.label,
12
12
  definition: def,
13
- blueprintHash: hashDefinition(def),
13
+ blueprintHash: await hashDefinition(def),
14
14
  singleton: def.singleton,
15
15
  tree: def.tree === true,
16
16
  drafts: def.drafts === true,
@@ -64,7 +64,7 @@ export async function updateBlueprint(db, handle, input) {
64
64
  await db.update(vulseCollections).set({
65
65
  label: canonical.label,
66
66
  definition: canonical,
67
- blueprintHash: hashDefinition(canonical),
67
+ blueprintHash: await hashDefinition(canonical),
68
68
  singleton: canonical.singleton,
69
69
  tree: canonical.tree === true,
70
70
  drafts: canonical.drafts === true,
@@ -1,5 +1,5 @@
1
1
  import type { VulseDb } from '../db.js';
2
- export declare function hashIp(ip: string): string;
2
+ export declare function hashIp(ip: string): Promise<string>;
3
3
  export declare function checkRateLimit(db: VulseDb, formHandle: string, ipHash: string, opts?: {
4
4
  maxPerIp: number;
5
5
  windowSec: number;
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/core/forms/rate-limit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAGvC,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,OAAO,EACX,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAsC,GAChF,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqCvD"}
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/core/forms/rate-limit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAGvC,wBAAsB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAExD;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,OAAO,EACX,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAsC,GAChF,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqCvD"}
@@ -1,8 +1,8 @@
1
- import { createHash } from 'node:crypto';
1
+ import { sha256Hex } from '../sha256.js';
2
2
  import { eq, and, lt } from 'drizzle-orm';
3
3
  import { vulseFormRateLimits } from '../schema.js';
4
- export function hashIp(ip) {
5
- return createHash('sha256').update(ip).digest('hex');
4
+ export async function hashIp(ip) {
5
+ return sha256Hex(ip);
6
6
  }
7
7
  export async function checkRateLimit(db, formHandle, ipHash, opts = { maxPerIp: 10, windowSec: 3600 }) {
8
8
  const windowMs = opts.windowSec * 1000;
@@ -1,5 +1,5 @@
1
1
  import type { VulseDb } from '../db.js';
2
2
  export declare function normalizeUniqueValue(value: unknown): string;
3
- export declare function hashUniqueValue(value: unknown): string;
3
+ export declare function hashUniqueValue(value: unknown): Promise<string>;
4
4
  export declare function insertUniqueValues(db: VulseDb, formHandle: string, submissionId: string, fields: Record<string, unknown>, uniqueFieldNames: string[]): Promise<void>;
5
5
  //# sourceMappingURL=unique.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"unique.d.ts","sourceRoot":"","sources":["../../../src/core/forms/unique.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAIvC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE3D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEtD;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,OAAO,EACX,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,gBAAgB,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAkBf"}
1
+ {"version":3,"file":"unique.d.ts","sourceRoot":"","sources":["../../../src/core/forms/unique.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAIvC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE3D;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAErE;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,OAAO,EACX,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,gBAAgB,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAkBf"}
@@ -1,11 +1,11 @@
1
- import { createHash } from 'node:crypto';
1
+ import { sha256Hex } from '../sha256.js';
2
2
  import { vulseFormUniqueValues } from '../schema.js';
3
3
  import { ConflictError } from '../errors.js';
4
4
  export function normalizeUniqueValue(value) {
5
5
  return String(value).trim().toLowerCase();
6
6
  }
7
- export function hashUniqueValue(value) {
8
- return createHash('sha256').update(normalizeUniqueValue(value)).digest('hex');
7
+ export async function hashUniqueValue(value) {
8
+ return sha256Hex(normalizeUniqueValue(value));
9
9
  }
10
10
  export async function insertUniqueValues(db, formHandle, submissionId, fields, uniqueFieldNames) {
11
11
  const now = new Date();
@@ -13,7 +13,7 @@ export async function insertUniqueValues(db, formHandle, submissionId, fields, u
13
13
  const value = fields[name];
14
14
  if (value === undefined || value === null || value === '')
15
15
  continue;
16
- const valueHash = hashUniqueValue(value);
16
+ const valueHash = await hashUniqueValue(value);
17
17
  try {
18
18
  await db.insert(vulseFormUniqueValues).values({
19
19
  formHandle,
@@ -9,5 +9,5 @@ export interface CompiledGlobalSet {
9
9
  schema: z.ZodObject<z.ZodRawShape>;
10
10
  hash: string;
11
11
  }
12
- export declare function compileGlobalSet(def: GlobalSetDefinition, sets?: Map<string, CompiledSet>): CompiledGlobalSet;
12
+ export declare function compileGlobalSet(def: GlobalSetDefinition, sets?: Map<string, CompiledSet>): Promise<CompiledGlobalSet>;
13
13
  //# sourceMappingURL=compile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/core/globals/compile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAElC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,KAAK,mBAAmB,EAA2B,MAAM,iBAAiB,CAAA;AAEnF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IAClC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,mBAAmB,EACxB,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAC9B,iBAAiB,CAiBnB"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/core/globals/compile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAElC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,KAAK,mBAAmB,EAA2B,MAAM,iBAAiB,CAAA;AAEnF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IAClC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,mBAAmB,EACxB,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAiB5B"}
@@ -1,6 +1,6 @@
1
1
  import { compileBlueprintSchema } from '../blueprints/compile.js';
2
2
  import { hashGlobalSetDefinition } from './definition.js';
3
- export function compileGlobalSet(def, sets) {
3
+ export async function compileGlobalSet(def, sets) {
4
4
  const options = sets ? { sets } : {};
5
5
  return {
6
6
  handle: def.handle,
@@ -12,6 +12,6 @@ export function compileGlobalSet(def, sets) {
12
12
  singleton: true,
13
13
  fields: def.fields,
14
14
  }, options),
15
- hash: hashGlobalSetDefinition(def),
15
+ hash: await hashGlobalSetDefinition(def),
16
16
  };
17
17
  }
@@ -157,5 +157,5 @@ export declare const GlobalSetDefinitionSchema: z.ZodObject<{
157
157
  }, z.core.$strip>>>;
158
158
  }, z.core.$strip>;
159
159
  export type GlobalSetDefinition = z.infer<typeof GlobalSetDefinitionSchema>;
160
- export declare function hashGlobalSetDefinition(def: GlobalSetDefinition): string;
160
+ export declare function hashGlobalSetDefinition(def: GlobalSetDefinition): Promise<string>;
161
161
  //# sourceMappingURL=definition.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../src/core/globals/definition.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAG7B,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIpC,CAAA;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAE3E,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,CAcxE"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../src/core/globals/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAI7B,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIpC,CAAA;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAE3E,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAcvF"}
@@ -1,12 +1,12 @@
1
- import { createHash } from 'node:crypto';
2
1
  import { z } from 'astro/zod';
2
+ import { sha256Hex } from '../sha256.js';
3
3
  import { FieldDefinitionSchema } from '../blueprints/definition.js';
4
4
  export const GlobalSetDefinitionSchema = z.object({
5
5
  handle: z.string().regex(/^[a-z][a-z0-9_-]*$/),
6
6
  label: z.string().min(1),
7
7
  fields: z.array(FieldDefinitionSchema).default([]),
8
8
  });
9
- export function hashGlobalSetDefinition(def) {
9
+ export async function hashGlobalSetDefinition(def) {
10
10
  const canonical = JSON.stringify({
11
11
  handle: def.handle,
12
12
  label: def.label,
@@ -19,5 +19,5 @@ export function hashGlobalSetDefinition(def) {
19
19
  validation: f.validation ?? null,
20
20
  })),
21
21
  });
22
- return createHash('sha256').update(canonical).digest('hex');
22
+ return sha256Hex(canonical);
23
23
  }
@@ -44,7 +44,7 @@ export class GlobalsRepo {
44
44
  if (existing)
45
45
  throw new ConflictError(`global set already exists: ${def.handle}`);
46
46
  const now = new Date();
47
- const hash = hashGlobalSetDefinition(def);
47
+ const hash = await hashGlobalSetDefinition(def);
48
48
  await this.db.insert(vulseGlobalSets).values({
49
49
  handle: def.handle,
50
50
  label: def.label,
@@ -78,7 +78,7 @@ export class GlobalsRepo {
78
78
  await this.db.update(vulseGlobalSets).set({
79
79
  label: def.label,
80
80
  definition: def,
81
- blueprintHash: hashGlobalSetDefinition(def),
81
+ blueprintHash: await hashGlobalSetDefinition(def),
82
82
  updatedAt: new Date(),
83
83
  }).where(eq(vulseGlobalSets.handle, handle));
84
84
  const row = await this.findSetByHandle(handle);
@@ -104,7 +104,7 @@ export class GlobalsRepo {
104
104
  if (!set)
105
105
  throw new NotFoundError('global set not found');
106
106
  const sets = await loadCompiledSets(this.db);
107
- const compiled = compileGlobalSet(set.definition, sets);
107
+ const compiled = await compileGlobalSet(set.definition, sets);
108
108
  const result = compiled.schema.safeParse(input);
109
109
  if (!result.success) {
110
110
  throw new ValidationError('Invalid global value', { issues: result.error.issues });
@@ -0,0 +1,3 @@
1
+ /** Workers-safe SHA-256 hex digest (no node:crypto). */
2
+ export declare function sha256Hex(input: string): Promise<string>;
3
+ //# sourceMappingURL=sha256.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sha256.d.ts","sourceRoot":"","sources":["../../src/core/sha256.ts"],"names":[],"mappings":"AAIA,wDAAwD;AACxD,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9D"}
@@ -0,0 +1,9 @@
1
+ function bytesToHex(bytes) {
2
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
3
+ }
4
+ /** Workers-safe SHA-256 hex digest (no node:crypto). */
5
+ export async function sha256Hex(input) {
6
+ const data = new TextEncoder().encode(input);
7
+ const hash = await crypto.subtle.digest('SHA-256', data);
8
+ return bytesToHex(new Uint8Array(hash));
9
+ }
@@ -50,7 +50,7 @@ export default function vulse(opts = {}) {
50
50
  ssr: {
51
51
  // Bundle vulse in-process for Cloudflare's module runner; avoid
52
52
  // noExternal: true — it pulls native dev deps (tailwind oxide, babel) into SSR.
53
- noExternal: ['@ekrist1/vulse'],
53
+ noExternal: ['@ekrist1/vulse', '@astrojs/vue'],
54
54
  optimizeDeps: {
55
55
  exclude: [...OPTIMIZE_DEPS_EXCLUDE],
56
56
  },
@@ -1 +1 @@
1
- {"version":3,"file":"install-hook.d.ts","sourceRoot":"","sources":["../../src/integration/install-hook.ts"],"names":[],"mappings":"AAsCA,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC/D"}
1
+ {"version":3,"file":"install-hook.d.ts","sourceRoot":"","sources":["../../src/integration/install-hook.ts"],"names":[],"mappings":"AAsCA,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC/D"}
@@ -1,7 +1,7 @@
1
1
  import { readFile, writeFile, mkdir, access } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { VULSE_PACKAGE } from '../package-name.js';
4
- import { patchWranglerToml } from './wrangler-patch.js';
4
+ import { ensureWranglerConfig, patchWranglerConfig, findWranglerConfig } from './wrangler-config.js';
5
5
  const STARTER_BLUEPRINT = `import { defineCollection, z } from '${VULSE_PACKAGE}'
6
6
 
7
7
  export default defineCollection({
@@ -39,9 +39,10 @@ async function fileExists(path) {
39
39
  }
40
40
  }
41
41
  export async function runInstallHook(cwd) {
42
- const wranglerPath = join(cwd, 'wrangler.toml');
42
+ const wranglerFile = await findWranglerConfig(cwd);
43
+ const wranglerPath = join(cwd, wranglerFile ?? 'wrangler.toml');
43
44
  const existing = (await fileExists(wranglerPath)) ? await readFile(wranglerPath, 'utf8') : '';
44
- const patched = patchWranglerToml(existing, { d1Name: 'vulse-db', r2Bucket: 'vulse-media' });
45
+ const patched = patchWranglerConfig(existing, wranglerFile ?? 'wrangler.toml', { d1Name: 'vulse-db', r2Bucket: 'vulse-media' });
45
46
  if (patched !== existing)
46
47
  await writeFile(wranglerPath, patched, 'utf8');
47
48
  const collectionsDir = join(cwd, 'src/vulse/collections');
@@ -63,9 +64,10 @@ export async function runInstallHook(cwd) {
63
64
  ✅ Vulse installed.
64
65
 
65
66
  One-time setup (copy/paste):
67
+ pnpm add @astrojs/vue vue # required at project root for the admin UI renderer
66
68
  wrangler d1 create vulse-db
67
69
  wrangler r2 bucket create vulse-media
68
- # Paste the returned database_id into wrangler.toml (search for TODO_PASTE_ID).
70
+ # Paste the returned database_id into your wrangler config (search for TODO_PASTE_ID).
69
71
  npx vulse migrate
70
72
  npx vulse seed:admin --email you@example.com
71
73
 
@@ -0,0 +1,12 @@
1
+ import { type PatchOptions } from './wrangler-patch.js';
2
+ declare const WRANGLER_FILES: readonly ["wrangler.jsonc", "wrangler.toml", "wrangler.json"];
3
+ export type WranglerConfigFile = (typeof WRANGLER_FILES)[number];
4
+ /** Prefer the wrangler file Astro/Cloudflare already created. */
5
+ export declare function findWranglerConfig(cwd: string): Promise<WranglerConfigFile | null>;
6
+ export declare function isJsonWranglerConfig(file: WranglerConfigFile): boolean;
7
+ export declare function patchWranglerJsonc(input: string, opts?: PatchOptions): string;
8
+ export declare function patchWranglerConfig(input: string, file: WranglerConfigFile, opts?: PatchOptions): string;
9
+ /** Ensure the active wrangler config points migrations at the bundled package SQL. */
10
+ export declare function ensureWranglerConfig(cwd: string, opts?: PatchOptions): Promise<WranglerConfigFile>;
11
+ export {};
12
+ //# sourceMappingURL=wrangler-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrangler-config.d.ts","sourceRoot":"","sources":["../../src/integration/wrangler-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEhG,QAAA,MAAM,cAAc,+DAAgE,CAAA;AAGpF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAMhE,iEAAiE;AACjE,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAKxF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAEtE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,YAA4B,GAAG,MAAM,CAyD5F;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,kBAAkB,EACxB,IAAI,GAAE,YAA4B,GACjC,MAAM,CAmBR;AAED,sFAAsF;AACtF,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,YAA4B,GACjC,OAAO,CAAC,kBAAkB,CAAC,CAQ7B"}
@@ -0,0 +1,97 @@
1
+ import { access, readFile, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { patchWranglerToml, VULSE_MIGRATIONS_DIR } from './wrangler-patch.js';
4
+ const WRANGLER_FILES = ['wrangler.jsonc', 'wrangler.toml', 'wrangler.json'];
5
+ const DEFAULT_PATCH = { d1Name: 'vulse-db', r2Bucket: 'vulse-media' };
6
+ async function fileExists(path) {
7
+ try {
8
+ await access(path);
9
+ return true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ /** Prefer the wrangler file Astro/Cloudflare already created. */
16
+ export async function findWranglerConfig(cwd) {
17
+ for (const file of WRANGLER_FILES) {
18
+ if (await fileExists(join(cwd, file)))
19
+ return file;
20
+ }
21
+ return null;
22
+ }
23
+ export function isJsonWranglerConfig(file) {
24
+ return file === 'wrangler.jsonc' || file === 'wrangler.json';
25
+ }
26
+ export function patchWranglerJsonc(input, opts = DEFAULT_PATCH) {
27
+ const D1_MARKER = '// vulse:d1';
28
+ const R2_MARKER = '// vulse:r2';
29
+ let out = input.trimEnd();
30
+ if (!out.endsWith('\n'))
31
+ out += '\n';
32
+ if (!out.includes(D1_MARKER)) {
33
+ if (/["']binding["']\s*:\s*["']DB["']/.test(out) && !out.includes('migrations_dir')) {
34
+ out = out.replace(/("binding"\s*:\s*"DB"[\s\S]*?)(}\s*,?\s*(?=\]|,|\n\s*}))/, (match, prefix, suffix) => {
35
+ if (prefix.includes('migrations_dir'))
36
+ return match;
37
+ const sep = prefix.trimEnd().endsWith(',') ? '\n ' : ',\n ';
38
+ return `${prefix}${sep}"migrations_dir": "${VULSE_MIGRATIONS_DIR}"${suffix}`;
39
+ });
40
+ }
41
+ else if (!out.includes('"d1_databases"')) {
42
+ const d1Block = ` ${D1_MARKER}
43
+ "d1_databases": [
44
+ {
45
+ "binding": "DB",
46
+ "database_name": "${opts.d1Name}",
47
+ "database_id": "TODO_PASTE_ID_FROM_WRANGLER_OUTPUT",
48
+ "migrations_dir": "${VULSE_MIGRATIONS_DIR}"
49
+ }
50
+ ],`;
51
+ out = out.replace(/\}\s*$/, `${d1Block}\n}\n`);
52
+ }
53
+ }
54
+ if (!out.includes(R2_MARKER) && !out.includes('"r2_buckets"')) {
55
+ const r2Block = ` ${R2_MARKER}
56
+ "r2_buckets": [
57
+ {
58
+ "binding": "BUCKET",
59
+ "bucket_name": "${opts.r2Bucket}"
60
+ }
61
+ ],`;
62
+ out = out.replace(/\}\s*$/, `${r2Block}\n}\n`);
63
+ }
64
+ if (!out.includes('nodejs_compat')) {
65
+ if (out.includes('"compatibility_flags"')) {
66
+ out = out.replace(/"compatibility_flags"\s*:\s*\[(.*?)\]/s, (match, flags) => flags.includes('nodejs_compat') ? match : `"compatibility_flags": [${flags.trim()}${flags.trim() ? ', ' : ''}"nodejs_compat"]`);
67
+ }
68
+ else if (out.includes('"compatibility_date"')) {
69
+ out = out.replace(/"compatibility_date"\s*:\s*"[^"]*"/, (m) => `${m},\n "compatibility_flags": ["nodejs_compat"]`);
70
+ }
71
+ }
72
+ return out;
73
+ }
74
+ export function patchWranglerConfig(input, file, opts = DEFAULT_PATCH) {
75
+ const patched = isJsonWranglerConfig(file) ? patchWranglerJsonc(input, opts) : patchWranglerToml(input, opts);
76
+ if (patched.includes('migrations_dir'))
77
+ return patched;
78
+ // Cloudflare scaffold may already define D1 without migrations_dir (no vulse marker).
79
+ if (file.endsWith('.toml') && patched.includes('binding = "DB"') && !patched.includes('migrations_dir')) {
80
+ if (patched.includes('database_id = ')) {
81
+ return patched.replace(/(database_id = "[^"]*")/, `$1\nmigrations_dir = "${VULSE_MIGRATIONS_DIR}"`);
82
+ }
83
+ return patched.replace(/(binding = "DB"[^\n]*\n)/, `$1migrations_dir = "${VULSE_MIGRATIONS_DIR}"\n`);
84
+ }
85
+ return patched;
86
+ }
87
+ /** Ensure the active wrangler config points migrations at the bundled package SQL. */
88
+ export async function ensureWranglerConfig(cwd, opts = DEFAULT_PATCH) {
89
+ const existing = await findWranglerConfig(cwd);
90
+ const file = existing ?? 'wrangler.toml';
91
+ const path = join(cwd, file);
92
+ const before = existing ? await readFile(path, 'utf8') : '';
93
+ const after = patchWranglerConfig(before, file, opts);
94
+ if (after !== before)
95
+ await writeFile(path, after, 'utf8');
96
+ return file;
97
+ }
@@ -2,5 +2,6 @@ export interface PatchOptions {
2
2
  d1Name: string;
3
3
  r2Bucket: string;
4
4
  }
5
+ export declare const VULSE_MIGRATIONS_DIR = "node_modules/@ekrist1/vulse/migrations";
5
6
  export declare function patchWranglerToml(input: string, opts: PatchOptions): string;
6
7
  //# sourceMappingURL=wrangler-patch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wrangler-patch.d.ts","sourceRoot":"","sources":["../../src/integration/wrangler-patch.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAe3E"}
1
+ {"version":3,"file":"wrangler-patch.d.ts","sourceRoot":"","sources":["../../src/integration/wrangler-patch.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,oBAAoB,2CAA6C,CAAA;AAK9E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAe3E"}
@@ -1,4 +1,5 @@
1
1
  import { VULSE_PACKAGE } from '../package-name.js';
2
+ export const VULSE_MIGRATIONS_DIR = `node_modules/${VULSE_PACKAGE}/migrations`;
2
3
  const D1_MARKER = '# vulse:d1';
3
4
  const R2_MARKER = '# vulse:r2';
4
5
  export function patchWranglerToml(input, opts) {
@@ -6,7 +7,7 @@ export function patchWranglerToml(input, opts) {
6
7
  const hasR2 = input.includes(R2_MARKER);
7
8
  let out = input;
8
9
  if (!hasD1) {
9
- out += `\n${D1_MARKER}\n[[d1_databases]]\nbinding = "DB"\ndatabase_name = "${opts.d1Name}"\ndatabase_id = "TODO_PASTE_ID_FROM_WRANGLER_OUTPUT"\nmigrations_dir = "node_modules/${VULSE_PACKAGE}/migrations"\n`;
10
+ out += `\n${D1_MARKER}\n[[d1_databases]]\nbinding = "DB"\ndatabase_name = "${opts.d1Name}"\ndatabase_id = "TODO_PASTE_ID_FROM_WRANGLER_OUTPUT"\nmigrations_dir = "${VULSE_MIGRATIONS_DIR}"\n`;
10
11
  }
11
12
  if (!hasR2) {
12
13
  out += `\n${R2_MARKER}\n[[r2_buckets]]\nbinding = "BUCKET"\nbucket_name = "${opts.r2Bucket}"\n`;
@@ -80,7 +80,7 @@ export function formSubmitRoutes(db, options = {}) {
80
80
  });
81
81
  }
82
82
  const rate = def.settings.rateLimit ?? { maxPerIp: 10, windowSec: 3600 };
83
- const rl = await checkRateLimit(db, handle, hashIp(ip), rate);
83
+ const rl = await checkRateLimit(db, handle, await hashIp(ip), rate);
84
84
  if (!rl.allowed) {
85
85
  return new Response(JSON.stringify({
86
86
  ok: false,
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VULSE_VERSION = "0.1.6-alpha.3";
1
+ export declare const VULSE_VERSION = "0.1.7-alpha.4";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by sync-version — do not edit
2
- export const VULSE_VERSION = "0.1.6-alpha.3";
2
+ export const VULSE_VERSION = "0.1.7-alpha.4";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekrist1/vulse",
3
- "version": "0.1.6-alpha.3",
3
+ "version": "0.1.7-alpha.4",
4
4
  "description": "Astro-native headless CMS for Cloudflare (D1, R2, Workers)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -72,6 +72,10 @@
72
72
  "files": [
73
73
  "dist",
74
74
  "migrations",
75
+ "src/admin",
76
+ "src/core",
77
+ "src/server",
78
+ "src/scaffold",
75
79
  "src/client",
76
80
  "LICENSE",
77
81
  "README.md"
@@ -90,6 +94,7 @@
90
94
  },
91
95
  "dependencies": {
92
96
  "@astrojs/vue": "^6.0.1",
97
+ "@tailwindcss/vite": "^4.3.0",
93
98
  "@tiptap/core": "^2.8.0",
94
99
  "@tiptap/pm": "^2.8.0",
95
100
  "@tiptap/starter-kit": "^2.8.0",
@@ -101,28 +106,31 @@
101
106
  "jose": "^6.2.3",
102
107
  "morphdom": "^2.7.8",
103
108
  "nanoid": "^5.0.0",
109
+ "tailwindcss": "^4",
104
110
  "vue": "^3.5.34"
105
111
  },
106
112
  "devDependencies": {
107
113
  "@cloudflare/vitest-pool-workers": "^0.6.0",
108
114
  "@cloudflare/workers-types": "^4.20240320.0",
109
- "@tailwindcss/vite": "^4.3.0",
110
115
  "@types/diff": "^8.0.0",
111
116
  "@types/node": "^22.0.0",
112
117
  "astro": "^6.3.7",
113
118
  "drizzle-kit": "^0.31.10",
114
119
  "esbuild": "^0.25.12",
115
- "tailwindcss": "^4",
116
120
  "typescript": "^5.6.0",
117
121
  "vite": "^7.3.0",
118
122
  "vitest": "^2.1.0",
119
123
  "wrangler": "^4.94.0"
120
124
  },
121
125
  "peerDependencies": {
126
+ "@astrojs/vue": "^6.0.0",
122
127
  "astro": "^6.3.0",
123
128
  "vue": "^3.5.0"
124
129
  },
125
130
  "peerDependenciesMeta": {
131
+ "@astrojs/vue": {
132
+ "optional": false
133
+ },
126
134
  "vue": {
127
135
  "optional": false
128
136
  }
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" role="img" aria-label="Vulse">
2
+ <rect x="0" y="0" width="120" height="120" rx="24" fill="#0B0B0C"></rect>
3
+ <path d="M30 36 L60 92 L90 36" stroke="#FAFAF7" stroke-width="11" stroke-linecap="round" stroke-linejoin="round" fill="none"></path>
4
+ <circle cx="60" cy="92" r="6" fill="#FF5B2E"></circle>
5
+ </svg>