domma-cms 0.44.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/CLAUDE.md +53 -53
  2. package/README.md +27 -27
  3. package/admin/css/admin.css +1 -1
  4. package/admin/dist/domma/domma-tools.css +3 -3
  5. package/admin/dist/domma/domma-tools.min.js +3 -3
  6. package/admin/index.html +2 -2
  7. package/admin/js/app.js +1 -1
  8. package/admin/js/lib/card-builder.js +2 -2
  9. package/admin/js/lib/crud-tutorial.js +1 -1
  10. package/admin/js/lib/effect-defs.js +1 -1
  11. package/admin/js/lib/effects-builder.js +1 -1
  12. package/admin/js/lib/image-editor.js +1 -1
  13. package/admin/js/lib/markdown-toolbar.js +2 -2
  14. package/admin/js/lib/project-context.js +1 -1
  15. package/admin/js/lib/project-quick-create.js +1 -1
  16. package/admin/js/lib/scribe-composer.js +1 -1
  17. package/admin/js/lib/server-restart.js +1 -1
  18. package/admin/js/lib/shortcode-context-menu.js +2 -2
  19. package/admin/js/lib/simple-editor.js +1 -1
  20. package/admin/js/lib/themes.js +1 -1
  21. package/admin/js/lib/timeline-builder.js +1 -1
  22. package/admin/js/templates/action-editor.html +8 -8
  23. package/admin/js/templates/api-endpoint-editor.html +7 -7
  24. package/admin/js/templates/api-endpoints.html +1 -1
  25. package/admin/js/templates/api-reference.html +1 -1
  26. package/admin/js/templates/block-editor.html +6 -6
  27. package/admin/js/templates/collection-editor.html +1 -1
  28. package/admin/js/templates/component-editor.html +2 -2
  29. package/admin/js/templates/dashboard/cache.html +3 -3
  30. package/admin/js/templates/dashboard/journeys.html +3 -3
  31. package/admin/js/templates/dashboard/kpi-strip.html +3 -3
  32. package/admin/js/templates/dashboard/top-pages.html +1 -1
  33. package/admin/js/templates/dashboard/traffic-chart.html +1 -1
  34. package/admin/js/templates/docs/api-actions.html +1 -1
  35. package/admin/js/templates/docs/api-collections.html +4 -4
  36. package/admin/js/templates/docs/api-pages.html +2 -2
  37. package/admin/js/templates/docs/api-plugins.html +1 -1
  38. package/admin/js/templates/docs/api-settings.html +2 -2
  39. package/admin/js/templates/docs/api-users.html +1 -1
  40. package/admin/js/templates/docs/components-howto.html +4 -4
  41. package/admin/js/templates/docs/components-reference.html +21 -21
  42. package/admin/js/templates/docs/components-rules.html +14 -14
  43. package/admin/js/templates/docs/components-walkthrough.html +13 -13
  44. package/admin/js/templates/docs/tutorial-crud.html +49 -49
  45. package/admin/js/templates/docs/tutorial-forms.html +4 -4
  46. package/admin/js/templates/docs/tutorial-plugin.html +10 -10
  47. package/admin/js/templates/docs/usage-actions.html +6 -6
  48. package/admin/js/templates/docs/usage-cta-shortcode.html +9 -9
  49. package/admin/js/templates/docs/usage-dconfig.html +4 -4
  50. package/admin/js/templates/docs/usage-navigation.html +1 -1
  51. package/admin/js/templates/docs/usage-pages.html +1 -1
  52. package/admin/js/templates/docs/usage-shortcodes.html +24 -24
  53. package/admin/js/templates/docs/usage-users-roles.html +3 -3
  54. package/admin/js/templates/docs/usage-views.html +4 -4
  55. package/admin/js/templates/documentation.html +1 -1
  56. package/admin/js/templates/effects.html +752 -752
  57. package/admin/js/templates/form-editor.html +5 -5
  58. package/admin/js/templates/forms.html +17 -17
  59. package/admin/js/templates/login.html +5 -5
  60. package/admin/js/templates/menu-editor.html +10 -10
  61. package/admin/js/templates/my-profile.html +17 -17
  62. package/admin/js/templates/navigation.html +11 -11
  63. package/admin/js/templates/notifications.html +1 -1
  64. package/admin/js/templates/page-editor.html +4 -4
  65. package/admin/js/templates/pro-docs.html +14 -14
  66. package/admin/js/templates/role-editor.html +70 -70
  67. package/admin/js/templates/roles.html +10 -10
  68. package/admin/js/templates/settings.html +10 -10
  69. package/admin/js/templates/tutorials.html +3 -3
  70. package/admin/js/templates/view-editor.html +15 -15
  71. package/admin/js/views/action-editor.js +1 -1
  72. package/admin/js/views/actions-list.js +1 -1
  73. package/admin/js/views/api-endpoint-editor.js +2 -2
  74. package/admin/js/views/api-endpoints.js +2 -2
  75. package/admin/js/views/api-tokens.js +3 -3
  76. package/admin/js/views/blocks.js +2 -2
  77. package/admin/js/views/collection-editor.js +1 -1
  78. package/admin/js/views/collection-entries.js +1 -1
  79. package/admin/js/views/collections.js +1 -1
  80. package/admin/js/views/component-editor.js +1 -1
  81. package/admin/js/views/components.js +4 -4
  82. package/admin/js/views/dashboard/widgets/cache.js +1 -1
  83. package/admin/js/views/dashboard/widgets/journeys.js +1 -1
  84. package/admin/js/views/dashboard/widgets/kpi-strip.js +1 -1
  85. package/admin/js/views/form-editor.js +7 -7
  86. package/admin/js/views/form-submissions.js +1 -1
  87. package/admin/js/views/forms.js +1 -1
  88. package/admin/js/views/layouts.js +1 -1
  89. package/admin/js/views/login.js +2 -2
  90. package/admin/js/views/menu-editor.js +3 -3
  91. package/admin/js/views/menu-locations.js +1 -1
  92. package/admin/js/views/menus.js +3 -3
  93. package/admin/js/views/navigation.js +8 -8
  94. package/admin/js/views/page-editor.js +40 -40
  95. package/admin/js/views/pages.js +3 -3
  96. package/admin/js/views/plugin-code.js +2 -2
  97. package/admin/js/views/plugins.js +1 -1
  98. package/admin/js/views/project-settings.js +1 -1
  99. package/admin/js/views/projects.js +1 -1
  100. package/admin/js/views/roles.js +1 -1
  101. package/admin/js/views/user-editor.js +1 -1
  102. package/admin/js/views/users.js +3 -3
  103. package/admin/js/views/view-editor.js +1 -1
  104. package/admin/js/views/view-preview.js +1 -1
  105. package/admin/js/views/views-list.js +1 -1
  106. package/bin/cli.js +8 -8
  107. package/bin/lib/config-merge.js +44 -44
  108. package/bin/update.js +16 -16
  109. package/config/plugins.json +1 -1
  110. package/package.json +2 -2
  111. package/plugins/_template/admin/views/index.js +1 -1
  112. package/plugins/_template/config.js +1 -1
  113. package/plugins/_template/plugin.js +1 -1
  114. package/plugins/analytics/admin/templates/analytics.html +3 -3
  115. package/plugins/analytics/admin/views/analytics.js +1 -1
  116. package/plugins/analytics/config.js +1 -1
  117. package/plugins/analytics/plugin.js +4 -4
  118. package/plugins/analytics/plugin.json +1 -1
  119. package/plugins/analytics/public/inject-body.html +2 -2
  120. package/plugins/analytics/public/inject-head.html +1 -1
  121. package/plugins/blog/admin/templates/blog.html +4 -4
  122. package/plugins/blog/admin/views/blog.js +3 -3
  123. package/plugins/blog/admin/views/categories.js +2 -2
  124. package/plugins/blog/admin/views/comments.js +4 -4
  125. package/plugins/blog/admin/views/post-editor.js +1 -1
  126. package/plugins/blog/plugin.js +2 -2
  127. package/plugins/blog/plugin.json +4 -4
  128. package/plugins/contacts/admin/views/contacts.js +8 -8
  129. package/plugins/contacts/plugin.js +4 -4
  130. package/plugins/contacts/plugin.json +1 -1
  131. package/plugins/invoice/admin/templates/editor.html +6 -6
  132. package/plugins/invoice/admin/templates/index.html +4 -4
  133. package/plugins/invoice/admin/views/editor.js +3 -3
  134. package/plugins/invoice/admin/views/index.js +4 -4
  135. package/plugins/invoice/admin/views/issuers.js +1 -1
  136. package/plugins/invoice/admin/views/party-view.js +3 -3
  137. package/plugins/invoice/admin/views/receivers.js +1 -1
  138. package/plugins/invoice/config.js +1 -1
  139. package/plugins/invoice/plugin.js +1 -1
  140. package/plugins/invoice/plugin.json +4 -4
  141. package/plugins/notes/admin/views/notes.js +4 -4
  142. package/plugins/notes/plugin.js +1 -1
  143. package/plugins/notes/plugin.json +1 -1
  144. package/plugins/site-search/admin/templates/site-search.html +3 -3
  145. package/plugins/site-search/admin/views/site-search.js +1 -1
  146. package/plugins/site-search/config.js +1 -1
  147. package/plugins/site-search/plugin.js +4 -4
  148. package/plugins/site-search/plugin.json +1 -1
  149. package/plugins/surveys/admin/templates/results.html +1 -1
  150. package/plugins/surveys/admin/templates/survey-editor.html +4 -4
  151. package/plugins/surveys/admin/views/audience.js +6 -6
  152. package/plugins/surveys/admin/views/results.js +3 -3
  153. package/plugins/surveys/admin/views/survey-editor.js +1 -1
  154. package/plugins/surveys/admin/views/surveys.js +2 -2
  155. package/plugins/surveys/plugin.js +1 -1
  156. package/plugins/surveys/plugin.json +4 -4
  157. package/plugins/theme-switcher/admin/views/theme-switcher.js +1 -1
  158. package/plugins/theme-switcher/plugin.json +3 -3
  159. package/plugins/theme-switcher/public/inject-body.html +28 -28
  160. package/plugins/theme-switcher/public/inject-head.html +1 -1
  161. package/plugins/todo/plugin.js +1 -1
  162. package/public/css/forms.css +1 -1
  163. package/public/js/collection-browser.js +1 -1
  164. package/public/js/collection-context.js +1 -1
  165. package/public/js/form-logic-engine.js +1 -1
  166. package/public/js/forms.js +2 -1
  167. package/public/js/site.js +1 -1
  168. package/scripts/build.js +14 -14
  169. package/scripts/create-plugin.js +2 -2
  170. package/scripts/fresh.js +2 -2
  171. package/scripts/gen-instance-secret.js +1 -1
  172. package/scripts/pro.js +12 -12
  173. package/scripts/reset.js +2 -2
  174. package/scripts/setup.js +15 -15
  175. package/scripts/users.js +5 -5
  176. package/scripts/verify-assets.mjs +6 -6
  177. package/server/config.js +1 -1
  178. package/server/middleware/auth.js +253 -253
  179. package/server/middleware/managerAuth.js +3 -3
  180. package/server/routes/api/actions.js +4 -4
  181. package/server/routes/api/api-endpoints.js +7 -7
  182. package/server/routes/api/api-tokens.js +5 -5
  183. package/server/routes/api/auth.js +309 -309
  184. package/server/routes/api/blocks.js +3 -3
  185. package/server/routes/api/collections.js +18 -18
  186. package/server/routes/api/dashboard.js +5 -5
  187. package/server/routes/api/effects.js +2 -2
  188. package/server/routes/api/endpoints-public.js +5 -5
  189. package/server/routes/api/forms.js +47 -47
  190. package/server/routes/api/menu-locations.js +3 -3
  191. package/server/routes/api/menus.js +7 -7
  192. package/server/routes/api/navigation.js +42 -42
  193. package/server/routes/api/notifications.js +2 -2
  194. package/server/routes/api/pages.js +14 -2
  195. package/server/routes/api/plugin-marketplace.js +3 -3
  196. package/server/routes/api/plugins.js +6 -6
  197. package/server/routes/api/projects.js +9 -9
  198. package/server/routes/api/scaffold.js +7 -7
  199. package/server/routes/api/settings.js +6 -6
  200. package/server/routes/api/sidebar.js +1 -1
  201. package/server/routes/api/users.js +5 -5
  202. package/server/routes/api/versions.js +1 -1
  203. package/server/routes/api/views.js +1 -1
  204. package/server/routes/docs-public.js +3 -3
  205. package/server/routes/public.js +14 -14
  206. package/server/server.js +34 -16
  207. package/server/services/actions.js +19 -19
  208. package/server/services/adapters/FileAdapter.js +2 -2
  209. package/server/services/adapters/MongoAdapter.js +5 -5
  210. package/server/services/apiEndpoints.js +15 -15
  211. package/server/services/apiTokens.js +7 -7
  212. package/server/services/blocks.js +13 -13
  213. package/server/services/cache/drivers/MemoryDriver.js +3 -3
  214. package/server/services/cache/drivers/NoneDriver.js +1 -1
  215. package/server/services/cache/index.js +5 -5
  216. package/server/services/collections.js +14 -14
  217. package/server/services/components.js +9 -9
  218. package/server/services/connectionManager.js +4 -4
  219. package/server/services/content.js +25 -2
  220. package/server/services/docs.js +14 -14
  221. package/server/services/email.js +167 -167
  222. package/server/services/filterEngine.js +6 -6
  223. package/server/services/forms.js +18 -10
  224. package/server/services/health.js +1 -1
  225. package/server/services/hooks.js +7 -7
  226. package/server/services/images.js +4 -4
  227. package/server/services/managerClient.js +1 -1
  228. package/server/services/markdown.js +79 -79
  229. package/server/services/menuRender.js +5 -5
  230. package/server/services/menus-migration.js +3 -3
  231. package/server/services/menus.js +31 -31
  232. package/server/services/permissionRegistry.js +1 -1
  233. package/server/services/pluginFiles.js +5 -5
  234. package/server/services/pluginInstaller.js +17 -17
  235. package/server/services/pluginScaffold.js +1 -1
  236. package/server/services/plugins.js +17 -17
  237. package/server/services/presetCollections.js +2 -2
  238. package/server/services/projects.js +35 -26
  239. package/server/services/recipes/contact-list.json +1 -1
  240. package/server/services/recipes/onboarding.json +8 -8
  241. package/server/services/references.js +8 -8
  242. package/server/services/renderer.js +9 -9
  243. package/server/services/roles.js +9 -9
  244. package/server/services/rowAccess.js +10 -10
  245. package/server/services/scaffolder.js +30 -30
  246. package/server/services/sidebar-migration.js +10 -10
  247. package/server/services/sitemap.js +1 -1
  248. package/server/services/userProfiles.js +199 -199
  249. package/server/services/userRoles.js +7 -7
  250. package/server/services/users.js +302 -302
  251. package/server/services/versions.js +3 -3
  252. package/server/services/viewPipeline.js +6 -6
  253. package/server/services/views.js +11 -11
  254. package/server/templates/page.html +5 -5
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Executes the Views feature's allowed aggregation-stage subset in plain
5
5
  * JavaScript so views work on file-backed collections (no MongoDB needed).
