meno-core 1.0.48 → 1.0.50

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 (89) hide show
  1. package/build-astro.ts +6 -2
  2. package/dist/build-static.js +7 -7
  3. package/dist/chunks/{chunk-D5E3OKSL.js → chunk-56EUSC6D.js} +5 -5
  4. package/dist/chunks/{chunk-3FHJUHAS.js → chunk-7NIC4I3V.js} +300 -43
  5. package/dist/chunks/chunk-7NIC4I3V.js.map +7 -0
  6. package/dist/chunks/{chunk-B2RTLDXY.js → chunk-AZQYF6KE.js} +132 -1
  7. package/dist/chunks/chunk-AZQYF6KE.js.map +7 -0
  8. package/dist/chunks/{chunk-TPQ7APVQ.js → chunk-CVLFID6V.js} +473 -73
  9. package/dist/chunks/chunk-CVLFID6V.js.map +7 -0
  10. package/dist/chunks/{chunk-NP76N4HQ.js → chunk-EDQSMAMP.js} +13 -2
  11. package/dist/chunks/{chunk-NP76N4HQ.js.map → chunk-EDQSMAMP.js.map} +2 -2
  12. package/dist/chunks/{chunk-RQSTH2BS.js → chunk-H4JSCDNW.js} +2 -2
  13. package/dist/chunks/{chunk-EK4KESLU.js → chunk-J23ZX5AP.js} +8 -2
  14. package/dist/chunks/{chunk-EK4KESLU.js.map → chunk-J23ZX5AP.js.map} +2 -2
  15. package/dist/chunks/{chunk-UUA5LEWF.js → chunk-LPVETICS.js} +156 -8
  16. package/dist/chunks/chunk-LPVETICS.js.map +7 -0
  17. package/dist/chunks/{chunk-BJRKEPMP.js → chunk-PQ2HRXDR.js} +5 -2
  18. package/dist/chunks/chunk-PQ2HRXDR.js.map +7 -0
  19. package/dist/chunks/{chunk-NKUV77SR.js → chunk-YWJJD5D6.js} +133 -37
  20. package/dist/chunks/chunk-YWJJD5D6.js.map +7 -0
  21. package/dist/chunks/{configService-IGJEC3MC.js → configService-VOY2MY2K.js} +3 -3
  22. package/dist/entries/server-router.js +9 -9
  23. package/dist/entries/server-router.js.map +2 -2
  24. package/dist/lib/client/index.js +92 -32
  25. package/dist/lib/client/index.js.map +3 -3
  26. package/dist/lib/server/index.js +14 -12
  27. package/dist/lib/server/index.js.map +2 -2
  28. package/dist/lib/shared/index.js +46 -10
  29. package/dist/lib/shared/index.js.map +3 -3
  30. package/entries/server-router.tsx +6 -2
  31. package/lib/client/core/ComponentBuilder.test.ts +34 -0
  32. package/lib/client/core/ComponentBuilder.ts +33 -4
  33. package/lib/client/core/builders/embedBuilder.ts +28 -7
  34. package/lib/client/core/builders/linkNodeBuilder.ts +28 -7
  35. package/lib/client/core/builders/localeListBuilder.ts +30 -11
  36. package/lib/client/styles/StyleInjector.ts +3 -2
  37. package/lib/client/templateEngine.ts +24 -0
  38. package/lib/client/theme.ts +4 -4
  39. package/lib/server/cssGenerator.test.ts +64 -1
  40. package/lib/server/cssGenerator.ts +48 -9
  41. package/lib/server/fileWatcher.test.ts +134 -0
  42. package/lib/server/fileWatcher.ts +100 -32
  43. package/lib/server/jsonLoader.ts +1 -0
  44. package/lib/server/providers/fileSystemCMSProvider.test.ts +163 -0
  45. package/lib/server/providers/fileSystemCMSProvider.ts +240 -19
  46. package/lib/server/routes/index.ts +1 -1
  47. package/lib/server/routes/pages.ts +23 -1
  48. package/lib/server/services/cmsService.test.ts +246 -0
  49. package/lib/server/services/cmsService.ts +122 -5
  50. package/lib/server/services/configService.ts +6 -0
  51. package/lib/server/services/fileWatcherService.ts +17 -0
  52. package/lib/server/ssr/attributeBuilder.ts +41 -0
  53. package/lib/server/ssr/htmlGenerator.test.ts +113 -0
  54. package/lib/server/ssr/htmlGenerator.ts +62 -7
  55. package/lib/server/ssr/liveReloadIntegration.test.ts +209 -0
  56. package/lib/server/ssr/ssrRenderer.test.ts +564 -0
  57. package/lib/server/ssr/ssrRenderer.ts +228 -49
  58. package/lib/server/webflow/buildWebflow.ts +1 -1
  59. package/lib/server/websocketManager.test.ts +61 -6
  60. package/lib/server/websocketManager.ts +25 -1
  61. package/lib/shared/cssGeneration.test.ts +267 -1
  62. package/lib/shared/cssGeneration.ts +240 -18
  63. package/lib/shared/cssProperties.test.ts +275 -1
  64. package/lib/shared/cssProperties.ts +223 -7
  65. package/lib/shared/interfaces/contentProvider.ts +39 -6
  66. package/lib/shared/pathSecurity.ts +16 -0
  67. package/lib/shared/responsiveScaling.test.ts +143 -0
  68. package/lib/shared/responsiveScaling.ts +253 -2
  69. package/lib/shared/themeDefaults.test.ts +3 -3
  70. package/lib/shared/themeDefaults.ts +3 -3
  71. package/lib/shared/types/api.ts +10 -1
  72. package/lib/shared/types/cms.ts +46 -12
  73. package/lib/shared/types/index.ts +1 -0
  74. package/lib/shared/utilityClassConfig.ts +3 -0
  75. package/lib/shared/utilityClassMapper.test.ts +123 -0
  76. package/lib/shared/utilityClassMapper.ts +179 -8
  77. package/lib/shared/validation/schemas.test.ts +93 -0
  78. package/lib/shared/validation/schemas.ts +71 -16
  79. package/lib/shared/validation/validators.ts +26 -1
  80. package/package.json +1 -1
  81. package/dist/chunks/chunk-3FHJUHAS.js.map +0 -7
  82. package/dist/chunks/chunk-B2RTLDXY.js.map +0 -7
  83. package/dist/chunks/chunk-BJRKEPMP.js.map +0 -7
  84. package/dist/chunks/chunk-NKUV77SR.js.map +0 -7
  85. package/dist/chunks/chunk-TPQ7APVQ.js.map +0 -7
  86. package/dist/chunks/chunk-UUA5LEWF.js.map +0 -7
  87. /package/dist/chunks/{chunk-D5E3OKSL.js.map → chunk-56EUSC6D.js.map} +0 -0
  88. /package/dist/chunks/{chunk-RQSTH2BS.js.map → chunk-H4JSCDNW.js.map} +0 -0
  89. /package/dist/chunks/{configService-IGJEC3MC.js.map → configService-VOY2MY2K.js.map} +0 -0
