@momentumcms/server-express 0.5.4 → 0.5.6

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 (4) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/index.cjs +211 -148
  3. package/index.js +89 -26
  4. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,51 @@
1
+ ## 0.5.6 (2026-03-10)
2
+
3
+ This was a version bump only for server-express to align it with other projects, there were no code changes.
4
+
5
+ ## 0.5.5 (2026-03-09)
6
+
7
+ ### 🚀 Features
8
+
9
+ - extract syncDatabaseSchema + fix findById breaking change ([#52](https://github.com/DonaldMurillo/momentum-cms/pull/52))
10
+ - swappable admin pages & layout slots with security hardening ([#51](https://github.com/DonaldMurillo/momentum-cms/pull/51))
11
+ - Versioning & drafts with draft/publish workflow ([#50](https://github.com/DonaldMurillo/momentum-cms/pull/50))
12
+ - NestJS server adapter + E2E stabilization (0.5.2) ([#48](https://github.com/DonaldMurillo/momentum-cms/pull/48))
13
+ - S3, auth plugin wiring, redirects, and E2E tooling ([#41](https://github.com/DonaldMurillo/momentum-cms/pull/41))
14
+ - client-side page view tracking and content performance improvements ([#39](https://github.com/DonaldMurillo/momentum-cms/pull/39))
15
+ - SEO plugin recovery, E2E fixes, and CLI templates ([#37](https://github.com/DonaldMurillo/momentum-cms/pull/37), [#33](https://github.com/DonaldMurillo/momentum-cms/issues/33))
16
+ - blocks showcase with articles, pages, and UI fixes ([#36](https://github.com/DonaldMurillo/momentum-cms/pull/36))
17
+ - add named tabs support with nested data grouping and UI improvements ([#30](https://github.com/DonaldMurillo/momentum-cms/pull/30))
18
+ - implement soft deletes with full stack support ([#22](https://github.com/DonaldMurillo/momentum-cms/pull/22))
19
+ - implement globals (singleton collections) with full stack support ([#20](https://github.com/DonaldMurillo/momentum-cms/pull/20))
20
+ - visual block editor & auth-gated admin mode ([#18](https://github.com/DonaldMurillo/momentum-cms/pull/18))
21
+ - Add document versioning and drafts system ([#5](https://github.com/DonaldMurillo/momentum-cms/pull/5))
22
+ - **ui:** enhance command palette with autofocus, filtering, and keyboard nav ([#2](https://github.com/DonaldMurillo/momentum-cms/pull/2))
23
+ - Add seeding feature with idempotent data initialization ([#1](https://github.com/DonaldMurillo/momentum-cms/pull/1))
24
+ - Add role-based access control system ([ebadbbef](https://github.com/DonaldMurillo/momentum-cms/commit/ebadbbef))
25
+ - Add authentication, UI library, and theme system ([0d387205](https://github.com/DonaldMurillo/momentum-cms/commit/0d387205))
26
+ - Add Tailwind design system and fix SQLite reliability ([6dd79b11](https://github.com/DonaldMurillo/momentum-cms/commit/6dd79b11))
27
+ - Implement admin UI with API integration and SSR hydration ([9ed7b2bd](https://github.com/DonaldMurillo/momentum-cms/commit/9ed7b2bd))
28
+ - Initialize Momentum CMS foundation ([f64f5817](https://github.com/DonaldMurillo/momentum-cms/commit/f64f5817))
29
+
30
+ ### 🩹 Fixes
31
+
32
+ - add public access to form-builder npm publish config ([#46](https://github.com/DonaldMurillo/momentum-cms/pull/46))
33
+ - Resolve non-null assertion bugs and CLAUDE.md violations ([#44](https://github.com/DonaldMurillo/momentum-cms/pull/44))
34
+ - add auth guard and MIME validation to PATCH upload route; fix pagination with client-side filtering ([#32](https://github.com/DonaldMurillo/momentum-cms/pull/32))
35
+ - **create-momentum-app:** add shell option to execFileSync for Windows ([#28](https://github.com/DonaldMurillo/momentum-cms/pull/28))
36
+ - correct repository URLs and add GitHub link to CLI ([#26](https://github.com/DonaldMurillo/momentum-cms/pull/26))
37
+ - resolve CUD toast interceptor issues ([#17](https://github.com/DonaldMurillo/momentum-cms/pull/17), [#1](https://github.com/DonaldMurillo/momentum-cms/issues/1), [#2](https://github.com/DonaldMurillo/momentum-cms/issues/2), [#3](https://github.com/DonaldMurillo/momentum-cms/issues/3), [#4](https://github.com/DonaldMurillo/momentum-cms/issues/4))
38
+ - address 7 critical and high-severity security and validation bugs ([#12](https://github.com/DonaldMurillo/momentum-cms/pull/12))
39
+ - address security vulnerabilities from code review ([#9](https://github.com/DonaldMurillo/momentum-cms/pull/9))
40
+ - address security and reliability issues from code review ([#7](https://github.com/DonaldMurillo/momentum-cms/pull/7))
41
+
42
+ ### ❤️ Thank You
43
+
44
+ - Claude Haiku 4.5
45
+ - Claude Opus 4.5
46
+ - Claude Opus 4.6
47
+ - Donald Murillo @DonaldMurillo
48
+
1
49
  ## 0.5.4 (2026-03-07)
2
50
 
3
51
  ### 🚀 Features
package/index.cjs CHANGED
@@ -569,14 +569,14 @@ var init_strip_artifacts = __esm({
569
569
 
570
570
  // libs/email/src/lib/render/render-types.ts
571
571
  function injectEmailData() {
572
- return (0, import_core11.inject)(EMAIL_DATA);
572
+ return (0, import_core12.inject)(EMAIL_DATA);
573
573
  }
574
- var import_core11, EMAIL_DATA;
574
+ var import_core12, EMAIL_DATA;
575
575
  var init_render_types = __esm({
576
576
  "libs/email/src/lib/render/render-types.ts"() {
577
577
  "use strict";
578
- import_core11 = require("@angular/core");
579
- EMAIL_DATA = new import_core11.InjectionToken("EMAIL_DATA");
578
+ import_core12 = require("@angular/core");
579
+ EMAIL_DATA = new import_core12.InjectionToken("EMAIL_DATA");
580
580
  }
581
581
  });
582
582
 
@@ -588,7 +588,7 @@ async function renderEmail(component, data, options) {
588
588
  const shouldInlineCss = options?.inlineCss ?? true;
589
589
  const shouldStripArtifacts = options?.stripArtifacts ?? true;
590
590
  const extraProviders = options?.providers ?? [];
591
- const mirror = (0, import_core12.reflectComponentType)(component);
591
+ const mirror = (0, import_core13.reflectComponentType)(component);
592
592
  if (!mirror) {
593
593
  throw new Error(
594
594
  `Cannot reflect component type: ${component.name}. Ensure it has a @Component decorator.`
@@ -610,12 +610,12 @@ async function renderEmail(component, data, options) {
610
610
  }
611
611
  return html;
612
612
  }
613
- var import_compiler, import_core12, import_platform_server, import_platform_browser;
613
+ var import_compiler, import_core13, import_platform_server, import_platform_browser;
614
614
  var init_render_email = __esm({
615
615
  "libs/email/src/lib/render/render-email.ts"() {
616
616
  "use strict";
617
617
  import_compiler = require("@angular/compiler");
618
- import_core12 = require("@angular/core");
618
+ import_core13 = require("@angular/core");
619
619
  import_platform_server = require("@angular/platform-server");
620
620
  import_platform_browser = require("@angular/platform-browser");
621
621
  init_css_inliner();
@@ -1048,26 +1048,26 @@ var init_default_templates = __esm({
1048
1048
  });
1049
1049
 
1050
1050
  // libs/email/src/lib/components/eml-body.component.ts
1051
- var import_core13, EmlBody;
1051
+ var import_core14, EmlBody;
1052
1052
  var init_eml_body_component = __esm({
1053
1053
  "libs/email/src/lib/components/eml-body.component.ts"() {
1054
1054
  "use strict";
1055
- import_core13 = require("@angular/core");
1055
+ import_core14 = require("@angular/core");
1056
1056
  EmlBody = class {
1057
1057
  constructor() {
1058
- this.backgroundColor = (0, import_core13.input)("#f4f4f5");
1059
- this.fontFamily = (0, import_core13.input)(
1058
+ this.backgroundColor = (0, import_core14.input)("#f4f4f5");
1059
+ this.fontFamily = (0, import_core14.input)(
1060
1060
  "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
1061
1061
  );
1062
- this.padding = (0, import_core13.input)("40px 20px");
1063
- this.tableStyle = (0, import_core13.computed)(
1062
+ this.padding = (0, import_core14.input)("40px 20px");
1063
+ this.tableStyle = (0, import_core14.computed)(
1064
1064
  () => `background-color: ${this.backgroundColor()}; font-family: ${this.fontFamily()}; line-height: 1.6; margin: 0; padding: 0;`
1065
1065
  );
1066
- this.cellStyle = (0, import_core13.computed)(() => `padding: ${this.padding()};`);
1066
+ this.cellStyle = (0, import_core14.computed)(() => `padding: ${this.padding()};`);
1067
1067
  }
1068
1068
  };
1069
1069
  EmlBody = __decorateClass([
1070
- (0, import_core13.Component)({
1070
+ (0, import_core14.Component)({
1071
1071
  selector: "eml-body",
1072
1072
  template: `
1073
1073
  <table
@@ -1084,33 +1084,33 @@ var init_eml_body_component = __esm({
1084
1084
  </tr>
1085
1085
  </table>
1086
1086
  `,
1087
- changeDetection: import_core13.ChangeDetectionStrategy.OnPush
1087
+ changeDetection: import_core14.ChangeDetectionStrategy.OnPush
1088
1088
  })
1089
1089
  ], EmlBody);
1090
1090
  }
1091
1091
  });
1092
1092
 
1093
1093
  // libs/email/src/lib/components/eml-container.component.ts
1094
- var import_core14, EmlContainer;
1094
+ var import_core15, EmlContainer;
1095
1095
  var init_eml_container_component = __esm({
1096
1096
  "libs/email/src/lib/components/eml-container.component.ts"() {
1097
1097
  "use strict";
1098
- import_core14 = require("@angular/core");
1098
+ import_core15 = require("@angular/core");
1099
1099
  EmlContainer = class {
1100
1100
  constructor() {
1101
- this.maxWidth = (0, import_core14.input)("480px");
1102
- this.backgroundColor = (0, import_core14.input)("#ffffff");
1103
- this.borderRadius = (0, import_core14.input)("8px");
1104
- this.padding = (0, import_core14.input)("40px");
1105
- this.shadow = (0, import_core14.input)("0 1px 3px rgba(0,0,0,0.1)");
1106
- this.tableStyle = (0, import_core14.computed)(
1101
+ this.maxWidth = (0, import_core15.input)("480px");
1102
+ this.backgroundColor = (0, import_core15.input)("#ffffff");
1103
+ this.borderRadius = (0, import_core15.input)("8px");
1104
+ this.padding = (0, import_core15.input)("40px");
1105
+ this.shadow = (0, import_core15.input)("0 1px 3px rgba(0,0,0,0.1)");
1106
+ this.tableStyle = (0, import_core15.computed)(
1107
1107
  () => `max-width: ${this.maxWidth()}; margin: 0 auto; background-color: ${this.backgroundColor()}; border-radius: ${this.borderRadius()}; box-shadow: ${this.shadow()};`
1108
1108
  );
1109
- this.cellStyle = (0, import_core14.computed)(() => `padding: ${this.padding()};`);
1109
+ this.cellStyle = (0, import_core15.computed)(() => `padding: ${this.padding()};`);
1110
1110
  }
1111
1111
  };
1112
1112
  EmlContainer = __decorateClass([
1113
- (0, import_core14.Component)({
1113
+ (0, import_core15.Component)({
1114
1114
  selector: "eml-container",
1115
1115
  template: `
1116
1116
  <table
@@ -1127,26 +1127,26 @@ var init_eml_container_component = __esm({
1127
1127
  </tr>
1128
1128
  </table>
1129
1129
  `,
1130
- changeDetection: import_core14.ChangeDetectionStrategy.OnPush
1130
+ changeDetection: import_core15.ChangeDetectionStrategy.OnPush
1131
1131
  })
1132
1132
  ], EmlContainer);
1133
1133
  }
1134
1134
  });
1135
1135
 
1136
1136
  // libs/email/src/lib/components/eml-section.component.ts
1137
- var import_core15, EmlSection;
1137
+ var import_core16, EmlSection;
1138
1138
  var init_eml_section_component = __esm({
1139
1139
  "libs/email/src/lib/components/eml-section.component.ts"() {
1140
1140
  "use strict";
1141
- import_core15 = require("@angular/core");
1141
+ import_core16 = require("@angular/core");
1142
1142
  EmlSection = class {
1143
1143
  constructor() {
1144
- this.padding = (0, import_core15.input)("0");
1145
- this.cellStyle = (0, import_core15.computed)(() => `padding: ${this.padding()};`);
1144
+ this.padding = (0, import_core16.input)("0");
1145
+ this.cellStyle = (0, import_core16.computed)(() => `padding: ${this.padding()};`);
1146
1146
  }
1147
1147
  };
1148
1148
  EmlSection = __decorateClass([
1149
- (0, import_core15.Component)({
1149
+ (0, import_core16.Component)({
1150
1150
  selector: "eml-section",
1151
1151
  template: `
1152
1152
  <table role="presentation" width="100%" cellspacing="0" cellpadding="0">
@@ -1157,22 +1157,22 @@ var init_eml_section_component = __esm({
1157
1157
  </tr>
1158
1158
  </table>
1159
1159
  `,
1160
- changeDetection: import_core15.ChangeDetectionStrategy.OnPush
1160
+ changeDetection: import_core16.ChangeDetectionStrategy.OnPush
1161
1161
  })
1162
1162
  ], EmlSection);
1163
1163
  }
1164
1164
  });
1165
1165
 
1166
1166
  // libs/email/src/lib/components/eml-row.component.ts
1167
- var import_core16, EmlRow;
1167
+ var import_core17, EmlRow;
1168
1168
  var init_eml_row_component = __esm({
1169
1169
  "libs/email/src/lib/components/eml-row.component.ts"() {
1170
1170
  "use strict";
1171
- import_core16 = require("@angular/core");
1171
+ import_core17 = require("@angular/core");
1172
1172
  EmlRow = class {
1173
1173
  };
1174
1174
  EmlRow = __decorateClass([
1175
- (0, import_core16.Component)({
1175
+ (0, import_core17.Component)({
1176
1176
  selector: "eml-row",
1177
1177
  template: `
1178
1178
  <table role="presentation" width="100%" cellspacing="0" cellpadding="0">
@@ -1181,130 +1181,130 @@ var init_eml_row_component = __esm({
1181
1181
  </tr>
1182
1182
  </table>
1183
1183
  `,
1184
- changeDetection: import_core16.ChangeDetectionStrategy.OnPush
1184
+ changeDetection: import_core17.ChangeDetectionStrategy.OnPush
1185
1185
  })
1186
1186
  ], EmlRow);
1187
1187
  }
1188
1188
  });
1189
1189
 
1190
1190
  // libs/email/src/lib/components/eml-column.component.ts
1191
- var import_core17, EmlColumn;
1191
+ var import_core18, EmlColumn;
1192
1192
  var init_eml_column_component = __esm({
1193
1193
  "libs/email/src/lib/components/eml-column.component.ts"() {
1194
1194
  "use strict";
1195
- import_core17 = require("@angular/core");
1195
+ import_core18 = require("@angular/core");
1196
1196
  EmlColumn = class {
1197
1197
  constructor() {
1198
- this.width = (0, import_core17.input)(void 0);
1199
- this.padding = (0, import_core17.input)("0");
1200
- this.verticalAlign = (0, import_core17.input)("top");
1201
- this.cellStyle = (0, import_core17.computed)(
1198
+ this.width = (0, import_core18.input)(void 0);
1199
+ this.padding = (0, import_core18.input)("0");
1200
+ this.verticalAlign = (0, import_core18.input)("top");
1201
+ this.cellStyle = (0, import_core18.computed)(
1202
1202
  () => `padding: ${this.padding()}; vertical-align: ${this.verticalAlign()};`
1203
1203
  );
1204
1204
  }
1205
1205
  };
1206
1206
  EmlColumn = __decorateClass([
1207
- (0, import_core17.Component)({
1207
+ (0, import_core18.Component)({
1208
1208
  selector: "eml-column",
1209
1209
  template: `
1210
1210
  <td [attr.style]="cellStyle()" [attr.width]="width()" valign="top">
1211
1211
  <ng-content />
1212
1212
  </td>
1213
1213
  `,
1214
- changeDetection: import_core17.ChangeDetectionStrategy.OnPush
1214
+ changeDetection: import_core18.ChangeDetectionStrategy.OnPush
1215
1215
  })
1216
1216
  ], EmlColumn);
1217
1217
  }
1218
1218
  });
1219
1219
 
1220
1220
  // libs/email/src/lib/components/eml-text.component.ts
1221
- var import_core18, EmlText;
1221
+ var import_core19, EmlText;
1222
1222
  var init_eml_text_component = __esm({
1223
1223
  "libs/email/src/lib/components/eml-text.component.ts"() {
1224
1224
  "use strict";
1225
- import_core18 = require("@angular/core");
1225
+ import_core19 = require("@angular/core");
1226
1226
  EmlText = class {
1227
1227
  constructor() {
1228
- this.color = (0, import_core18.input)("#3f3f46");
1229
- this.fontSize = (0, import_core18.input)("16px");
1230
- this.lineHeight = (0, import_core18.input)("1.6");
1231
- this.margin = (0, import_core18.input)("0 0 16px");
1232
- this.textAlign = (0, import_core18.input)("left");
1233
- this.pStyle = (0, import_core18.computed)(
1228
+ this.color = (0, import_core19.input)("#3f3f46");
1229
+ this.fontSize = (0, import_core19.input)("16px");
1230
+ this.lineHeight = (0, import_core19.input)("1.6");
1231
+ this.margin = (0, import_core19.input)("0 0 16px");
1232
+ this.textAlign = (0, import_core19.input)("left");
1233
+ this.pStyle = (0, import_core19.computed)(
1234
1234
  () => `margin: ${this.margin()}; color: ${this.color()}; font-size: ${this.fontSize()}; line-height: ${this.lineHeight()}; text-align: ${this.textAlign()};`
1235
1235
  );
1236
1236
  }
1237
1237
  };
1238
1238
  EmlText = __decorateClass([
1239
- (0, import_core18.Component)({
1239
+ (0, import_core19.Component)({
1240
1240
  selector: "eml-text",
1241
1241
  template: `
1242
1242
  <p [attr.style]="pStyle()">
1243
1243
  <ng-content />
1244
1244
  </p>
1245
1245
  `,
1246
- changeDetection: import_core18.ChangeDetectionStrategy.OnPush
1246
+ changeDetection: import_core19.ChangeDetectionStrategy.OnPush
1247
1247
  })
1248
1248
  ], EmlText);
1249
1249
  }
1250
1250
  });
1251
1251
 
1252
1252
  // libs/email/src/lib/components/eml-heading.component.ts
1253
- var import_core19, EmlHeading;
1253
+ var import_core20, EmlHeading;
1254
1254
  var init_eml_heading_component = __esm({
1255
1255
  "libs/email/src/lib/components/eml-heading.component.ts"() {
1256
1256
  "use strict";
1257
- import_core19 = require("@angular/core");
1257
+ import_core20 = require("@angular/core");
1258
1258
  EmlHeading = class {
1259
1259
  constructor() {
1260
- this.level = (0, import_core19.input)(1);
1261
- this.color = (0, import_core19.input)("#18181b");
1262
- this.margin = (0, import_core19.input)("0 0 24px");
1263
- this.textAlign = (0, import_core19.input)("left");
1260
+ this.level = (0, import_core20.input)(1);
1261
+ this.color = (0, import_core20.input)("#18181b");
1262
+ this.margin = (0, import_core20.input)("0 0 24px");
1263
+ this.textAlign = (0, import_core20.input)("left");
1264
1264
  this.fontSizeMap = {
1265
1265
  1: "24px",
1266
1266
  2: "20px",
1267
1267
  3: "16px"
1268
1268
  };
1269
- this.headingStyle = (0, import_core19.computed)(
1269
+ this.headingStyle = (0, import_core20.computed)(
1270
1270
  () => `margin: ${this.margin()}; font-size: ${this.fontSizeMap[this.level()] ?? "24px"}; font-weight: 600; color: ${this.color()}; text-align: ${this.textAlign()};`
1271
1271
  );
1272
1272
  }
1273
1273
  };
1274
1274
  EmlHeading = __decorateClass([
1275
- (0, import_core19.Component)({
1275
+ (0, import_core20.Component)({
1276
1276
  selector: "eml-heading",
1277
1277
  template: `<div [attr.style]="headingStyle()" [attr.role]="'heading'" [attr.aria-level]="level()">
1278
1278
  <ng-content />
1279
1279
  </div>`,
1280
- changeDetection: import_core19.ChangeDetectionStrategy.OnPush
1280
+ changeDetection: import_core20.ChangeDetectionStrategy.OnPush
1281
1281
  })
1282
1282
  ], EmlHeading);
1283
1283
  }
1284
1284
  });
1285
1285
 
1286
1286
  // libs/email/src/lib/components/eml-button.component.ts
1287
- var import_core20, EmlButton;
1287
+ var import_core21, EmlButton;
1288
1288
  var init_eml_button_component = __esm({
1289
1289
  "libs/email/src/lib/components/eml-button.component.ts"() {
1290
1290
  "use strict";
1291
- import_core20 = require("@angular/core");
1291
+ import_core21 = require("@angular/core");
1292
1292
  EmlButton = class {
1293
1293
  constructor() {
1294
- this.href = (0, import_core20.input)("");
1295
- this.backgroundColor = (0, import_core20.input)("#18181b");
1296
- this.color = (0, import_core20.input)("#ffffff");
1297
- this.borderRadius = (0, import_core20.input)("6px");
1298
- this.padding = (0, import_core20.input)("12px 24px");
1299
- this.textAlign = (0, import_core20.input)("left");
1300
- this.alignStyle = (0, import_core20.computed)(() => `padding: 0; text-align: ${this.textAlign()};`);
1301
- this.linkStyle = (0, import_core20.computed)(
1294
+ this.href = (0, import_core21.input)("");
1295
+ this.backgroundColor = (0, import_core21.input)("#18181b");
1296
+ this.color = (0, import_core21.input)("#ffffff");
1297
+ this.borderRadius = (0, import_core21.input)("6px");
1298
+ this.padding = (0, import_core21.input)("12px 24px");
1299
+ this.textAlign = (0, import_core21.input)("left");
1300
+ this.alignStyle = (0, import_core21.computed)(() => `padding: 0; text-align: ${this.textAlign()};`);
1301
+ this.linkStyle = (0, import_core21.computed)(
1302
1302
  () => `display: inline-block; padding: ${this.padding()}; background-color: ${this.backgroundColor()}; color: ${this.color()}; text-decoration: none; border-radius: ${this.borderRadius()}; font-weight: 500;`
1303
1303
  );
1304
1304
  }
1305
1305
  };
1306
1306
  EmlButton = __decorateClass([
1307
- (0, import_core20.Component)({
1307
+ (0, import_core21.Component)({
1308
1308
  selector: "eml-button",
1309
1309
  template: `
1310
1310
  <table role="presentation" width="100%" cellspacing="0" cellpadding="0">
@@ -1317,62 +1317,62 @@ var init_eml_button_component = __esm({
1317
1317
  </tr>
1318
1318
  </table>
1319
1319
  `,
1320
- changeDetection: import_core20.ChangeDetectionStrategy.OnPush
1320
+ changeDetection: import_core21.ChangeDetectionStrategy.OnPush
1321
1321
  })
1322
1322
  ], EmlButton);
1323
1323
  }
1324
1324
  });
1325
1325
 
1326
1326
  // libs/email/src/lib/components/eml-link.component.ts
1327
- var import_core21, EmlLink;
1327
+ var import_core22, EmlLink;
1328
1328
  var init_eml_link_component = __esm({
1329
1329
  "libs/email/src/lib/components/eml-link.component.ts"() {
1330
1330
  "use strict";
1331
- import_core21 = require("@angular/core");
1331
+ import_core22 = require("@angular/core");
1332
1332
  EmlLink = class {
1333
1333
  constructor() {
1334
- this.href = (0, import_core21.input)("");
1335
- this.color = (0, import_core21.input)("#18181b");
1336
- this.textDecoration = (0, import_core21.input)("underline");
1337
- this.linkStyle = (0, import_core21.computed)(
1334
+ this.href = (0, import_core22.input)("");
1335
+ this.color = (0, import_core22.input)("#18181b");
1336
+ this.textDecoration = (0, import_core22.input)("underline");
1337
+ this.linkStyle = (0, import_core22.computed)(
1338
1338
  () => `color: ${this.color()}; text-decoration: ${this.textDecoration()};`
1339
1339
  );
1340
1340
  }
1341
1341
  };
1342
1342
  EmlLink = __decorateClass([
1343
- (0, import_core21.Component)({
1343
+ (0, import_core22.Component)({
1344
1344
  selector: "eml-link",
1345
1345
  template: `
1346
1346
  <a [attr.href]="href()" [attr.style]="linkStyle()" target="_blank">
1347
1347
  <ng-content />
1348
1348
  </a>
1349
1349
  `,
1350
- changeDetection: import_core21.ChangeDetectionStrategy.OnPush
1350
+ changeDetection: import_core22.ChangeDetectionStrategy.OnPush
1351
1351
  })
1352
1352
  ], EmlLink);
1353
1353
  }
1354
1354
  });
1355
1355
 
1356
1356
  // libs/email/src/lib/components/eml-image.component.ts
1357
- var import_core22, EmlImage;
1357
+ var import_core23, EmlImage;
1358
1358
  var init_eml_image_component = __esm({
1359
1359
  "libs/email/src/lib/components/eml-image.component.ts"() {
1360
1360
  "use strict";
1361
- import_core22 = require("@angular/core");
1361
+ import_core23 = require("@angular/core");
1362
1362
  EmlImage = class {
1363
1363
  constructor() {
1364
- this.src = (0, import_core22.input)("");
1365
- this.alt = (0, import_core22.input)("");
1366
- this.width = (0, import_core22.input)(void 0);
1367
- this.height = (0, import_core22.input)(void 0);
1368
- this.borderRadius = (0, import_core22.input)("0");
1369
- this.imgStyle = (0, import_core22.computed)(
1364
+ this.src = (0, import_core23.input)("");
1365
+ this.alt = (0, import_core23.input)("");
1366
+ this.width = (0, import_core23.input)(void 0);
1367
+ this.height = (0, import_core23.input)(void 0);
1368
+ this.borderRadius = (0, import_core23.input)("0");
1369
+ this.imgStyle = (0, import_core23.computed)(
1370
1370
  () => `display: block; max-width: 100%; border: 0; outline: none; border-radius: ${this.borderRadius()};`
1371
1371
  );
1372
1372
  }
1373
1373
  };
1374
1374
  EmlImage = __decorateClass([
1375
- (0, import_core22.Component)({
1375
+ (0, import_core23.Component)({
1376
1376
  selector: "eml-image",
1377
1377
  template: `
1378
1378
  <img
@@ -1383,104 +1383,104 @@ var init_eml_image_component = __esm({
1383
1383
  [attr.style]="imgStyle()"
1384
1384
  />
1385
1385
  `,
1386
- changeDetection: import_core22.ChangeDetectionStrategy.OnPush
1386
+ changeDetection: import_core23.ChangeDetectionStrategy.OnPush
1387
1387
  })
1388
1388
  ], EmlImage);
1389
1389
  }
1390
1390
  });
1391
1391
 
1392
1392
  // libs/email/src/lib/components/eml-divider.component.ts
1393
- var import_core23, EmlDivider;
1393
+ var import_core24, EmlDivider;
1394
1394
  var init_eml_divider_component = __esm({
1395
1395
  "libs/email/src/lib/components/eml-divider.component.ts"() {
1396
1396
  "use strict";
1397
- import_core23 = require("@angular/core");
1397
+ import_core24 = require("@angular/core");
1398
1398
  EmlDivider = class {
1399
1399
  constructor() {
1400
- this.color = (0, import_core23.input)("#e4e4e7");
1401
- this.margin = (0, import_core23.input)("24px 0");
1402
- this.hrStyle = (0, import_core23.computed)(
1400
+ this.color = (0, import_core24.input)("#e4e4e7");
1401
+ this.margin = (0, import_core24.input)("24px 0");
1402
+ this.hrStyle = (0, import_core24.computed)(
1403
1403
  () => `border: none; border-top: 1px solid ${this.color()}; margin: ${this.margin()};`
1404
1404
  );
1405
1405
  }
1406
1406
  };
1407
1407
  EmlDivider = __decorateClass([
1408
- (0, import_core23.Component)({
1408
+ (0, import_core24.Component)({
1409
1409
  selector: "eml-divider",
1410
1410
  template: `<hr [attr.style]="hrStyle()" />`,
1411
- changeDetection: import_core23.ChangeDetectionStrategy.OnPush
1411
+ changeDetection: import_core24.ChangeDetectionStrategy.OnPush
1412
1412
  })
1413
1413
  ], EmlDivider);
1414
1414
  }
1415
1415
  });
1416
1416
 
1417
1417
  // libs/email/src/lib/components/eml-preview.component.ts
1418
- var import_core24, EmlPreview;
1418
+ var import_core25, EmlPreview;
1419
1419
  var init_eml_preview_component = __esm({
1420
1420
  "libs/email/src/lib/components/eml-preview.component.ts"() {
1421
1421
  "use strict";
1422
- import_core24 = require("@angular/core");
1422
+ import_core25 = require("@angular/core");
1423
1423
  EmlPreview = class {
1424
1424
  };
1425
1425
  EmlPreview = __decorateClass([
1426
- (0, import_core24.Component)({
1426
+ (0, import_core25.Component)({
1427
1427
  selector: "eml-preview",
1428
1428
  template: `
1429
1429
  <div style="display: none; max-height: 0; overflow: hidden; mso-hide: all;">
1430
1430
  <ng-content />
1431
1431
  </div>
1432
1432
  `,
1433
- changeDetection: import_core24.ChangeDetectionStrategy.OnPush
1433
+ changeDetection: import_core25.ChangeDetectionStrategy.OnPush
1434
1434
  })
1435
1435
  ], EmlPreview);
1436
1436
  }
1437
1437
  });
1438
1438
 
1439
1439
  // libs/email/src/lib/components/eml-spacer.component.ts
1440
- var import_core25, EmlSpacer;
1440
+ var import_core26, EmlSpacer;
1441
1441
  var init_eml_spacer_component = __esm({
1442
1442
  "libs/email/src/lib/components/eml-spacer.component.ts"() {
1443
1443
  "use strict";
1444
- import_core25 = require("@angular/core");
1444
+ import_core26 = require("@angular/core");
1445
1445
  EmlSpacer = class {
1446
1446
  constructor() {
1447
- this.height = (0, import_core25.input)("24px");
1448
- this.spacerStyle = (0, import_core25.computed)(
1447
+ this.height = (0, import_core26.input)("24px");
1448
+ this.spacerStyle = (0, import_core26.computed)(
1449
1449
  () => `height: ${this.height()}; line-height: ${this.height()}; font-size: 1px;`
1450
1450
  );
1451
1451
  }
1452
1452
  };
1453
1453
  EmlSpacer = __decorateClass([
1454
- (0, import_core25.Component)({
1454
+ (0, import_core26.Component)({
1455
1455
  selector: "eml-spacer",
1456
1456
  template: `<div [attr.style]="spacerStyle()"></div>`,
1457
- changeDetection: import_core25.ChangeDetectionStrategy.OnPush
1457
+ changeDetection: import_core26.ChangeDetectionStrategy.OnPush
1458
1458
  })
1459
1459
  ], EmlSpacer);
1460
1460
  }
1461
1461
  });
1462
1462
 
1463
1463
  // libs/email/src/lib/components/eml-footer.component.ts
1464
- var import_core26, EmlFooter;
1464
+ var import_core27, EmlFooter;
1465
1465
  var init_eml_footer_component = __esm({
1466
1466
  "libs/email/src/lib/components/eml-footer.component.ts"() {
1467
1467
  "use strict";
1468
- import_core26 = require("@angular/core");
1468
+ import_core27 = require("@angular/core");
1469
1469
  EmlFooter = class {
1470
1470
  constructor() {
1471
- this.maxWidth = (0, import_core26.input)("480px");
1472
- this.color = (0, import_core26.input)("#71717a");
1473
- this.fontSize = (0, import_core26.input)("12px");
1474
- this.textAlign = (0, import_core26.input)("center");
1475
- this.padding = (0, import_core26.input)("20px 0 0");
1476
- this.tableStyle = (0, import_core26.computed)(() => `max-width: ${this.maxWidth()}; margin: 0 auto;`);
1477
- this.cellStyle = (0, import_core26.computed)(
1471
+ this.maxWidth = (0, import_core27.input)("480px");
1472
+ this.color = (0, import_core27.input)("#71717a");
1473
+ this.fontSize = (0, import_core27.input)("12px");
1474
+ this.textAlign = (0, import_core27.input)("center");
1475
+ this.padding = (0, import_core27.input)("20px 0 0");
1476
+ this.tableStyle = (0, import_core27.computed)(() => `max-width: ${this.maxWidth()}; margin: 0 auto;`);
1477
+ this.cellStyle = (0, import_core27.computed)(
1478
1478
  () => `text-align: ${this.textAlign()}; color: ${this.color()}; font-size: ${this.fontSize()}; padding: ${this.padding()};`
1479
1479
  );
1480
1480
  }
1481
1481
  };
1482
1482
  EmlFooter = __decorateClass([
1483
- (0, import_core26.Component)({
1483
+ (0, import_core27.Component)({
1484
1484
  selector: "eml-footer",
1485
1485
  template: `
1486
1486
  <table
@@ -1497,7 +1497,7 @@ var init_eml_footer_component = __esm({
1497
1497
  </tr>
1498
1498
  </table>
1499
1499
  `,
1500
- changeDetection: import_core26.ChangeDetectionStrategy.OnPush
1500
+ changeDetection: import_core27.ChangeDetectionStrategy.OnPush
1501
1501
  })
1502
1502
  ], EmlFooter);
1503
1503
  }
@@ -2246,8 +2246,27 @@ var MediaCollection = defineCollection({
2246
2246
  }
2247
2247
  });
2248
2248
 
2249
+ // libs/core/src/lib/migrations.ts
2250
+ function resolveMigrationMode(mode) {
2251
+ if (mode === "push" || mode === "migrate")
2252
+ return mode;
2253
+ const env = globalThis["process"]?.env?.["NODE_ENV"];
2254
+ if (env === "production")
2255
+ return "migrate";
2256
+ return "push";
2257
+ }
2258
+
2249
2259
  // libs/core/src/lib/config.ts
2250
2260
  var MIN_PASSWORD_LENGTH = 8;
2261
+ function shouldSyncSchema(config) {
2262
+ const explicit = config.db.syncSchema ?? "auto";
2263
+ if (typeof explicit === "boolean")
2264
+ return explicit;
2265
+ if (!config.migrations)
2266
+ return true;
2267
+ const mode = resolveMigrationMode(config.migrations.mode);
2268
+ return mode !== "migrate";
2269
+ }
2251
2270
 
2252
2271
  // libs/core/src/lib/seeding/seeding.types.ts
2253
2272
  var SEED_TRACKING_COLLECTION_SLUG = "_momentum_seeds";
@@ -2697,6 +2716,12 @@ var DocumentNotFoundError = class extends Error {
2697
2716
  this.name = "DocumentNotFoundError";
2698
2717
  }
2699
2718
  };
2719
+ var DraftNotVisibleError = class extends Error {
2720
+ constructor(collection, id) {
2721
+ super(`Draft "${id}" in collection "${collection}" is not visible to the current user`);
2722
+ this.name = "DraftNotVisibleError";
2723
+ }
2724
+ };
2700
2725
  var AccessDeniedError = class extends Error {
2701
2726
  constructor(operation, collection) {
2702
2727
  super(`Access denied for ${operation} on collection "${collection}"`);
@@ -3114,13 +3139,31 @@ function stripTransientKeys(data) {
3114
3139
  }
3115
3140
  return result;
3116
3141
  }
3142
+ var COMPARISON_OPS = ["gt", "gte", "lt", "lte"];
3117
3143
  function flattenWhereClause(where) {
3118
3144
  if (!where)
3119
3145
  return {};
3120
3146
  const result = {};
3121
3147
  for (const [field, condition] of Object.entries(where)) {
3122
- if (typeof condition === "object" && condition !== null && "equals" in condition) {
3123
- result[field] = condition["equals"];
3148
+ if (typeof condition !== "object" || condition === null) {
3149
+ result[field] = condition;
3150
+ continue;
3151
+ }
3152
+ const condObj = condition;
3153
+ if ("equals" in condObj) {
3154
+ result[field] = condObj["equals"];
3155
+ continue;
3156
+ }
3157
+ const ops = {};
3158
+ let hasComparisonOp = false;
3159
+ for (const op of COMPARISON_OPS) {
3160
+ if (op in condObj) {
3161
+ ops[`$${op}`] = condObj[op];
3162
+ hasComparisonOp = true;
3163
+ }
3164
+ }
3165
+ if (hasComparisonOp) {
3166
+ result[field] = ops;
3124
3167
  } else {
3125
3168
  result[field] = condition;
3126
3169
  }
@@ -3215,24 +3258,24 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
3215
3258
  await this.runBeforeReadHooks();
3216
3259
  const doc = await this.adapter.findById(this.slug, id);
3217
3260
  if (!doc) {
3218
- return null;
3261
+ throw new DocumentNotFoundError(this.slug, id);
3219
3262
  }
3220
3263
  const softDeleteField = getSoftDeleteField(this.collectionConfig);
3221
3264
  if (softDeleteField && !options?.withDeleted && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- T is compatible with Record<string, unknown>
3222
3265
  doc[softDeleteField]) {
3223
- return null;
3266
+ throw new DocumentNotFoundError(this.slug, id);
3224
3267
  }
3225
3268
  if (hasVersionDrafts(this.collectionConfig) && !this.context.overrideAccess) {
3226
3269
  const canSeeDrafts = await this.canReadDrafts();
3227
3270
  if (!canSeeDrafts) {
3228
3271
  const record = doc;
3229
3272
  if (record["_status"] !== "published") {
3230
- return null;
3273
+ throw new DraftNotVisibleError(this.slug, id);
3231
3274
  }
3232
3275
  }
3233
3276
  }
3234
3277
  if (!this.matchesDefaultWhereConstraints(doc)) {
3235
- return null;
3278
+ throw new DocumentNotFoundError(this.slug, id);
3236
3279
  }
3237
3280
  const [processed] = await this.processAfterReadHooks([doc]);
3238
3281
  const MAX_RELATIONSHIP_DEPTH = 10;
@@ -4103,9 +4146,6 @@ function createMomentumHandlers(config) {
4103
4146
  const depth = typeof request.query?.["depth"] === "number" ? request.query["depth"] : void 0;
4104
4147
  const withDeleted = request.query?.["withDeleted"] === true;
4105
4148
  const doc = await api.collection(request.collectionSlug).findById(request.id, { depth, withDeleted });
4106
- if (!doc) {
4107
- return { error: "Document not found", status: 404 };
4108
- }
4109
4149
  return { doc };
4110
4150
  } catch (error) {
4111
4151
  return handleError(error);
@@ -4222,6 +4262,9 @@ function handleError(error) {
4222
4262
  if (error instanceof DocumentNotFoundError) {
4223
4263
  return { error: error.message, status: 404 };
4224
4264
  }
4265
+ if (error instanceof DraftNotVisibleError) {
4266
+ return { doc: null };
4267
+ }
4225
4268
  if (error instanceof AccessDeniedError) {
4226
4269
  return { error: error.message, status: 403 };
4227
4270
  }
@@ -4674,7 +4717,10 @@ async function sendWebhook(webhook, payload, attempt = 0) {
4674
4717
  webhookLogger.warn(`Blocked request to disallowed URL: ${webhook.url}`);
4675
4718
  return;
4676
4719
  }
4677
- const body = JSON.stringify(payload);
4720
+ const body = JSON.stringify(
4721
+ payload,
4722
+ (_key, value) => typeof value === "bigint" ? Number(value) : value
4723
+ );
4678
4724
  const maxRetries = webhook.retries ?? 0;
4679
4725
  const headers = {
4680
4726
  "Content-Type": "application/json",
@@ -5182,7 +5228,14 @@ function buildGraphQLSchema(collections) {
5182
5228
  const api = getMomentumAPI();
5183
5229
  const ctx = buildAPIContext(context);
5184
5230
  const contextApi = Object.keys(ctx).length > 0 ? api.setContext(ctx) : api;
5185
- return contextApi.collection(col.slug).findById(args.id);
5231
+ try {
5232
+ return await contextApi.collection(col.slug).findById(args.id);
5233
+ } catch (err) {
5234
+ if (err instanceof Error && err.name === "DocumentNotFoundError") {
5235
+ return null;
5236
+ }
5237
+ throw err;
5238
+ }
5186
5239
  }
5187
5240
  };
5188
5241
  queryFields[plural.charAt(0).toLowerCase() + plural.slice(1)] = {
@@ -6473,6 +6526,22 @@ var RateLimiter = class _RateLimiter {
6473
6526
  }
6474
6527
  };
6475
6528
 
6529
+ // libs/server-core/src/lib/schema-sync.ts
6530
+ async function syncDatabaseSchema(config, log) {
6531
+ if (shouldSyncSchema(config)) {
6532
+ if (config.db.adapter.initialize) {
6533
+ log.info("Initializing database schema...");
6534
+ await config.db.adapter.initialize(config.collections);
6535
+ }
6536
+ if (config.db.adapter.initializeGlobals && config.globals && config.globals.length > 0) {
6537
+ log.info(`Initializing globals table for ${config.globals.length} global(s)...`);
6538
+ await config.db.adapter.initializeGlobals(config.globals);
6539
+ }
6540
+ } else {
6541
+ log.info("Skipping automatic schema sync (migration mode). Run migrations separately.");
6542
+ }
6543
+ }
6544
+
6476
6545
  // libs/server-core/src/lib/shared-server-utils.ts
6477
6546
  function sanitizeErrorMessage(error, fallback) {
6478
6547
  if (!(error instanceof Error))
@@ -7188,12 +7257,7 @@ function momentumApiMiddleware(config) {
7188
7257
  } else {
7189
7258
  const api = getMomentumAPI();
7190
7259
  const contextApi = user ? api.setContext({ user }) : api;
7191
- const dbDoc = await contextApi.collection(slug2).findById(id);
7192
- if (!dbDoc) {
7193
- res.status(404).json({ error: "Document not found" });
7194
- return;
7195
- }
7196
- doc = dbDoc;
7260
+ doc = await contextApi.collection(slug2).findById(id);
7197
7261
  }
7198
7262
  const emailField = getEmailBuilderFieldName(collectionConfig);
7199
7263
  const html = emailField ? await renderEmailPreviewHTML(doc, emailField) : renderPreviewHTML({ doc, collection: collectionConfig });
@@ -7386,7 +7450,13 @@ function momentumApiMiddleware(config) {
7386
7450
  return { docs: r.docs, totalDocs: r.totalDocs };
7387
7451
  },
7388
7452
  findById: async (slug2, id) => {
7389
- return await ctxApi.collection(slug2).findById(id);
7453
+ try {
7454
+ return await ctxApi.collection(slug2).findById(id);
7455
+ } catch (err) {
7456
+ if (err instanceof Error && err.name === "DocumentNotFoundError")
7457
+ return null;
7458
+ throw err;
7459
+ }
7390
7460
  },
7391
7461
  count: (slug2) => ctxApi.collection(slug2).count(),
7392
7462
  create: async (slug2, data) => {
@@ -8784,14 +8854,7 @@ function initializeMomentum(config, options = {}) {
8784
8854
  }
8785
8855
  }
8786
8856
  setPluginMiddleware(pluginMiddleware2);
8787
- if (config.db.adapter.initialize) {
8788
- log.info("Initializing database schema...");
8789
- await config.db.adapter.initialize(config.collections);
8790
- }
8791
- if (config.db.adapter.initializeGlobals && config.globals && config.globals.length > 0) {
8792
- log.info(`Initializing globals table for ${config.globals.length} global(s)...`);
8793
- await config.db.adapter.initializeGlobals(config.globals);
8794
- }
8857
+ await syncDatabaseSchema(config, log);
8795
8858
  log.info("Initializing API...");
8796
8859
  const api = initializeMomentumAPI(config);
8797
8860
  const runOnStart = config.seeding?.options?.runOnStart ?? "development";
package/index.js CHANGED
@@ -2202,8 +2202,27 @@ var MediaCollection = defineCollection({
2202
2202
  }
2203
2203
  });
2204
2204
 
2205
+ // libs/core/src/lib/migrations.ts
2206
+ function resolveMigrationMode(mode) {
2207
+ if (mode === "push" || mode === "migrate")
2208
+ return mode;
2209
+ const env = globalThis["process"]?.env?.["NODE_ENV"];
2210
+ if (env === "production")
2211
+ return "migrate";
2212
+ return "push";
2213
+ }
2214
+
2205
2215
  // libs/core/src/lib/config.ts
2206
2216
  var MIN_PASSWORD_LENGTH = 8;
2217
+ function shouldSyncSchema(config) {
2218
+ const explicit = config.db.syncSchema ?? "auto";
2219
+ if (typeof explicit === "boolean")
2220
+ return explicit;
2221
+ if (!config.migrations)
2222
+ return true;
2223
+ const mode = resolveMigrationMode(config.migrations.mode);
2224
+ return mode !== "migrate";
2225
+ }
2207
2226
 
2208
2227
  // libs/core/src/lib/seeding/seeding.types.ts
2209
2228
  var SEED_TRACKING_COLLECTION_SLUG = "_momentum_seeds";
@@ -2653,6 +2672,12 @@ var DocumentNotFoundError = class extends Error {
2653
2672
  this.name = "DocumentNotFoundError";
2654
2673
  }
2655
2674
  };
2675
+ var DraftNotVisibleError = class extends Error {
2676
+ constructor(collection, id) {
2677
+ super(`Draft "${id}" in collection "${collection}" is not visible to the current user`);
2678
+ this.name = "DraftNotVisibleError";
2679
+ }
2680
+ };
2656
2681
  var AccessDeniedError = class extends Error {
2657
2682
  constructor(operation, collection) {
2658
2683
  super(`Access denied for ${operation} on collection "${collection}"`);
@@ -3070,13 +3095,31 @@ function stripTransientKeys(data) {
3070
3095
  }
3071
3096
  return result;
3072
3097
  }
3098
+ var COMPARISON_OPS = ["gt", "gte", "lt", "lte"];
3073
3099
  function flattenWhereClause(where) {
3074
3100
  if (!where)
3075
3101
  return {};
3076
3102
  const result = {};
3077
3103
  for (const [field, condition] of Object.entries(where)) {
3078
- if (typeof condition === "object" && condition !== null && "equals" in condition) {
3079
- result[field] = condition["equals"];
3104
+ if (typeof condition !== "object" || condition === null) {
3105
+ result[field] = condition;
3106
+ continue;
3107
+ }
3108
+ const condObj = condition;
3109
+ if ("equals" in condObj) {
3110
+ result[field] = condObj["equals"];
3111
+ continue;
3112
+ }
3113
+ const ops = {};
3114
+ let hasComparisonOp = false;
3115
+ for (const op of COMPARISON_OPS) {
3116
+ if (op in condObj) {
3117
+ ops[`$${op}`] = condObj[op];
3118
+ hasComparisonOp = true;
3119
+ }
3120
+ }
3121
+ if (hasComparisonOp) {
3122
+ result[field] = ops;
3080
3123
  } else {
3081
3124
  result[field] = condition;
3082
3125
  }
@@ -3171,24 +3214,24 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
3171
3214
  await this.runBeforeReadHooks();
3172
3215
  const doc = await this.adapter.findById(this.slug, id);
3173
3216
  if (!doc) {
3174
- return null;
3217
+ throw new DocumentNotFoundError(this.slug, id);
3175
3218
  }
3176
3219
  const softDeleteField = getSoftDeleteField(this.collectionConfig);
3177
3220
  if (softDeleteField && !options?.withDeleted && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- T is compatible with Record<string, unknown>
3178
3221
  doc[softDeleteField]) {
3179
- return null;
3222
+ throw new DocumentNotFoundError(this.slug, id);
3180
3223
  }
3181
3224
  if (hasVersionDrafts(this.collectionConfig) && !this.context.overrideAccess) {
3182
3225
  const canSeeDrafts = await this.canReadDrafts();
3183
3226
  if (!canSeeDrafts) {
3184
3227
  const record = doc;
3185
3228
  if (record["_status"] !== "published") {
3186
- return null;
3229
+ throw new DraftNotVisibleError(this.slug, id);
3187
3230
  }
3188
3231
  }
3189
3232
  }
3190
3233
  if (!this.matchesDefaultWhereConstraints(doc)) {
3191
- return null;
3234
+ throw new DocumentNotFoundError(this.slug, id);
3192
3235
  }
3193
3236
  const [processed] = await this.processAfterReadHooks([doc]);
3194
3237
  const MAX_RELATIONSHIP_DEPTH = 10;
@@ -4059,9 +4102,6 @@ function createMomentumHandlers(config) {
4059
4102
  const depth = typeof request.query?.["depth"] === "number" ? request.query["depth"] : void 0;
4060
4103
  const withDeleted = request.query?.["withDeleted"] === true;
4061
4104
  const doc = await api.collection(request.collectionSlug).findById(request.id, { depth, withDeleted });
4062
- if (!doc) {
4063
- return { error: "Document not found", status: 404 };
4064
- }
4065
4105
  return { doc };
4066
4106
  } catch (error) {
4067
4107
  return handleError(error);
@@ -4178,6 +4218,9 @@ function handleError(error) {
4178
4218
  if (error instanceof DocumentNotFoundError) {
4179
4219
  return { error: error.message, status: 404 };
4180
4220
  }
4221
+ if (error instanceof DraftNotVisibleError) {
4222
+ return { doc: null };
4223
+ }
4181
4224
  if (error instanceof AccessDeniedError) {
4182
4225
  return { error: error.message, status: 403 };
4183
4226
  }
@@ -4630,7 +4673,10 @@ async function sendWebhook(webhook, payload, attempt = 0) {
4630
4673
  webhookLogger.warn(`Blocked request to disallowed URL: ${webhook.url}`);
4631
4674
  return;
4632
4675
  }
4633
- const body = JSON.stringify(payload);
4676
+ const body = JSON.stringify(
4677
+ payload,
4678
+ (_key, value) => typeof value === "bigint" ? Number(value) : value
4679
+ );
4634
4680
  const maxRetries = webhook.retries ?? 0;
4635
4681
  const headers = {
4636
4682
  "Content-Type": "application/json",
@@ -5151,7 +5197,14 @@ function buildGraphQLSchema(collections) {
5151
5197
  const api = getMomentumAPI();
5152
5198
  const ctx = buildAPIContext(context);
5153
5199
  const contextApi = Object.keys(ctx).length > 0 ? api.setContext(ctx) : api;
5154
- return contextApi.collection(col.slug).findById(args.id);
5200
+ try {
5201
+ return await contextApi.collection(col.slug).findById(args.id);
5202
+ } catch (err) {
5203
+ if (err instanceof Error && err.name === "DocumentNotFoundError") {
5204
+ return null;
5205
+ }
5206
+ throw err;
5207
+ }
5155
5208
  }
5156
5209
  };
5157
5210
  queryFields[plural.charAt(0).toLowerCase() + plural.slice(1)] = {
@@ -6442,6 +6495,22 @@ var RateLimiter = class _RateLimiter {
6442
6495
  }
6443
6496
  };
6444
6497
 
6498
+ // libs/server-core/src/lib/schema-sync.ts
6499
+ async function syncDatabaseSchema(config, log) {
6500
+ if (shouldSyncSchema(config)) {
6501
+ if (config.db.adapter.initialize) {
6502
+ log.info("Initializing database schema...");
6503
+ await config.db.adapter.initialize(config.collections);
6504
+ }
6505
+ if (config.db.adapter.initializeGlobals && config.globals && config.globals.length > 0) {
6506
+ log.info(`Initializing globals table for ${config.globals.length} global(s)...`);
6507
+ await config.db.adapter.initializeGlobals(config.globals);
6508
+ }
6509
+ } else {
6510
+ log.info("Skipping automatic schema sync (migration mode). Run migrations separately.");
6511
+ }
6512
+ }
6513
+
6445
6514
  // libs/server-core/src/lib/shared-server-utils.ts
6446
6515
  function sanitizeErrorMessage(error, fallback) {
6447
6516
  if (!(error instanceof Error))
@@ -7157,12 +7226,7 @@ function momentumApiMiddleware(config) {
7157
7226
  } else {
7158
7227
  const api = getMomentumAPI();
7159
7228
  const contextApi = user ? api.setContext({ user }) : api;
7160
- const dbDoc = await contextApi.collection(slug2).findById(id);
7161
- if (!dbDoc) {
7162
- res.status(404).json({ error: "Document not found" });
7163
- return;
7164
- }
7165
- doc = dbDoc;
7229
+ doc = await contextApi.collection(slug2).findById(id);
7166
7230
  }
7167
7231
  const emailField = getEmailBuilderFieldName(collectionConfig);
7168
7232
  const html = emailField ? await renderEmailPreviewHTML(doc, emailField) : renderPreviewHTML({ doc, collection: collectionConfig });
@@ -7355,7 +7419,13 @@ function momentumApiMiddleware(config) {
7355
7419
  return { docs: r.docs, totalDocs: r.totalDocs };
7356
7420
  },
7357
7421
  findById: async (slug2, id) => {
7358
- return await ctxApi.collection(slug2).findById(id);
7422
+ try {
7423
+ return await ctxApi.collection(slug2).findById(id);
7424
+ } catch (err) {
7425
+ if (err instanceof Error && err.name === "DocumentNotFoundError")
7426
+ return null;
7427
+ throw err;
7428
+ }
7359
7429
  },
7360
7430
  count: (slug2) => ctxApi.collection(slug2).count(),
7361
7431
  create: async (slug2, data) => {
@@ -8753,14 +8823,7 @@ function initializeMomentum(config, options = {}) {
8753
8823
  }
8754
8824
  }
8755
8825
  setPluginMiddleware(pluginMiddleware2);
8756
- if (config.db.adapter.initialize) {
8757
- log.info("Initializing database schema...");
8758
- await config.db.adapter.initialize(config.collections);
8759
- }
8760
- if (config.db.adapter.initializeGlobals && config.globals && config.globals.length > 0) {
8761
- log.info(`Initializing globals table for ${config.globals.length} global(s)...`);
8762
- await config.db.adapter.initializeGlobals(config.globals);
8763
- }
8826
+ await syncDatabaseSchema(config, log);
8764
8827
  log.info("Initializing API...");
8765
8828
  const api = initializeMomentumAPI(config);
8766
8829
  const runOnStart = config.seeding?.options?.runOnStart ?? "development";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momentumcms/server-express",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Express adapter for Momentum CMS with Angular SSR support",
5
5
  "license": "MIT",
6
6
  "author": "Momentum CMS Contributors",