6
- * MongoDB-backed sources keep using native aggregation in views.js — this
6
+ * MongoDB-backed sources keep using native aggregation in views.js - this
7
7
  * module exists so the SAME view definition produces the same results on
8
8
  * either storage adapter. Documents are the raw entry shape ({id, data,
9
9
  * meta}) and field paths are dot-paths ('data.price', 'meta.createdAt').
@@ -14,7 +14,7 @@
14
14
  * that visibly "should" match. (Same trade filterEngine makes.)
15
15
  * - $sort places missing/null values LAST regardless of direction (Mongo
16
16
  * treats missing as lowest).
17
- * - $addFields supports literals and '$path' references only — operator
17
+ * - $addFields supports literals and '$path' references only - operator
18
18
  * expressions throw a clear error rather than mis-evaluating.
19
19
  *
20
20
  * Pure module: no imports from other services. $lookup resolves foreign
@@ -103,7 +103,7 @@ function deletePath(target, path) {
103
103
  if (typeof node === 'object' && node !== null) delete node[parts[parts.length - 1]];
104
104
  }
105
105
 
106
- /** Number('') is 0 — treat empty strings as non-numeric like filterEngine. */
106
+ /** Number('') is 0 - treat empty strings as non-numeric like filterEngine. */
107
107
  function maybeNumber(value) {
108
108
  if (typeof value === 'number') return value;
109
109
  if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))) {
@@ -342,7 +342,7 @@ function evalProject(docs, config) {
342
342
 
343
343
  return docs.map((doc) => {
344
344
  const out = {};
345
- // id carried unless explicitly excluded ({..., id: 0} — mongo's _id exception)
345
+ // id carried unless explicitly excluded ({..., id: 0} - mongo's _id exception)
346
346
  const idExcluded = entries.some(([k, v]) => (k === 'id' || k === '_id') && (v === 0 || v === false));
347
347
  if (!idExcluded && doc.id !== undefined) out.id = doc.id;
348
348
  for (const [path, spec] of inclusions) {
@@ -522,7 +522,7 @@ async function evalLookup(docs, config, resolveCollection, lookupCache) {
522
522
  throw new ViewPipelineError('$lookup requires a collection resolver', '$lookup');
523
523
  }
524
524
 
525
- // Mongo-authored views reference `cms_<slug>` collection names — accept both.
525
+ // Mongo-authored views reference `cms_<slug>` collection names - accept both.
526
526
  const slug = String(from).replace(/^cms_/, '');
527
527
  if (!lookupCache.has(slug)) {
528
528
  lookupCache.set(slug, await resolveCollection(slug));
@@ -548,7 +548,7 @@ async function evalLookup(docs, config, resolveCollection, lookupCache) {
548
548
 
549
549
  /**
550
550
  * Execute a pipeline (mongo-form stage objects) over an array of documents.
551
- * Returns the FULL result set — the caller paginates.
551
+ * Returns the FULL result set - the caller paginates.
552
552
  *
553
553
  * @param {object[]} docs
554
554
  * @param {object[]} stages - [{$match: {...}}, {$sort: {...}}, ...]
@@ -10,12 +10,12 @@
10
10
  * - everything else → the built-in JS pipeline evaluator (viewPipeline.js)
11
11
  * over the collection adapter's documents
12
12
  *
13
- * The same view definition therefore works on both storage adapters —
13
+ * The same view definition therefore works on both storage adapters -
14
14
  * field paths are raw-document dot-paths ('data.price', 'meta.createdAt')
15
15
  * in both cases.
16
16
  *
17
17
  * Older installs that stored view configs in the MongoDB `cms__views`
18
- * collection are migrated to files automatically (one-time, read-only —
18
+ * collection are migrated to files automatically (one-time, read-only -
19
19
  * the Mongo collection is never modified).
20
20
  *
21
21
  * Allowed aggregation stage types:
@@ -40,10 +40,10 @@ export const VIEWS_DIR = path.join(ROOT, 'content', 'views');
40
40
  /** Legacy MongoDB collection where pre-0.34 view configs were stored. */
41
41
  const LEGACY_VIEWS_COLLECTION = 'cms__views';
42
42
 
43
- /** Prefix applied to CMS data collections — mirrors MongoAdapter.PREFIX. */
43
+ /** Prefix applied to CMS data collections - mirrors MongoAdapter.PREFIX. */
44
44
  const COLLECTION_PREFIX = 'cms_';
45
45
 
46
- /** Filename/lookup guard — view slugs are slugified, so keep this strict. */
46
+ /** Filename/lookup guard - view slugs are slugified, so keep this strict. */
47
47
  const SLUG_RE = /^[a-z0-9-]+$/;
48
48
 
49
49
  const ALLOWED_STAGES = new Set([
@@ -103,7 +103,7 @@ function buildPipelineStages(stages) {
103
103
  // ---------------------------------------------------------------------------
104
104
 
105
105
  /**
106
- * Ensure the views directory exists. Lazy — engine updates never touch
106
+ * Ensure the views directory exists. Lazy - engine updates never touch
107
107
  * content/, so the dir is created on first write.
108
108
  *
109
109
  * @returns {Promise<void>}
@@ -113,7 +113,7 @@ export async function ensureViewsDir() {
113
113
  }
114
114
 
115
115
  /**
116
- * Read a single view config by slug (no migration hook — internal/raw).
116
+ * Read a single view config by slug (no migration hook - internal/raw).
117
117
  *
118
118
  * @param {string} slug
119
119
  * @returns {Promise<object>}
@@ -164,14 +164,14 @@ export async function migrateFromMongo({ getDbImpl } = {}) {
164
164
  try {
165
165
  const entries = await fs.readdir(VIEWS_DIR);
166
166
  if (entries.some(e => e.endsWith('.json'))) return;
167
- } catch { /* dir absent — proceed */ }
167
+ } catch { /* dir absent - proceed */ }
168
168
 
169
169
  let db;
170
170
  try {
171
171
  const getDb = getDbImpl ?? (await import('./connectionManager.js')).getDb;
172
172
  db = getDb('default');
173
173
  } catch {
174
- return; // file-mode install — nothing to migrate
174
+ return; // file-mode install - nothing to migrate
175
175
  }
176
176
 
177
177
  let docs;
@@ -238,7 +238,7 @@ export async function listViews() {
238
238
  export async function getView(slug) {
239
239
  await ensureMigrated();
240
240
 
241
- // Strict slug guard — this is hit with raw URL params (public route) and
241
+ // Strict slug guard - this is hit with raw URL params (public route) and
242
242
  // the slug becomes a filename.
243
243
  if (typeof slug !== 'string' || !SLUG_RE.test(slug)) return null;
244
244
 
@@ -414,7 +414,7 @@ async function executeMongoView(view, { page, limit, user }) {
414
414
 
415
415
  /**
416
416
  * Execute a view against any other source via the JS pipeline evaluator.
417
- * The full collection and full pipeline output are materialised in memory —
417
+ * The full collection and full pipeline output are materialised in memory -
418
418
  * same trade the FileAdapter already makes for whole collections.
419
419
  */
420
420
  async function executeFileView(view, { page, limit, user }) {
@@ -456,7 +456,7 @@ export async function executeView(slug, {page = 1, limit = 25, user = null} = {}
456
456
  validateStages(view.pipeline?.stages || []);
457
457
 
458
458
  // Dispatch on the SOURCE collection's storage adapter. A mongodb-declared
459
- // schema whose connection is unavailable falls back to the JS evaluator —
459
+ // schema whose connection is unavailable falls back to the JS evaluator -
460
460
  // matching adapterRegistry's own file fallback.
461
461
  let useMongo = false;
462
462
  try {
@@ -18,7 +18,7 @@
18
18
 
19
19
  <!-- Site CSS -->
20
20
  <link rel="stylesheet" href="/public/css/site.css">
21
- <link rel="stylesheet" href="/public/css/forms.css?v=20260817-multi-chooser">
21
+ <link rel="stylesheet" href="/public/css/forms.css?v=20260821-wizard-steps">
22
22
 
23
23
  <!-- Font overrides -->
24
24
  {{fontStyleTag}}
@@ -26,7 +26,7 @@
26
26
  <!-- Plugin head injection -->
27
27
  {{headInject}}
28
28
 
29
- <!-- Late head injection — custom CSS always loads last so it can override everything -->
29
+ <!-- Late head injection - custom CSS always loads last so it can override everything -->
30
30
  {{headInjectLate}}
31
31
  </head>
32
32
  <body class="dm-cloaked dm-theme-{{theme}} {{layoutBodyClass}}" data-layout="{{layout}}">
@@ -116,7 +116,7 @@
116
116
  </script>
117
117
 
118
118
  <!-- Site initialisation -->
119
- <script src="/public/js/site.js?v=20260817-menu-bindings" type="module"></script>
119
+ <script src="/public/js/site.js?v=20260821-wizard-steps" type="module"></script>
120
120
  <script src="/public/js/collection-context.js?v=20260819-export" type="module"></script>
121
121
 
122
122
  <!-- Interactive Collection Browser (used by [collection] shortcodes with
@@ -124,8 +124,8 @@
124
124
  <script src="/public/js/collection-browser.js?v=20260523-browser"></script>
125
125
 
126
126
  <!-- Core Forms (logic engine must load before renderer) -->
127
- <script src="/public/js/form-logic-engine.js?v=20260817-transition-speed"></script>
128
- <script src="/public/js/forms.js?v=20260817-multi-chooser" type="module"></script>
127
+ <script src="/public/js/form-logic-engine.js?v=20260821-wizard-steps"></script>
128
+ <script src="/public/js/forms.js?v=20260821-wizard-steps" type="module"></script>
129
129
 
130
130
  <!-- Core effects runtime -->
131
131
  <script src="/public/js/effects.js"></script>