@@ -15,10 +15,10 @@ import {
15
15
  parseJSON,
16
16
  resolveSlugToPageId,
17
17
  variableService
18
- } from "./chunk-TPQ7APVQ.js";
18
+ } from "./chunk-CVLFID6V.js";
19
19
  import {
20
20
  configService
21
- } from "./chunk-BJRKEPMP.js";
21
+ } from "./chunk-PQ2HRXDR.js";
22
22
  import {
23
23
  bundleFile,
24
24
  createRuntimeServer,
@@ -38,16 +38,16 @@ import {
38
38
  } from "./chunk-WQFG7PAH.js";
39
39
  import {
40
40
  extractStringValue
41
- } from "./chunk-RQSTH2BS.js";
41
+ } from "./chunk-H4JSCDNW.js";
42
42
  import {
43
43
  isPathWithinRoot
44
- } from "./chunk-EK4KESLU.js";
44
+ } from "./chunk-J23ZX5AP.js";
45
45
  import {
46
46
  addItemUrls
47
- } from "./chunk-3FHJUHAS.js";
47
+ } from "./chunk-7NIC4I3V.js";
48
48
  import {
49
49
  parseLocaleFromPath
50
- } from "./chunk-B2RTLDXY.js";
50
+ } from "./chunk-AZQYF6KE.js";
51
51
  import {
52
52
  API_ROUTES,
53
53
  HMR_ROUTE,
@@ -217,6 +217,27 @@ var WebSocketManager = class {
217
217
  collection
218
218
  });
