@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
@@ -0,0 +1,535 @@
1
+ // ../../node_modules/.pnpm/morphdom@2.7.8/node_modules/morphdom/dist/morphdom-esm.js
2
+ var DOCUMENT_FRAGMENT_NODE = 11;
3
+ function morphAttrs(fromNode, toNode) {
4
+ var toNodeAttrs = toNode.attributes;
5
+ var attr;
6
+ var attrName;
7
+ var attrNamespaceURI;
8
+ var attrValue;
9
+ var fromValue;
10
+ if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) {
11
+ return;
12
+ }
13
+ for (var i = toNodeAttrs.length - 1; i >= 0; i--) {
14
+ attr = toNodeAttrs[i];
15
+ attrName = attr.name;
16
+ attrNamespaceURI = attr.namespaceURI;
17
+ attrValue = attr.value;
18
+ if (attrNamespaceURI) {
19
+ attrName = attr.localName || attrName;
20
+ fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);
21
+ if (fromValue !== attrValue) {
22
+ if (attr.prefix === "xmlns") {
23
+ attrName = attr.name;
24
+ }
25
+ fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);
26
+ }
27
+ } else {
28
+ fromValue = fromNode.getAttribute(attrName);
29
+ if (fromValue !== attrValue) {
30
+ fromNode.setAttribute(attrName, attrValue);
31
+ }
32
+ }
33
+ }
34
+ var fromNodeAttrs = fromNode.attributes;
35
+ for (var d = fromNodeAttrs.length - 1; d >= 0; d--) {
36
+ attr = fromNodeAttrs[d];
37
+ attrName = attr.name;
38
+ attrNamespaceURI = attr.namespaceURI;
39
+ if (attrNamespaceURI) {
40
+ attrName = attr.localName || attrName;
41
+ if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) {
42
+ fromNode.removeAttributeNS(attrNamespaceURI, attrName);
43
+ }
44
+ } else {
45
+ if (!toNode.hasAttribute(attrName)) {
46
+ fromNode.removeAttribute(attrName);
47
+ }
48
+ }
49
+ }
50
+ }
51
+ var range;
52
+ var NS_XHTML = "http://www.w3.org/1999/xhtml";
53
+ var doc = typeof document === "undefined" ? void 0 : document;
54
+ var HAS_TEMPLATE_SUPPORT = !!doc && "content" in doc.createElement("template");
55
+ var HAS_RANGE_SUPPORT = !!doc && doc.createRange && "createContextualFragment" in doc.createRange();
56
+ function createFragmentFromTemplate(str) {
57
+ var template = doc.createElement("template");
58
+ template.innerHTML = str;
59
+ return template.content.childNodes[0];
60
+ }
61
+ function createFragmentFromRange(str) {
62
+ if (!range) {
63
+ range = doc.createRange();
64
+ range.selectNode(doc.body);
65
+ }
66
+ var fragment = range.createContextualFragment(str);
67
+ return fragment.childNodes[0];
68
+ }
69
+ function createFragmentFromWrap(str) {
70
+ var fragment = doc.createElement("body");
71
+ fragment.innerHTML = str;
72
+ return fragment.childNodes[0];
73
+ }
74
+ function toElement(str) {
75
+ str = str.trim();
76
+ if (HAS_TEMPLATE_SUPPORT) {
77
+ return createFragmentFromTemplate(str);
78
+ } else if (HAS_RANGE_SUPPORT) {
79
+ return createFragmentFromRange(str);
80
+ }
81
+ return createFragmentFromWrap(str);
82
+ }
83
+ function compareNodeNames(fromEl, toEl) {
84
+ var fromNodeName = fromEl.nodeName;
85
+ var toNodeName = toEl.nodeName;
86
+ var fromCodeStart, toCodeStart;
87
+ if (fromNodeName === toNodeName) {
88
+ return true;
89
+ }
90
+ fromCodeStart = fromNodeName.charCodeAt(0);
91
+ toCodeStart = toNodeName.charCodeAt(0);
92
+ if (fromCodeStart <= 90 && toCodeStart >= 97) {
93
+ return fromNodeName === toNodeName.toUpperCase();
94
+ } else if (toCodeStart <= 90 && fromCodeStart >= 97) {
95
+ return toNodeName === fromNodeName.toUpperCase();
96
+ } else {
97
+ return false;
98
+ }
99
+ }
100
+ function createElementNS(name, namespaceURI) {
101
+ return !namespaceURI || namespaceURI === NS_XHTML ? doc.createElement(name) : doc.createElementNS(namespaceURI, name);
102
+ }
103
+ function moveChildren(fromEl, toEl) {
104
+ var curChild = fromEl.firstChild;
105
+ while (curChild) {
106
+ var nextChild = curChild.nextSibling;
107
+ toEl.appendChild(curChild);
108
+ curChild = nextChild;
109
+ }
110
+ return toEl;
111
+ }
112
+ function syncBooleanAttrProp(fromEl, toEl, name) {
113
+ if (fromEl[name] !== toEl[name]) {
114
+ fromEl[name] = toEl[name];
115
+ if (fromEl[name]) {
116
+ fromEl.setAttribute(name, "");
117
+ } else {
118
+ fromEl.removeAttribute(name);
119
+ }
120
+ }
121
+ }
122
+ var specialElHandlers = {
123
+ OPTION: function(fromEl, toEl) {
124
+ var parentNode = fromEl.parentNode;
125
+ if (parentNode) {
126
+ var parentName = parentNode.nodeName.toUpperCase();
127
+ if (parentName === "OPTGROUP") {
128
+ parentNode = parentNode.parentNode;
129
+ parentName = parentNode && parentNode.nodeName.toUpperCase();
130
+ }
131
+ if (parentName === "SELECT" && !parentNode.hasAttribute("multiple")) {
132
+ if (fromEl.hasAttribute("selected") && !toEl.selected) {
133
+ fromEl.setAttribute("selected", "selected");
134
+ fromEl.removeAttribute("selected");
135
+ }
136
+ parentNode.selectedIndex = -1;
137
+ }
138
+ }
139
+ syncBooleanAttrProp(fromEl, toEl, "selected");
140
+ },
141
+ /**
142
+ * The "value" attribute is special for the <input> element since it sets
143
+ * the initial value. Changing the "value" attribute without changing the
144
+ * "value" property will have no effect since it is only used to the set the
145
+ * initial value. Similar for the "checked" attribute, and "disabled".
146
+ */
147
+ INPUT: function(fromEl, toEl) {
148
+ syncBooleanAttrProp(fromEl, toEl, "checked");
149
+ syncBooleanAttrProp(fromEl, toEl, "disabled");
150
+ if (fromEl.value !== toEl.value) {
151
+ fromEl.value = toEl.value;
152
+ }
153
+ if (!toEl.hasAttribute("value")) {
154
+ fromEl.removeAttribute("value");
155
+ }
156
+ },
157
+ TEXTAREA: function(fromEl, toEl) {
158
+ var newValue = toEl.value;
159
+ if (fromEl.value !== newValue) {
160
+ fromEl.value = newValue;
161
+ }
162
+ var firstChild = fromEl.firstChild;
163
+ if (firstChild) {
164
+ var oldValue = firstChild.nodeValue;
165
+ if (oldValue == newValue || !newValue && oldValue == fromEl.placeholder) {
166
+ return;
167
+ }
168
+ firstChild.nodeValue = newValue;
169
+ }
170
+ },
171
+ SELECT: function(fromEl, toEl) {
172
+ if (!toEl.hasAttribute("multiple")) {
173
+ var selectedIndex = -1;
174
+ var i = 0;
175
+ var curChild = fromEl.firstChild;
176
+ var optgroup;
177
+ var nodeName;
178
+ while (curChild) {
179
+ nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();
180
+ if (nodeName === "OPTGROUP") {
181
+ optgroup = curChild;
182
+ curChild = optgroup.firstChild;
183
+ if (!curChild) {
184
+ curChild = optgroup.nextSibling;
185
+ optgroup = null;
186
+ }
187
+ } else {
188
+ if (nodeName === "OPTION") {
189
+ if (curChild.hasAttribute("selected")) {
190
+ selectedIndex = i;
191
+ break;
192
+ }
193
+ i++;
194
+ }
195
+ curChild = curChild.nextSibling;
196
+ if (!curChild && optgroup) {
197
+ curChild = optgroup.nextSibling;
198
+ optgroup = null;
199
+ }
200
+ }
201
+ }
202
+ fromEl.selectedIndex = selectedIndex;
203
+ }
204
+ }
205
+ };
206
+ var ELEMENT_NODE = 1;
207
+ var DOCUMENT_FRAGMENT_NODE$1 = 11;
208
+ var TEXT_NODE = 3;
209
+ var COMMENT_NODE = 8;
210
+ function noop() {
211
+ }
212
+ function defaultGetNodeKey(node) {
213
+ if (node) {
214
+ return node.getAttribute && node.getAttribute("id") || node.id;
215
+ }
216
+ }
217
+ function morphdomFactory(morphAttrs2) {
218
+ return function morphdom2(fromNode, toNode, options) {
219
+ if (!options) {
220
+ options = {};
221
+ }
222
+ if (typeof toNode === "string") {
223
+ if (fromNode.nodeName === "#document" || fromNode.nodeName === "HTML") {
224
+ var toNodeHtml = toNode;
225
+ toNode = doc.createElement("html");
226
+ toNode.innerHTML = toNodeHtml;
227
+ } else if (fromNode.nodeName === "BODY") {
228
+ var toNodeBody = toNode;
229
+ toNode = doc.createElement("html");
230
+ toNode.innerHTML = toNodeBody;
231
+ var bodyElement = toNode.querySelector("body");
232
+ if (bodyElement) {
233
+ toNode = bodyElement;
234
+ }
235
+ } else {
236
+ toNode = toElement(toNode);
237
+ }
238
+ } else if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
239
+ toNode = toNode.firstElementChild;
240
+ }
241
+ var getNodeKey = options.getNodeKey || defaultGetNodeKey;
242
+ var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;
243
+ var onNodeAdded = options.onNodeAdded || noop;
244
+ var onBeforeElUpdated = options.onBeforeElUpdated || noop;
245
+ var onElUpdated = options.onElUpdated || noop;
246
+ var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
247
+ var onNodeDiscarded = options.onNodeDiscarded || noop;
248
+ var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;
249
+ var skipFromChildren = options.skipFromChildren || noop;
250
+ var addChild = options.addChild || function(parent, child) {
251
+ return parent.appendChild(child);
252
+ };
253
+ var childrenOnly = options.childrenOnly === true;
254
+ var fromNodesLookup = /* @__PURE__ */ Object.create(null);
255
+ var keyedRemovalList = [];
256
+ function addKeyedRemoval(key) {
257
+ keyedRemovalList.push(key);
258
+ }
259
+ function walkDiscardedChildNodes(node, skipKeyedNodes) {
260
+ if (node.nodeType === ELEMENT_NODE) {
261
+ var curChild = node.firstChild;
262
+ while (curChild) {
263
+ var key = void 0;
264
+ if (skipKeyedNodes && (key = getNodeKey(curChild))) {
265
+ addKeyedRemoval(key);
266
+ } else {
267
+ onNodeDiscarded(curChild);
268
+ if (curChild.firstChild) {
269
+ walkDiscardedChildNodes(curChild, skipKeyedNodes);
270
+ }
271
+ }
272
+ curChild = curChild.nextSibling;
273
+ }
274
+ }
275
+ }
276
+ function removeNode(node, parentNode, skipKeyedNodes) {
277
+ if (onBeforeNodeDiscarded(node) === false) {
278
+ return;
279
+ }
280
+ if (parentNode) {
281
+ parentNode.removeChild(node);
282
+ }
283
+ onNodeDiscarded(node);
284
+ walkDiscardedChildNodes(node, skipKeyedNodes);
285
+ }
286
+ function indexTree(node) {
287
+ if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
288
+ var curChild = node.firstChild;
289
+ while (curChild) {
290
+ var key = getNodeKey(curChild);
291
+ if (key) {
292
+ fromNodesLookup[key] = curChild;
293
+ }
294
+ indexTree(curChild);
295
+ curChild = curChild.nextSibling;
296
+ }
297
+ }
298
+ }
299
+ indexTree(fromNode);
300
+ function handleNodeAdded(el) {
301
+ onNodeAdded(el);
302
+ var curChild = el.firstChild;
303
+ while (curChild) {
304
+ var nextSibling = curChild.nextSibling;
305
+ var key = getNodeKey(curChild);
306
+ if (key) {
307
+ var unmatchedFromEl = fromNodesLookup[key];
308
+ if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {
309
+ curChild.parentNode.replaceChild(unmatchedFromEl, curChild);
310
+ morphEl(unmatchedFromEl, curChild);
311
+ } else {
312
+ handleNodeAdded(curChild);
313
+ }
314
+ } else {
315
+ handleNodeAdded(curChild);
316
+ }
317
+ curChild = nextSibling;
318
+ }
319
+ }
320
+ function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {
321
+ while (curFromNodeChild) {
322
+ var fromNextSibling = curFromNodeChild.nextSibling;
323
+ if (curFromNodeKey = getNodeKey(curFromNodeChild)) {
324
+ addKeyedRemoval(curFromNodeKey);
325
+ } else {
326
+ removeNode(
327
+ curFromNodeChild,
328
+ fromEl,
329
+ true
330
+ /* skip keyed nodes */
331
+ );
332
+ }
333
+ curFromNodeChild = fromNextSibling;
334
+ }
335
+ }
336
+ function morphEl(fromEl, toEl, childrenOnly2) {
337
+ var toElKey = getNodeKey(toEl);
338
+ if (toElKey) {
339
+ delete fromNodesLookup[toElKey];
340
+ }
341
+ if (!childrenOnly2) {
342
+ var beforeUpdateResult = onBeforeElUpdated(fromEl, toEl);
343
+ if (beforeUpdateResult === false) {
344
+ return;
345
+ } else if (beforeUpdateResult instanceof HTMLElement) {
346
+ fromEl = beforeUpdateResult;
347
+ indexTree(fromEl);
348
+ }
349
+ morphAttrs2(fromEl, toEl);
350
+ onElUpdated(fromEl);
351
+ if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {
352
+ return;
353
+ }
354
+ }
355
+ if (fromEl.nodeName !== "TEXTAREA") {
356
+ morphChildren(fromEl, toEl);
357
+ } else {
358
+ specialElHandlers.TEXTAREA(fromEl, toEl);
359
+ }
360
+ }
361
+ function morphChildren(fromEl, toEl) {
362
+ var skipFrom = skipFromChildren(fromEl, toEl);
363
+ var curToNodeChild = toEl.firstChild;
364
+ var curFromNodeChild = fromEl.firstChild;
365
+ var curToNodeKey;
366
+ var curFromNodeKey;
367
+ var fromNextSibling;
368
+ var toNextSibling;
369
+ var matchingFromEl;
370
+ outer: while (curToNodeChild) {
371
+ toNextSibling = curToNodeChild.nextSibling;
372
+ curToNodeKey = getNodeKey(curToNodeChild);
373
+ while (!skipFrom && curFromNodeChild) {
374
+ fromNextSibling = curFromNodeChild.nextSibling;
375
+ if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {
376
+ curToNodeChild = toNextSibling;
377
+ curFromNodeChild = fromNextSibling;
378
+ continue outer;
379
+ }
380
+ curFromNodeKey = getNodeKey(curFromNodeChild);
381
+ var curFromNodeType = curFromNodeChild.nodeType;
382
+ var isCompatible = void 0;
383
+ if (curFromNodeType === curToNodeChild.nodeType) {
384
+ if (curFromNodeType === ELEMENT_NODE) {
385
+ if (curToNodeKey) {
386
+ if (curToNodeKey !== curFromNodeKey) {
387
+ if (matchingFromEl = fromNodesLookup[curToNodeKey]) {
388
+ if (fromNextSibling === matchingFromEl) {
389
+ isCompatible = false;
390
+ } else {
391
+ fromEl.insertBefore(matchingFromEl, curFromNodeChild);
392
+ if (curFromNodeKey) {
393
+ addKeyedRemoval(curFromNodeKey);
394
+ } else {
395
+ removeNode(
396
+ curFromNodeChild,
397
+ fromEl,
398
+ true
399
+ /* skip keyed nodes */
400
+ );
401
+ }
402
+ curFromNodeChild = matchingFromEl;
403
+ curFromNodeKey = getNodeKey(curFromNodeChild);
404
+ }
405
+ } else {
406
+ isCompatible = false;
407
+ }
408
+ }
409
+ } else if (curFromNodeKey) {
410
+ isCompatible = false;
411
+ }
412
+ isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);
413
+ if (isCompatible) {
414
+ morphEl(curFromNodeChild, curToNodeChild);
415
+ }
416
+ } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {
417
+ isCompatible = true;
418
+ if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {
419
+ curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
420
+ }
421
+ }
422
+ }
423
+ if (isCompatible) {
424
+ curToNodeChild = toNextSibling;
425
+ curFromNodeChild = fromNextSibling;
426
+ continue outer;
427
+ }
428
+ if (curFromNodeKey) {
429
+ addKeyedRemoval(curFromNodeKey);
430
+ } else {
431
+ removeNode(
432
+ curFromNodeChild,
433
+ fromEl,
434
+ true
435
+ /* skip keyed nodes */
436
+ );
437
+ }
438
+ curFromNodeChild = fromNextSibling;
439
+ }
440
+ if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {
441
+ if (!skipFrom) {
442
+ addChild(fromEl, matchingFromEl);
443
+ }
444
+ morphEl(matchingFromEl, curToNodeChild);
445
+ } else {
446
+ var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);
447
+ if (onBeforeNodeAddedResult !== false) {
448
+ if (onBeforeNodeAddedResult) {
449
+ curToNodeChild = onBeforeNodeAddedResult;
450
+ }
451
+ if (curToNodeChild.actualize) {
452
+ curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);
453
+ }
454
+ addChild(fromEl, curToNodeChild);
455
+ handleNodeAdded(curToNodeChild);
456
+ }
457
+ }
458
+ curToNodeChild = toNextSibling;
459
+ curFromNodeChild = fromNextSibling;
460
+ }
461
+ cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);
462
+ var specialElHandler = specialElHandlers[fromEl.nodeName];
463
+ if (specialElHandler) {
464
+ specialElHandler(fromEl, toEl);
465
+ }
466
+ }
467
+ var morphedNode = fromNode;
468
+ var morphedNodeType = morphedNode.nodeType;
469
+ var toNodeType = toNode.nodeType;
470
+ if (!childrenOnly) {
471
+ if (morphedNodeType === ELEMENT_NODE) {
472
+ if (toNodeType === ELEMENT_NODE) {
473
+ if (!compareNodeNames(fromNode, toNode)) {
474
+ onNodeDiscarded(fromNode);
475
+ morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));
476
+ }
477
+ } else {
478
+ morphedNode = toNode;
479
+ }
480
+ } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) {
481
+ if (toNodeType === morphedNodeType) {
482
+ if (morphedNode.nodeValue !== toNode.nodeValue) {
483
+ morphedNode.nodeValue = toNode.nodeValue;
484
+ }
485
+ return morphedNode;
486
+ } else {
487
+ morphedNode = toNode;
488
+ }
489
+ }
490
+ }
491
+ if (morphedNode === toNode) {
492
+ onNodeDiscarded(fromNode);
493
+ } else {
494
+ if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {
495
+ return;
496
+ }
497
+ morphEl(morphedNode, toNode, childrenOnly);
498
+ if (keyedRemovalList) {
499
+ for (var i = 0, len = keyedRemovalList.length; i < len; i++) {
500
+ var elToRemove = fromNodesLookup[keyedRemovalList[i]];
501
+ if (elToRemove) {
502
+ removeNode(elToRemove, elToRemove.parentNode, false);
503
+ }
504
+ }
505
+ }
506
+ }
507
+ if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
508
+ if (morphedNode.actualize) {
509
+ morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);
510
+ }
511
+ fromNode.parentNode.replaceChild(morphedNode, fromNode);
512
+ }
513
+ return morphedNode;
514
+ };
515
+ }
516
+ var morphdom = morphdomFactory(morphAttrs);
517
+ var morphdom_esm_default = morphdom;
518
+
519
+ // src/client/live-preview-bridge.ts
520
+ var ROOT = document.documentElement.dataset.vulsePreviewRoot ?? "main";
521
+ window.addEventListener("message", async (event) => {
522
+ if (event.origin !== window.location.origin) return;
523
+ if (event.data?.name !== "vulse.preview.updated") return;
524
+ const res = await fetch(window.location.href, {
525
+ cache: "no-store",
526
+ credentials: "include",
527
+ headers: { Accept: "text/html" }
528
+ });
529
+ if (!res.ok) return;
530
+ const html = await res.text();
531
+ const doc2 = new DOMParser().parseFromString(html, "text/html");
532
+ const from = doc2.querySelector(ROOT);
533
+ const to = document.querySelector(ROOT);
534
+ if (from && to) morphdom_esm_default(to, from, { childrenOnly: true });
535
+ });
@@ -0,0 +1,82 @@
1
+ import { betterAuth } from 'better-auth'
2
+ import { drizzleAdapter } from 'better-auth/adapters/drizzle'
3
+ import type { VulseDb } from '../core/db.js'
4
+ import * as schema from '../core/schema.js'
5
+ import { SettingsRepo } from '../core/repos/settings.js'
6
+ import { runAuthUserAfterCreateHooks, runAuthUserBeforeCreateHooks } from './plugins.js'
7
+ import type { AuthUserCreateInput } from '../core/plugins/definition.js'
8
+ import { sendEmail, type EmailEnv } from './email.js'
9
+
10
+ export interface AuthConfig {
11
+ baseURL: string
12
+ secret: string
13
+ /** Override settings row (tests/cron). */
14
+ allowSignUp?: boolean
15
+ env?: Record<string, unknown>
16
+ }
17
+
18
+ function emailDomain(email: string): string | null {
19
+ return email.split('@')[1]?.toLowerCase() ?? null
20
+ }
21
+
22
+ export async function createAuth(db: VulseDb, config: AuthConfig) {
23
+ const settings = new SettingsRepo(db)
24
+ const allowSignUp = config.allowSignUp ?? (await settings.get<boolean>('allowMemberSignUp')) ?? false
25
+ const allowedDomains = (await settings.get<string[]>('allowedSignUpDomains')) ?? []
26
+ const pluginEnv = config.env
27
+
28
+ return betterAuth({
29
+ baseURL: config.baseURL,
30
+ secret: config.secret,
31
+ database: drizzleAdapter(db, { provider: 'sqlite', schema }),
32
+ emailAndPassword: {
33
+ enabled: true,
34
+ autoSignIn: true,
35
+ disableSignUp: !allowSignUp,
36
+ sendResetPassword: async ({ user, url }) => {
37
+ const emailEnv = pluginEnv as EmailEnv | undefined
38
+ void sendEmail(emailEnv ?? {}, {
39
+ to: user.email,
40
+ subject: 'Reset your password',
41
+ body: `Click the link to reset your password:\n\n${url}\n\nIf you did not request this, you can ignore this email.`,
42
+ })
43
+ },
44
+ },
45
+ user: {
46
+ additionalFields: {
47
+ role: { type: 'string', defaultValue: 'member', input: false },
48
+ displayName: { type: 'string', required: false },
49
+ },
50
+ },
51
+ session: {
52
+ cookieCache: { enabled: true, maxAge: 5 * 60 },
53
+ },
54
+ databaseHooks: {
55
+ user: {
56
+ create: {
57
+ before: async (user) => {
58
+ const email = typeof user.email === 'string' ? user.email : ''
59
+ const domain = emailDomain(email)
60
+ if (allowedDomains.length > 0 && (!domain || !allowedDomains.includes(domain))) {
61
+ throw new Error('Email domain not allowed')
62
+ }
63
+
64
+ const nextUser = await runAuthUserBeforeCreateHooks({
65
+ user: user as AuthUserCreateInput,
66
+ }, pluginEnv)
67
+ if (nextUser === false) return false
68
+ if (nextUser) return { data: nextUser }
69
+ return undefined
70
+ },
71
+ after: async (user) => {
72
+ await runAuthUserAfterCreateHooks({
73
+ user: user as AuthUserCreateInput,
74
+ }, pluginEnv)
75
+ },
76
+ },
77
+ },
78
+ },
79
+ })
80
+ }
81
+
82
+ export type Auth = Awaited<ReturnType<typeof createAuth>>
@@ -0,0 +1,34 @@
1
+ const DEFAULT_VARIANTS = ['thumbnail', 'card', 'hero', 'og'] as const
2
+ export type Variant = typeof DEFAULT_VARIANTS[number]
3
+
4
+ export interface CfImagesConfig {
5
+ accountHash?: string
6
+ token?: string
7
+ }
8
+
9
+ export function isImagesEnabled(cfg: CfImagesConfig): boolean {
10
+ return !!cfg.accountHash
11
+ }
12
+
13
+ export function buildDeliveryUrl(cfg: CfImagesConfig, imageId: string, variant: Variant | string = 'card'): string | null {
14
+ if (!cfg.accountHash) return null
15
+ return `https://imagedelivery.net/${cfg.accountHash}/${imageId}/${variant}`
16
+ }
17
+
18
+ /** Called on first migration: ensures default variants exist via the CF Images API. */
19
+ export async function registerDefaultVariants(cfg: CfImagesConfig): Promise<void> {
20
+ if (!cfg.token || !cfg.accountHash) return
21
+ const variants = [
22
+ { id: 'thumbnail', options: { fit: 'cover', width: 160, height: 160 } },
23
+ { id: 'card', options: { fit: 'cover', width: 800, height: 450 } },
24
+ { id: 'hero', options: { fit: 'scale-down', width: 1600 } },
25
+ { id: 'og', options: { fit: 'cover', width: 1200, height: 630 } },
26
+ ]
27
+ for (const v of variants) {
28
+ await fetch(`https://api.cloudflare.com/client/v4/accounts/${cfg.accountHash}/images/v1/variants`, {
29
+ method: 'POST',
30
+ headers: { authorization: `Bearer ${cfg.token}`, 'content-type': 'application/json' },
31
+ body: JSON.stringify(v),
32
+ }).catch(() => {})
33
+ }
34
+ }
@@ -0,0 +1,37 @@
1
+ import { createDb } from '../core/db.js'
2
+ import { PreviewSessionsRepo } from '../core/repos/preview-sessions.js'
3
+ import { mediaRoutes } from './routes/media.js'
4
+ import { purgeExpiredFormUploadDrafts } from './routes/form-upload.js'
5
+ import { createAuth } from './better-auth.js'
6
+
7
+ export interface CronEnv {
8
+ DB: D1Database
9
+ BUCKET: R2Bucket
10
+ CF_IMAGES_ACCOUNT_HASH?: string
11
+ CF_IMAGES_TOKEN?: string
12
+ BETTER_AUTH_SECRET: string
13
+ }
14
+
15
+ export async function vulseScheduled(env: CronEnv): Promise<void> {
16
+ const db = createDb(env.DB)
17
+ const auth = await createAuth(db, {
18
+ baseURL: 'http://localhost',
19
+ secret: env.BETTER_AUTH_SECRET,
20
+ allowSignUp: false,
21
+ })
22
+ const routes = mediaRoutes(db, auth, {
23
+ bucket: env.BUCKET,
24
+ cfImages: {
25
+ ...(env.CF_IMAGES_ACCOUNT_HASH ? { accountHash: env.CF_IMAGES_ACCOUNT_HASH } : {}),
26
+ ...(env.CF_IMAGES_TOKEN ? { token: env.CF_IMAGES_TOKEN } : {}),
27
+ },
28
+ })
29
+ const mediaResult = await routes.purge()
30
+ console.log(`[vulse-cron] purged ${mediaResult.purged} media row(s)`)
31
+
32
+ const draftResult = await purgeExpiredFormUploadDrafts(db, env.BUCKET)
33
+ console.log(`[vulse-cron] purged ${draftResult.purged} form upload draft(s)`)
34
+
35
+ const previewResult = await new PreviewSessionsRepo(db).purgeExpired(new Date())
36
+ console.log(`[vulse-cron] purged ${previewResult} preview session(s)`)
37
+ }