@momentumcms/server-express 0.5.4 → 0.5.5
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.
- package/CHANGELOG.md +44 -0
- package/index.cjs +211 -148
- package/index.js +89 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
## 0.5.5 (2026-03-09)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- extract syncDatabaseSchema + fix findById breaking change ([#52](https://github.com/DonaldMurillo/momentum-cms/pull/52))
|
|
6
|
+
- swappable admin pages & layout slots with security hardening ([#51](https://github.com/DonaldMurillo/momentum-cms/pull/51))
|
|
7
|
+
- Versioning & drafts with draft/publish workflow ([#50](https://github.com/DonaldMurillo/momentum-cms/pull/50))
|
|
8
|
+
- NestJS server adapter + E2E stabilization (0.5.2) ([#48](https://github.com/DonaldMurillo/momentum-cms/pull/48))
|
|
9
|
+
- S3, auth plugin wiring, redirects, and E2E tooling ([#41](https://github.com/DonaldMurillo/momentum-cms/pull/41))
|
|
10
|
+
- client-side page view tracking and content performance improvements ([#39](https://github.com/DonaldMurillo/momentum-cms/pull/39))
|
|
11
|
+
- 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))
|
|
12
|
+
- blocks showcase with articles, pages, and UI fixes ([#36](https://github.com/DonaldMurillo/momentum-cms/pull/36))
|
|
13
|
+
- add named tabs support with nested data grouping and UI improvements ([#30](https://github.com/DonaldMurillo/momentum-cms/pull/30))
|
|
14
|
+
- implement soft deletes with full stack support ([#22](https://github.com/DonaldMurillo/momentum-cms/pull/22))
|
|
15
|
+
- implement globals (singleton collections) with full stack support ([#20](https://github.com/DonaldMurillo/momentum-cms/pull/20))
|
|
16
|
+
- visual block editor & auth-gated admin mode ([#18](https://github.com/DonaldMurillo/momentum-cms/pull/18))
|
|
17
|
+
- Add document versioning and drafts system ([#5](https://github.com/DonaldMurillo/momentum-cms/pull/5))
|
|
18
|
+
- **ui:** enhance command palette with autofocus, filtering, and keyboard nav ([#2](https://github.com/DonaldMurillo/momentum-cms/pull/2))
|
|
19
|
+
- Add seeding feature with idempotent data initialization ([#1](https://github.com/DonaldMurillo/momentum-cms/pull/1))
|
|
20
|
+
- Add role-based access control system ([ebadbbef](https://github.com/DonaldMurillo/momentum-cms/commit/ebadbbef))
|
|
21
|
+
- Add authentication, UI library, and theme system ([0d387205](https://github.com/DonaldMurillo/momentum-cms/commit/0d387205))
|
|
22
|
+
- Add Tailwind design system and fix SQLite reliability ([6dd79b11](https://github.com/DonaldMurillo/momentum-cms/commit/6dd79b11))
|
|
23
|
+
- Implement admin UI with API integration and SSR hydration ([9ed7b2bd](https://github.com/DonaldMurillo/momentum-cms/commit/9ed7b2bd))
|
|
24
|
+
- Initialize Momentum CMS foundation ([f64f5817](https://github.com/DonaldMurillo/momentum-cms/commit/f64f5817))
|
|
25
|
+
|
|
26
|
+
### 🩹 Fixes
|
|
27
|
+
|
|
28
|
+
- add public access to form-builder npm publish config ([#46](https://github.com/DonaldMurillo/momentum-cms/pull/46))
|
|
29
|
+
- Resolve non-null assertion bugs and CLAUDE.md violations ([#44](https://github.com/DonaldMurillo/momentum-cms/pull/44))
|
|
30
|
+
- 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))
|
|
31
|
+
- **create-momentum-app:** add shell option to execFileSync for Windows ([#28](https://github.com/DonaldMurillo/momentum-cms/pull/28))
|
|
32
|
+
- correct repository URLs and add GitHub link to CLI ([#26](https://github.com/DonaldMurillo/momentum-cms/pull/26))
|
|
33
|
+
- 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))
|
|
34
|
+
- address 7 critical and high-severity security and validation bugs ([#12](https://github.com/DonaldMurillo/momentum-cms/pull/12))
|
|
35
|
+
- address security vulnerabilities from code review ([#9](https://github.com/DonaldMurillo/momentum-cms/pull/9))
|
|
36
|
+
- address security and reliability issues from code review ([#7](https://github.com/DonaldMurillo/momentum-cms/pull/7))
|
|
37
|
+
|
|
38
|
+
### ❤️ Thank You
|
|
39
|
+
|
|
40
|
+
- Claude Haiku 4.5
|
|
41
|
+
- Claude Opus 4.5
|
|
42
|
+
- Claude Opus 4.6
|
|
43
|
+
- Donald Murillo @DonaldMurillo
|
|
44
|
+
|
|
1
45
|
## 0.5.4 (2026-03-07)
|
|
2
46
|
|
|
3
47
|
### 🚀 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,
|
|
572
|
+
return (0, import_core12.inject)(EMAIL_DATA);
|
|
573
573
|
}
|
|
574
|
-
var
|
|
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
|
-
|
|
579
|
-
EMAIL_DATA = new
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1055
|
+
import_core14 = require("@angular/core");
|
|
1056
1056
|
EmlBody = class {
|
|
1057
1057
|
constructor() {
|
|
1058
|
-
this.backgroundColor = (0,
|
|
1059
|
-
this.fontFamily = (0,
|
|
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,
|
|
1063
|
-
this.tableStyle = (0,
|
|
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,
|
|
1066
|
+
this.cellStyle = (0, import_core14.computed)(() => `padding: ${this.padding()};`);
|
|
1067
1067
|
}
|
|
1068
1068
|
};
|
|
1069
1069
|
EmlBody = __decorateClass([
|
|
1070
|
-
(0,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1098
|
+
import_core15 = require("@angular/core");
|
|
1099
1099
|
EmlContainer = class {
|
|
1100
1100
|
constructor() {
|
|
1101
|
-
this.maxWidth = (0,
|
|
1102
|
-
this.backgroundColor = (0,
|
|
1103
|
-
this.borderRadius = (0,
|
|
1104
|
-
this.padding = (0,
|
|
1105
|
-
this.shadow = (0,
|
|
1106
|
-
this.tableStyle = (0,
|
|
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,
|
|
1109
|
+
this.cellStyle = (0, import_core15.computed)(() => `padding: ${this.padding()};`);
|
|
1110
1110
|
}
|
|
1111
1111
|
};
|
|
1112
1112
|
EmlContainer = __decorateClass([
|
|
1113
|
-
(0,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1141
|
+
import_core16 = require("@angular/core");
|
|
1142
1142
|
EmlSection = class {
|
|
1143
1143
|
constructor() {
|
|
1144
|
-
this.padding = (0,
|
|
1145
|
-
this.cellStyle = (0,
|
|
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,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1171
|
+
import_core17 = require("@angular/core");
|
|
1172
1172
|
EmlRow = class {
|
|
1173
1173
|
};
|
|
1174
1174
|
EmlRow = __decorateClass([
|
|
1175
|
-
(0,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1195
|
+
import_core18 = require("@angular/core");
|
|
1196
1196
|
EmlColumn = class {
|
|
1197
1197
|
constructor() {
|
|
1198
|
-
this.width = (0,
|
|
1199
|
-
this.padding = (0,
|
|
1200
|
-
this.verticalAlign = (0,
|
|
1201
|
-
this.cellStyle = (0,
|
|
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,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1225
|
+
import_core19 = require("@angular/core");
|
|
1226
1226
|
EmlText = class {
|
|
1227
1227
|
constructor() {
|
|
1228
|
-
this.color = (0,
|
|
1229
|
-
this.fontSize = (0,
|
|
1230
|
-
this.lineHeight = (0,
|
|
1231
|
-
this.margin = (0,
|
|
1232
|
-
this.textAlign = (0,
|
|
1233
|
-
this.pStyle = (0,
|
|
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,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1257
|
+
import_core20 = require("@angular/core");
|
|
1258
1258
|
EmlHeading = class {
|
|
1259
1259
|
constructor() {
|
|
1260
|
-
this.level = (0,
|
|
1261
|
-
this.color = (0,
|
|
1262
|
-
this.margin = (0,
|
|
1263
|
-
this.textAlign = (0,
|
|
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,
|
|
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,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1291
|
+
import_core21 = require("@angular/core");
|
|
1292
1292
|
EmlButton = class {
|
|
1293
1293
|
constructor() {
|
|
1294
|
-
this.href = (0,
|
|
1295
|
-
this.backgroundColor = (0,
|
|
1296
|
-
this.color = (0,
|
|
1297
|
-
this.borderRadius = (0,
|
|
1298
|
-
this.padding = (0,
|
|
1299
|
-
this.textAlign = (0,
|
|
1300
|
-
this.alignStyle = (0,
|
|
1301
|
-
this.linkStyle = (0,
|
|
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,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1331
|
+
import_core22 = require("@angular/core");
|
|
1332
1332
|
EmlLink = class {
|
|
1333
1333
|
constructor() {
|
|
1334
|
-
this.href = (0,
|
|
1335
|
-
this.color = (0,
|
|
1336
|
-
this.textDecoration = (0,
|
|
1337
|
-
this.linkStyle = (0,
|
|
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,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1361
|
+
import_core23 = require("@angular/core");
|
|
1362
1362
|
EmlImage = class {
|
|
1363
1363
|
constructor() {
|
|
1364
|
-
this.src = (0,
|
|
1365
|
-
this.alt = (0,
|
|
1366
|
-
this.width = (0,
|
|
1367
|
-
this.height = (0,
|
|
1368
|
-
this.borderRadius = (0,
|
|
1369
|
-
this.imgStyle = (0,
|
|
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,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1397
|
+
import_core24 = require("@angular/core");
|
|
1398
1398
|
EmlDivider = class {
|
|
1399
1399
|
constructor() {
|
|
1400
|
-
this.color = (0,
|
|
1401
|
-
this.margin = (0,
|
|
1402
|
-
this.hrStyle = (0,
|
|
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,
|
|
1408
|
+
(0, import_core24.Component)({
|
|
1409
1409
|
selector: "eml-divider",
|
|
1410
1410
|
template: `<hr [attr.style]="hrStyle()" />`,
|
|
1411
|
-
changeDetection:
|
|
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
|
|
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
|
-
|
|
1422
|
+
import_core25 = require("@angular/core");
|
|
1423
1423
|
EmlPreview = class {
|
|
1424
1424
|
};
|
|
1425
1425
|
EmlPreview = __decorateClass([
|
|
1426
|
-
(0,
|
|
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:
|
|
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
|
|
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
|
-
|
|
1444
|
+
import_core26 = require("@angular/core");
|
|
1445
1445
|
EmlSpacer = class {
|
|
1446
1446
|
constructor() {
|
|
1447
|
-
this.height = (0,
|
|
1448
|
-
this.spacerStyle = (0,
|
|
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,
|
|
1454
|
+
(0, import_core26.Component)({
|
|
1455
1455
|
selector: "eml-spacer",
|
|
1456
1456
|
template: `<div [attr.style]="spacerStyle()"></div>`,
|
|
1457
|
-
changeDetection:
|
|
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
|
|
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
|
-
|
|
1468
|
+
import_core27 = require("@angular/core");
|
|
1469
1469
|
EmlFooter = class {
|
|
1470
1470
|
constructor() {
|
|
1471
|
-
this.maxWidth = (0,
|
|
1472
|
-
this.color = (0,
|
|
1473
|
-
this.fontSize = (0,
|
|
1474
|
-
this.textAlign = (0,
|
|
1475
|
-
this.padding = (0,
|
|
1476
|
-
this.tableStyle = (0,
|
|
1477
|
-
this.cellStyle = (0,
|
|
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,
|
|
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:
|
|
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
|
|
3123
|
-
result[field] = condition
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3273
|
+
throw new DraftNotVisibleError(this.slug, id);
|
|
3231
3274
|
}
|
|
3232
3275
|
}
|
|
3233
3276
|
}
|
|
3234
3277
|
if (!this.matchesDefaultWhereConstraints(doc)) {
|
|
3235
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3079
|
-
result[field] = condition
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3229
|
+
throw new DraftNotVisibleError(this.slug, id);
|
|
3187
3230
|
}
|
|
3188
3231
|
}
|
|
3189
3232
|
}
|
|
3190
3233
|
if (!this.matchesDefaultWhereConstraints(doc)) {
|
|
3191
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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";
|