219
219
  }
220
+ /**
221
+ * Broadcast CMS collections-list update notification.
222
+ * Emitted when a template file is added, removed, or its schema changes —
223
+ * tells connected clients to re-fetch the collections list.
224
+ */
225
+ broadcastCollectionsUpdate() {
226
+ this.broadcast({
227
+ type: "hmr:cms-collections-update"
228
+ });
229
+ }
230
+ /**
231
+ * Broadcast project.config.json update notification.
232
+ * Emitted when project.config.json changes (e.g. an AI tool adds a new
233
+ * locale) — tells connected clients to re-fetch config-derived state
234
+ * such as the i18n locale list.
235
+ */
236
+ broadcastConfigUpdate() {
237
+ this.broadcast({
238
+ type: "hmr:config-update"
239
+ });
240
+ }
220
241
  /**
221
242
  * Get number of connected clients
222
243
  */
@@ -1313,6 +1334,27 @@ import { existsSync as existsSync4 } from "fs";
1313
1334
 
1314
1335
  // lib/server/fileWatcher.ts
1315
1336
  import { watch, existsSync as existsSync3 } from "fs";
1337
+ import { basename, dirname } from "path";
1338
+ function attachWhenDirExists(dirPath, attach, setWatcher) {
1339
+ if (existsSync3(dirPath)) {
1340
+ setWatcher(attach());
1341
+ return;
1342
+ }
1343
+ const parentDir = dirname(dirPath);
1344
+ const targetName = basename(dirPath);
1345
+ if (!existsSync3(parentDir)) {
1346
+ return;
1347
+ }
1348
+ let parentWatcher = null;
1349
+ parentWatcher = watch(parentDir, (_event, filename) => {
1350
+ if (filename !== targetName) return;
1351
+ if (!existsSync3(dirPath)) return;
1352
+ parentWatcher?.close();
1353
+ parentWatcher = null;
1354
+ setWatcher(attach());
1355
+ });
1356
+ setWatcher(parentWatcher);
1357
+ }
1316
1358
  var FileWatcher = class {
1317
1359
  constructor(callbacks) {
1318
1360
  this.callbacks = callbacks;
@@ -1326,6 +1368,7 @@ var FileWatcher = class {
1326
1368
  cmsWatcher = null;
1327
1369
  imagesWatcher = null;
1328
1370
  librariesWatcher = null;
1371
+ projectConfigWatcher = null;
1329
1372
  /**
1330
1373
  * Start watching components directory
1331
1374
  * Watches both .json and .js files to detect component definition and JavaScript changes
@@ -1369,23 +1412,29 @@ var FileWatcher = class {
1369
1412
  );
1370
1413
  }
1371
1414
  /**
1372
- * Start watching root templates directory for CMS template changes
1415
+ * Start watching root templates directory for CMS template changes.
1416
+ * Falls back to a deferred-attach watcher on the project root when
1417
+ * `templates/` doesn't exist yet (blank projects, projects that have never
1418
+ * had a CMS collection).
1373
1419
  */
1374
1420
  watchTemplates(dirPath = projectPaths.templates()) {
1375
- if (!existsSync3(dirPath)) {
1376
- return;
1377
- }
1378
- this.templatesWatcher = watch(
1421
+ attachWhenDirExists(
1379
1422
  dirPath,
1380
- { recursive: true },
1381
- async (event, filename) => {
1382
- if (filename && filename.endsWith(".json")) {
1383
- const pageName = `templates/${filename.replace(".json", "")}`;
1384
- const pagePath = mapPageNameToPath(pageName);
1385
- if (this.callbacks.onPageChange) {
1386
- await this.callbacks.onPageChange(pagePath);
1423
+ () => watch(
1424
+ dirPath,
1425
+ { recursive: true },
1426
+ async (event, filename) => {
1427
+ if (filename && filename.endsWith(".json")) {
1428
+ const pageName = `templates/${filename.replace(".json", "")}`;
1429
+ const pagePath = mapPageNameToPath(pageName);
1430
+ if (this.callbacks.onPageChange) {
1431
+ await this.callbacks.onPageChange(pagePath);
1432
+ }
1387
1433
  }
1388
1434
  }
1435
+ ),
1436
+ (w) => {
1437
+ this.templatesWatcher = w;
1389
1438
  }
1390
1439
  );
1391
1440
  }
@@ -1438,23 +1487,27 @@ var FileWatcher = class {
1438
1487
  );
1439
1488
  }
1440
1489
  /**
1441
- * Start watching CMS directory
1442
- * Watches for changes in CMS content files (cms/{collection}/*.json)
1490
+ * Start watching CMS directory.
1491
+ * Watches for changes in CMS content files (cms/{collection}/*.json).
1492
+ * Falls back to a deferred-attach watcher when `cms/` doesn't exist yet.
1443
1493
  */
1444
1494
  watchCMS(dirPath = projectPaths.cms()) {
1445
- if (!existsSync3(dirPath)) {
1446
- return;
1447
- }
1448
- this.cmsWatcher = watch(
1495
+ attachWhenDirExists(
1449
1496
  dirPath,
1450
- { recursive: true },
1451
- async (event, filename) => {
1452
- if (filename && filename.endsWith(".json")) {
1453
- const collection = filename.split("/")[0];
1454
- if (this.callbacks.onCMSChange) {
1455
- await this.callbacks.onCMSChange(collection);
1497
+ () => watch(
1498
+ dirPath,
1499
+ { recursive: true },
1500
+ async (event, filename) => {
1501
+ if (filename && filename.endsWith(".json")) {
1502
+ const collection = filename.split("/")[0];
1503
+ if (this.callbacks.onCMSChange) {
1504
+ await this.callbacks.onCMSChange(collection);
1505
+ }
1456
1506
  }
1457
1507
  }
1508
+ ),
1509
+ (w) => {
1510
+ this.cmsWatcher = w;
1458
1511
  }
1459
1512
  );
1460
1513
  }
@@ -1475,6 +1528,24 @@ var FileWatcher = class {
1475
1528
  }
1476
1529
  );
1477
1530
  }
1531
+ /**
1532
+ * Start watching project.config.json for changes.
1533
+ * Picks up edits to i18n locales, breakpoints, libraries, icons, etc. so the
1534
+ * studio reflects external writes (e.g. an AI tool adding a new locale) without
1535
+ * a dev-server restart.
1536
+ */
1537
+ watchProjectConfig() {
1538
+ const dirPath = getProjectRoot();
1539
+ this.projectConfigWatcher = watch(
1540
+ dirPath,
1541
+ { recursive: false },
1542
+ async (_event, filename) => {
1543
+ if (filename === "project.config.json" && this.callbacks.onProjectConfigChange) {
1544
+ await this.callbacks.onProjectConfigChange();
1545
+ }
1546
+ }
1547
+ );
1548
+ }
1478
1549
  /**
1479
1550
  * Start watching libraries directory for CSS/JS changes
1480
1551
  */
@@ -1507,6 +1578,7 @@ var FileWatcher = class {
1507
1578
  this.watchCMS();
1508
1579
  this.watchImages();
1509
1580
  this.watchLibraries();
1581
+ this.watchProjectConfig();
1510
1582
  }
1511
1583
  /**
1512
1584
  * Stop watching all directories
@@ -1548,6 +1620,10 @@ var FileWatcher = class {
1548
1620
  this.librariesWatcher.close();
1549
1621
  this.librariesWatcher = null;
1550
1622
  }
1623
+ if (this.projectConfigWatcher) {
1624
+ this.projectConfigWatcher.close();
1625
+ this.projectConfigWatcher = null;
1626
+ }
1551
1627
  }
1552
1628
  /**
1553
1629
  * Check if watchers are active
@@ -1598,9 +1674,11 @@ var FileWatcherService = class {
1598
1674
  clearTimeout(this.refreshSchemasTimer);
1599
1675
  }
1600
1676
  const cmsService = this.cmsService;
1677
+ const wsManager = this.wsManager;
1601
1678
  this.refreshSchemasTimer = setTimeout(async () => {
1602
1679
  this.refreshSchemasTimer = null;
1603
1680
  await cmsService.refreshSchemas();
1681
+ wsManager.broadcastCollectionsUpdate();
1604
1682
  }, 50);
1605
1683
  }
1606
1684
  },
@@ -1617,11 +1695,17 @@ var FileWatcherService = class {
1617
1695
  this.wsManager.broadcastEnumsUpdate();
1618
1696
  },
1619
1697
  onCMSChange: async (collection) => {
1698
+ this.cmsService?.clearItemsCache(collection);
1620
1699
  this.wsManager.broadcastCMSUpdate(collection);
1621
1700
  },
1622
1701
  onImageAdded: this.onImageAdded,
1623
1702
  onLibraryChange: async () => {
1624
1703
  this.wsManager.broadcastLibrariesUpdate();
1704
+ },
1705
+ onProjectConfigChange: async () => {
1706
+ configService.reset();
1707
+ await configService.load();
1708
+ this.wsManager.broadcastConfigUpdate();
1625
1709
  }
1626
1710
  });
1627
1711
  this.fileWatcher.watchAll();
@@ -2633,9 +2717,11 @@ function hashContent2(content) {
2633
2717
  }
2634
2718
 
2635
2719
  // lib/server/routes/pages.ts
2636
- async function handlePageRoute(url, context) {
2720
+ var EDITOR_HEADER = "x-meno-editor";
2721
+ async function handlePageRoute(url, context, req) {
2637
2722
  const { pageService, componentService, cmsService, injectLiveReload, isEditor, serverPort } = context;
2638
2723
  const pagePath = url.pathname;
2724
+ const injectEditorAttrs = req?.headers.get(EDITOR_HEADER) === "1";
2639
2725
  const i18nConfig = await loadI18nConfig();
2640
2726
  const { locale, pathWithoutLocale } = parseLocaleFromPath(pagePath, i18nConfig);
2641
2727
  const slugMappings = pageService.getSlugMappings();
@@ -2643,6 +2729,12 @@ async function handlePageRoute(url, context) {
2643
2729
  if (cmsService) {
2644
2730
  const cmsMatch = await cmsService.matchRoute(pathWithoutLocale, locale);
2645
2731
  if (cmsMatch) {
2732
+ if (injectEditorAttrs && url.searchParams.get("previewDraft") === "1" && cmsMatch.item._filename) {
2733
+ const draft = await cmsService.getDraft(cmsMatch.collection, cmsMatch.item._filename);
2734
+ if (draft) {
2735
+ cmsMatch.item = draft;
2736
+ }
2737
+ }
2646
2738
  const templatePageContent = await loadPageByFilePath(cmsMatch.pagePath);
2647
2739
  if (templatePageContent) {
2648
2740
  const templatesDir = projectPaths.templates();
@@ -2667,6 +2759,7 @@ async function handlePageRoute(url, context) {
2667
2759
  pageLibraries: typedPageData.meta?.libraries,
2668
2760
  pageCustomCode: typedPageData.meta?.customCode,
2669
2761
  injectLiveReload,
2762
+ injectEditorAttrs,
2670
2763
  isEditor,
2671
2764
  serverPort,
2672
2765
  returnSeparateJS: true
@@ -2700,6 +2793,7 @@ async function handlePageRoute(url, context) {
2700
2793
  cmsTemplatePath,
2701
2794
  pageLibraries: typedPageData.meta?.libraries,
2702
2795
  pageCustomCode: typedPageData.meta?.customCode,
2796
+ injectEditorAttrs,
2703
2797
  isEditor
2704
2798
  });
2705
2799
  return new Response(ssrHTML, {
@@ -2760,6 +2854,7 @@ async function handlePageRoute(url, context) {
2760
2854
  pageLibraries: pageData.meta?.libraries,
2761
2855
  pageCustomCode: pageData.meta?.customCode,
2762
2856
  injectLiveReload,
2857
+ injectEditorAttrs,
2763
2858
  isEditor,
2764
2859
  serverPort,
2765
2860
  returnSeparateJS: true
@@ -2791,6 +2886,7 @@ async function handlePageRoute(url, context) {
2791
2886
  cmsService,
2792
2887
  pageLibraries: pageData.meta?.libraries,
2793
2888
  pageCustomCode: pageData.meta?.customCode,
2889
+ injectEditorAttrs,
2794
2890
  isEditor
2795
2891
  });
2796
2892
  return new Response(ssrHTML, {
@@ -2967,7 +3063,7 @@ async function handleRoutes(req, url, server, context) {
2967
3063
  }
2968
3064
  }
2969
3065
  if (url.pathname === "/" || url.pathname.startsWith("/") && !url.pathname.includes(".")) {
2970
- const response2 = await handlePageRoute(url, context);
3066
+ const response2 = await handlePageRoute(url, context, req);
2971
3067
  logResponseTime(startTime, req);
2972
3068
  return response2;
2973
3069
  }
@@ -3096,7 +3192,7 @@ async function createServer(config) {
3096
3192
 
3097
3193
  // lib/server/providers/fileSystemPageProvider.ts
3098
3194
  import { existsSync as existsSync5, readdirSync as readdirSync3, mkdirSync as mkdirSync3, rmdirSync as rmdirSync3 } from "fs";
3099
- import { join as join4, dirname } from "path";
3195
+ import { join as join4, dirname as dirname2 } from "path";
3100
3196
 
3101
3197
  // lib/shared/utils/fileUtils.ts
3102
3198
  var isJSONFile = (name) => name.endsWith(".json");
@@ -3191,7 +3287,7 @@ var FileSystemPageProvider = class {
3191
3287
  async save(path2, content) {
3192
3288
  const { writeFile: writeFile2 } = await import("fs/promises");
3193
3289
  const filePath = this.resolveFilePath(path2);
3194
- const dir = dirname(filePath);
3290
+ const dir = dirname2(filePath);
3195
3291
  if (!existsSync5(dir)) {
3196
3292
  mkdirSync3(dir, { recursive: true });
3197
3293
  }
@@ -3203,7 +3299,7 @@ var FileSystemPageProvider = class {
3203
3299
  const rootDir = this.resolveRootDir(path2);
3204
3300
  if (existsSync5(filePath)) {
3205
3301
  await unlink(filePath);
3206
- let dir = dirname(filePath);
3302
+ let dir = dirname2(filePath);
3207
3303
  while (dir !== rootDir) {
3208
3304
  try {
3209
3305
  const remaining = readdirSync3(dir);
@@ -3215,7 +3311,7 @@ var FileSystemPageProvider = class {
3215
3311
  } catch {
3216
3312
  break;
3217
3313
  }
3218
- dir = dirname(dir);
3314
+ dir = dirname2(dir);
3219
3315
  }
3220
3316
  }
3221
3317
  }
@@ -3254,4 +3350,4 @@ export {
3254
3350
  createServer,
3255
3351
  FileSystemPageProvider
3256
3352
  };
3257
- //# sourceMappingURL=chunk-NKUV77SR.js.map
3353
+ //# sourceMappingURL=chunk-YWJJD5D6.js.map