@momentumcms/server-analog 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 +30 -0
- package/index.cjs +73 -17
- package/index.js +73 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
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
|
+
- NestJS server adapter + E2E stabilization (0.5.2) ([#48](https://github.com/DonaldMurillo/momentum-cms/pull/48))
|
|
8
|
+
- S3, auth plugin wiring, redirects, and E2E tooling ([#41](https://github.com/DonaldMurillo/momentum-cms/pull/41))
|
|
9
|
+
- client-side page view tracking and content performance improvements ([#39](https://github.com/DonaldMurillo/momentum-cms/pull/39))
|
|
10
|
+
- blocks showcase with articles, pages, and UI fixes ([#36](https://github.com/DonaldMurillo/momentum-cms/pull/36))
|
|
11
|
+
- add named tabs support with nested data grouping and UI improvements ([#30](https://github.com/DonaldMurillo/momentum-cms/pull/30))
|
|
12
|
+
- Implement admin UI with API integration and SSR hydration ([9ed7b2bd](https://github.com/DonaldMurillo/momentum-cms/commit/9ed7b2bd))
|
|
13
|
+
- Initialize Momentum CMS foundation ([f64f5817](https://github.com/DonaldMurillo/momentum-cms/commit/f64f5817))
|
|
14
|
+
|
|
15
|
+
### 🩹 Fixes
|
|
16
|
+
|
|
17
|
+
- Analog versioning access control + E2E improvements ([#54](https://github.com/DonaldMurillo/momentum-cms/pull/54))
|
|
18
|
+
- add public access to form-builder npm publish config ([#46](https://github.com/DonaldMurillo/momentum-cms/pull/46))
|
|
19
|
+
- Resolve non-null assertion bugs and CLAUDE.md violations ([#44](https://github.com/DonaldMurillo/momentum-cms/pull/44))
|
|
20
|
+
- **create-momentum-app:** add shell option to execFileSync for Windows ([#28](https://github.com/DonaldMurillo/momentum-cms/pull/28))
|
|
21
|
+
- correct repository URLs and add GitHub link to CLI ([#26](https://github.com/DonaldMurillo/momentum-cms/pull/26))
|
|
22
|
+
- 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))
|
|
23
|
+
|
|
24
|
+
### ❤️ Thank You
|
|
25
|
+
|
|
26
|
+
- Claude Haiku 4.5
|
|
27
|
+
- Claude Opus 4.5
|
|
28
|
+
- Claude Opus 4.6
|
|
29
|
+
- Donald Murillo @DonaldMurillo
|
|
30
|
+
|
|
1
31
|
## 0.5.4 (2026-03-07)
|
|
2
32
|
|
|
3
33
|
This was a version bump only for server-analog to align it with other projects, there were no code changes.
|
package/index.cjs
CHANGED
|
@@ -1814,6 +1814,12 @@ var DocumentNotFoundError = class extends Error {
|
|
|
1814
1814
|
this.name = "DocumentNotFoundError";
|
|
1815
1815
|
}
|
|
1816
1816
|
};
|
|
1817
|
+
var DraftNotVisibleError = class extends Error {
|
|
1818
|
+
constructor(collection, id) {
|
|
1819
|
+
super(`Draft "${id}" in collection "${collection}" is not visible to the current user`);
|
|
1820
|
+
this.name = "DraftNotVisibleError";
|
|
1821
|
+
}
|
|
1822
|
+
};
|
|
1817
1823
|
var AccessDeniedError = class extends Error {
|
|
1818
1824
|
constructor(operation, collection) {
|
|
1819
1825
|
super(`Access denied for ${operation} on collection "${collection}"`);
|
|
@@ -2231,13 +2237,31 @@ function stripTransientKeys(data) {
|
|
|
2231
2237
|
}
|
|
2232
2238
|
return result;
|
|
2233
2239
|
}
|
|
2240
|
+
var COMPARISON_OPS = ["gt", "gte", "lt", "lte"];
|
|
2234
2241
|
function flattenWhereClause(where) {
|
|
2235
2242
|
if (!where)
|
|
2236
2243
|
return {};
|
|
2237
2244
|
const result = {};
|
|
2238
2245
|
for (const [field, condition] of Object.entries(where)) {
|
|
2239
|
-
if (typeof condition
|
|
2240
|
-
result[field] = condition
|
|
2246
|
+
if (typeof condition !== "object" || condition === null) {
|
|
2247
|
+
result[field] = condition;
|
|
2248
|
+
continue;
|
|
2249
|
+
}
|
|
2250
|
+
const condObj = condition;
|
|
2251
|
+
if ("equals" in condObj) {
|
|
2252
|
+
result[field] = condObj["equals"];
|
|
2253
|
+
continue;
|
|
2254
|
+
}
|
|
2255
|
+
const ops = {};
|
|
2256
|
+
let hasComparisonOp = false;
|
|
2257
|
+
for (const op of COMPARISON_OPS) {
|
|
2258
|
+
if (op in condObj) {
|
|
2259
|
+
ops[`$${op}`] = condObj[op];
|
|
2260
|
+
hasComparisonOp = true;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
if (hasComparisonOp) {
|
|
2264
|
+
result[field] = ops;
|
|
2241
2265
|
} else {
|
|
2242
2266
|
result[field] = condition;
|
|
2243
2267
|
}
|
|
@@ -2332,24 +2356,24 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
|
|
|
2332
2356
|
await this.runBeforeReadHooks();
|
|
2333
2357
|
const doc = await this.adapter.findById(this.slug, id);
|
|
2334
2358
|
if (!doc) {
|
|
2335
|
-
|
|
2359
|
+
throw new DocumentNotFoundError(this.slug, id);
|
|
2336
2360
|
}
|
|
2337
2361
|
const softDeleteField = getSoftDeleteField(this.collectionConfig);
|
|
2338
2362
|
if (softDeleteField && !options?.withDeleted && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- T is compatible with Record<string, unknown>
|
|
2339
2363
|
doc[softDeleteField]) {
|
|
2340
|
-
|
|
2364
|
+
throw new DocumentNotFoundError(this.slug, id);
|
|
2341
2365
|
}
|
|
2342
2366
|
if (hasVersionDrafts(this.collectionConfig) && !this.context.overrideAccess) {
|
|
2343
2367
|
const canSeeDrafts = await this.canReadDrafts();
|
|
2344
2368
|
if (!canSeeDrafts) {
|
|
2345
2369
|
const record = doc;
|
|
2346
2370
|
if (record["_status"] !== "published") {
|
|
2347
|
-
|
|
2371
|
+
throw new DraftNotVisibleError(this.slug, id);
|
|
2348
2372
|
}
|
|
2349
2373
|
}
|
|
2350
2374
|
}
|
|
2351
2375
|
if (!this.matchesDefaultWhereConstraints(doc)) {
|
|
2352
|
-
|
|
2376
|
+
throw new DocumentNotFoundError(this.slug, id);
|
|
2353
2377
|
}
|
|
2354
2378
|
const [processed] = await this.processAfterReadHooks([doc]);
|
|
2355
2379
|
const MAX_RELATIONSHIP_DEPTH = 10;
|
|
@@ -3220,9 +3244,6 @@ function createMomentumHandlers(config) {
|
|
|
3220
3244
|
const depth = typeof request.query?.["depth"] === "number" ? request.query["depth"] : void 0;
|
|
3221
3245
|
const withDeleted = request.query?.["withDeleted"] === true;
|
|
3222
3246
|
const doc = await api.collection(request.collectionSlug).findById(request.id, { depth, withDeleted });
|
|
3223
|
-
if (!doc) {
|
|
3224
|
-
return { error: "Document not found", status: 404 };
|
|
3225
|
-
}
|
|
3226
3247
|
return { doc };
|
|
3227
3248
|
} catch (error) {
|
|
3228
3249
|
return handleError(error);
|
|
@@ -3339,6 +3360,9 @@ function handleError(error) {
|
|
|
3339
3360
|
if (error instanceof DocumentNotFoundError) {
|
|
3340
3361
|
return { error: error.message, status: 404 };
|
|
3341
3362
|
}
|
|
3363
|
+
if (error instanceof DraftNotVisibleError) {
|
|
3364
|
+
return { doc: null };
|
|
3365
|
+
}
|
|
3342
3366
|
if (error instanceof AccessDeniedError) {
|
|
3343
3367
|
return { error: error.message, status: 403 };
|
|
3344
3368
|
}
|
|
@@ -3735,7 +3759,14 @@ function buildGraphQLSchema(collections) {
|
|
|
3735
3759
|
const api = getMomentumAPI();
|
|
3736
3760
|
const ctx = buildAPIContext(context);
|
|
3737
3761
|
const contextApi = Object.keys(ctx).length > 0 ? api.setContext(ctx) : api;
|
|
3738
|
-
|
|
3762
|
+
try {
|
|
3763
|
+
return await contextApi.collection(col.slug).findById(args.id);
|
|
3764
|
+
} catch (err) {
|
|
3765
|
+
if (err instanceof Error && err.name === "DocumentNotFoundError") {
|
|
3766
|
+
return null;
|
|
3767
|
+
}
|
|
3768
|
+
throw err;
|
|
3769
|
+
}
|
|
3739
3770
|
}
|
|
3740
3771
|
};
|
|
3741
3772
|
queryFields[plural.charAt(0).toLowerCase() + plural.slice(1)] = {
|
|
@@ -5366,7 +5397,13 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5366
5397
|
return { docs: r.docs, totalDocs: r.totalDocs };
|
|
5367
5398
|
},
|
|
5368
5399
|
findById: async (slug2, id) => {
|
|
5369
|
-
|
|
5400
|
+
try {
|
|
5401
|
+
return await contextApi.collection(slug2).findById(id);
|
|
5402
|
+
} catch (err) {
|
|
5403
|
+
if (err instanceof Error && err.name === "DocumentNotFoundError")
|
|
5404
|
+
return null;
|
|
5405
|
+
throw err;
|
|
5406
|
+
}
|
|
5370
5407
|
},
|
|
5371
5408
|
count: (slug2) => contextApi.collection(slug2).count(),
|
|
5372
5409
|
create: async (slug2, data) => {
|
|
@@ -5731,6 +5768,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5731
5768
|
});
|
|
5732
5769
|
return { doc: restored, message: "Version restored successfully" };
|
|
5733
5770
|
} catch (error) {
|
|
5771
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5772
|
+
utils.setResponseStatus(event, 403);
|
|
5773
|
+
return { error: "Access denied" };
|
|
5774
|
+
}
|
|
5734
5775
|
const message = sanitizeErrorMessage(error, "Unknown error");
|
|
5735
5776
|
if (error instanceof Error && error.message.includes("mismatch")) {
|
|
5736
5777
|
utils.setResponseStatus(event, 400);
|
|
@@ -5771,6 +5812,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5771
5812
|
);
|
|
5772
5813
|
return { differences };
|
|
5773
5814
|
} catch (error) {
|
|
5815
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5816
|
+
utils.setResponseStatus(event, 403);
|
|
5817
|
+
return { error: "Access denied" };
|
|
5818
|
+
}
|
|
5774
5819
|
utils.setResponseStatus(event, 500);
|
|
5775
5820
|
return {
|
|
5776
5821
|
error: "Failed to compare versions",
|
|
@@ -5798,6 +5843,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5798
5843
|
}
|
|
5799
5844
|
return version;
|
|
5800
5845
|
} catch (error) {
|
|
5846
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5847
|
+
utils.setResponseStatus(event, 403);
|
|
5848
|
+
return { error: "Access denied" };
|
|
5849
|
+
}
|
|
5801
5850
|
utils.setResponseStatus(event, 500);
|
|
5802
5851
|
return {
|
|
5803
5852
|
error: "Failed to fetch version",
|
|
@@ -5822,6 +5871,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5822
5871
|
});
|
|
5823
5872
|
return result;
|
|
5824
5873
|
} catch (error) {
|
|
5874
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5875
|
+
utils.setResponseStatus(event, 403);
|
|
5876
|
+
return { error: "Access denied" };
|
|
5877
|
+
}
|
|
5825
5878
|
utils.setResponseStatus(event, 500);
|
|
5826
5879
|
return {
|
|
5827
5880
|
error: "Failed to fetch versions",
|
|
@@ -5862,12 +5915,7 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5862
5915
|
}
|
|
5863
5916
|
} else {
|
|
5864
5917
|
const contextApi = getContextualAPI(user);
|
|
5865
|
-
|
|
5866
|
-
if (!doc) {
|
|
5867
|
-
utils.setResponseStatus(event, 404);
|
|
5868
|
-
return { error: "Document not found" };
|
|
5869
|
-
}
|
|
5870
|
-
docRecord = doc;
|
|
5918
|
+
docRecord = await contextApi.collection(collectionSlug2).findById(docId);
|
|
5871
5919
|
}
|
|
5872
5920
|
const emailField = getEmailBuilderFieldName(collectionConfig);
|
|
5873
5921
|
const html = emailField ? await renderEmailPreviewHTML(docRecord, emailField) : renderPreviewHTML({ doc: docRecord, collection: collectionConfig });
|
|
@@ -5936,6 +5984,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5936
5984
|
return { message: "Scheduled publish cancelled" };
|
|
5937
5985
|
}
|
|
5938
5986
|
} catch (error) {
|
|
5987
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5988
|
+
utils.setResponseStatus(event, 403);
|
|
5989
|
+
return { error: "Access denied" };
|
|
5990
|
+
}
|
|
5939
5991
|
utils.setResponseStatus(event, 500);
|
|
5940
5992
|
return {
|
|
5941
5993
|
error: `Failed to ${action.replace(/-/g, " ")}`,
|
|
@@ -5977,6 +6029,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5977
6029
|
const status = await versionOps.getStatus(docId);
|
|
5978
6030
|
return { status };
|
|
5979
6031
|
} catch (error) {
|
|
6032
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
6033
|
+
utils.setResponseStatus(event, 403);
|
|
6034
|
+
return { error: "Access denied" };
|
|
6035
|
+
}
|
|
5980
6036
|
utils.setResponseStatus(event, 500);
|
|
5981
6037
|
return {
|
|
5982
6038
|
error: "Failed to get status",
|
package/index.js
CHANGED
|
@@ -1781,6 +1781,12 @@ var DocumentNotFoundError = class extends Error {
|
|
|
1781
1781
|
this.name = "DocumentNotFoundError";
|
|
1782
1782
|
}
|
|
1783
1783
|
};
|
|
1784
|
+
var DraftNotVisibleError = class extends Error {
|
|
1785
|
+
constructor(collection, id) {
|
|
1786
|
+
super(`Draft "${id}" in collection "${collection}" is not visible to the current user`);
|
|
1787
|
+
this.name = "DraftNotVisibleError";
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1784
1790
|
var AccessDeniedError = class extends Error {
|
|
1785
1791
|
constructor(operation, collection) {
|
|
1786
1792
|
super(`Access denied for ${operation} on collection "${collection}"`);
|
|
@@ -2198,13 +2204,31 @@ function stripTransientKeys(data) {
|
|
|
2198
2204
|
}
|
|
2199
2205
|
return result;
|
|
2200
2206
|
}
|
|
2207
|
+
var COMPARISON_OPS = ["gt", "gte", "lt", "lte"];
|
|
2201
2208
|
function flattenWhereClause(where) {
|
|
2202
2209
|
if (!where)
|
|
2203
2210
|
return {};
|
|
2204
2211
|
const result = {};
|
|
2205
2212
|
for (const [field, condition] of Object.entries(where)) {
|
|
2206
|
-
if (typeof condition
|
|
2207
|
-
result[field] = condition
|
|
2213
|
+
if (typeof condition !== "object" || condition === null) {
|
|
2214
|
+
result[field] = condition;
|
|
2215
|
+
continue;
|
|
2216
|
+
}
|
|
2217
|
+
const condObj = condition;
|
|
2218
|
+
if ("equals" in condObj) {
|
|
2219
|
+
result[field] = condObj["equals"];
|
|
2220
|
+
continue;
|
|
2221
|
+
}
|
|
2222
|
+
const ops = {};
|
|
2223
|
+
let hasComparisonOp = false;
|
|
2224
|
+
for (const op of COMPARISON_OPS) {
|
|
2225
|
+
if (op in condObj) {
|
|
2226
|
+
ops[`$${op}`] = condObj[op];
|
|
2227
|
+
hasComparisonOp = true;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
if (hasComparisonOp) {
|
|
2231
|
+
result[field] = ops;
|
|
2208
2232
|
} else {
|
|
2209
2233
|
result[field] = condition;
|
|
2210
2234
|
}
|
|
@@ -2299,24 +2323,24 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
|
|
|
2299
2323
|
await this.runBeforeReadHooks();
|
|
2300
2324
|
const doc = await this.adapter.findById(this.slug, id);
|
|
2301
2325
|
if (!doc) {
|
|
2302
|
-
|
|
2326
|
+
throw new DocumentNotFoundError(this.slug, id);
|
|
2303
2327
|
}
|
|
2304
2328
|
const softDeleteField = getSoftDeleteField(this.collectionConfig);
|
|
2305
2329
|
if (softDeleteField && !options?.withDeleted && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- T is compatible with Record<string, unknown>
|
|
2306
2330
|
doc[softDeleteField]) {
|
|
2307
|
-
|
|
2331
|
+
throw new DocumentNotFoundError(this.slug, id);
|
|
2308
2332
|
}
|
|
2309
2333
|
if (hasVersionDrafts(this.collectionConfig) && !this.context.overrideAccess) {
|
|
2310
2334
|
const canSeeDrafts = await this.canReadDrafts();
|
|
2311
2335
|
if (!canSeeDrafts) {
|
|
2312
2336
|
const record = doc;
|
|
2313
2337
|
if (record["_status"] !== "published") {
|
|
2314
|
-
|
|
2338
|
+
throw new DraftNotVisibleError(this.slug, id);
|
|
2315
2339
|
}
|
|
2316
2340
|
}
|
|
2317
2341
|
}
|
|
2318
2342
|
if (!this.matchesDefaultWhereConstraints(doc)) {
|
|
2319
|
-
|
|
2343
|
+
throw new DocumentNotFoundError(this.slug, id);
|
|
2320
2344
|
}
|
|
2321
2345
|
const [processed] = await this.processAfterReadHooks([doc]);
|
|
2322
2346
|
const MAX_RELATIONSHIP_DEPTH = 10;
|
|
@@ -3187,9 +3211,6 @@ function createMomentumHandlers(config) {
|
|
|
3187
3211
|
const depth = typeof request.query?.["depth"] === "number" ? request.query["depth"] : void 0;
|
|
3188
3212
|
const withDeleted = request.query?.["withDeleted"] === true;
|
|
3189
3213
|
const doc = await api.collection(request.collectionSlug).findById(request.id, { depth, withDeleted });
|
|
3190
|
-
if (!doc) {
|
|
3191
|
-
return { error: "Document not found", status: 404 };
|
|
3192
|
-
}
|
|
3193
3214
|
return { doc };
|
|
3194
3215
|
} catch (error) {
|
|
3195
3216
|
return handleError(error);
|
|
@@ -3306,6 +3327,9 @@ function handleError(error) {
|
|
|
3306
3327
|
if (error instanceof DocumentNotFoundError) {
|
|
3307
3328
|
return { error: error.message, status: 404 };
|
|
3308
3329
|
}
|
|
3330
|
+
if (error instanceof DraftNotVisibleError) {
|
|
3331
|
+
return { doc: null };
|
|
3332
|
+
}
|
|
3309
3333
|
if (error instanceof AccessDeniedError) {
|
|
3310
3334
|
return { error: error.message, status: 403 };
|
|
3311
3335
|
}
|
|
@@ -3715,7 +3739,14 @@ function buildGraphQLSchema(collections) {
|
|
|
3715
3739
|
const api = getMomentumAPI();
|
|
3716
3740
|
const ctx = buildAPIContext(context);
|
|
3717
3741
|
const contextApi = Object.keys(ctx).length > 0 ? api.setContext(ctx) : api;
|
|
3718
|
-
|
|
3742
|
+
try {
|
|
3743
|
+
return await contextApi.collection(col.slug).findById(args.id);
|
|
3744
|
+
} catch (err) {
|
|
3745
|
+
if (err instanceof Error && err.name === "DocumentNotFoundError") {
|
|
3746
|
+
return null;
|
|
3747
|
+
}
|
|
3748
|
+
throw err;
|
|
3749
|
+
}
|
|
3719
3750
|
}
|
|
3720
3751
|
};
|
|
3721
3752
|
queryFields[plural.charAt(0).toLowerCase() + plural.slice(1)] = {
|
|
@@ -5346,7 +5377,13 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5346
5377
|
return { docs: r.docs, totalDocs: r.totalDocs };
|
|
5347
5378
|
},
|
|
5348
5379
|
findById: async (slug2, id) => {
|
|
5349
|
-
|
|
5380
|
+
try {
|
|
5381
|
+
return await contextApi.collection(slug2).findById(id);
|
|
5382
|
+
} catch (err) {
|
|
5383
|
+
if (err instanceof Error && err.name === "DocumentNotFoundError")
|
|
5384
|
+
return null;
|
|
5385
|
+
throw err;
|
|
5386
|
+
}
|
|
5350
5387
|
},
|
|
5351
5388
|
count: (slug2) => contextApi.collection(slug2).count(),
|
|
5352
5389
|
create: async (slug2, data) => {
|
|
@@ -5711,6 +5748,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5711
5748
|
});
|
|
5712
5749
|
return { doc: restored, message: "Version restored successfully" };
|
|
5713
5750
|
} catch (error) {
|
|
5751
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5752
|
+
utils.setResponseStatus(event, 403);
|
|
5753
|
+
return { error: "Access denied" };
|
|
5754
|
+
}
|
|
5714
5755
|
const message = sanitizeErrorMessage(error, "Unknown error");
|
|
5715
5756
|
if (error instanceof Error && error.message.includes("mismatch")) {
|
|
5716
5757
|
utils.setResponseStatus(event, 400);
|
|
@@ -5751,6 +5792,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5751
5792
|
);
|
|
5752
5793
|
return { differences };
|
|
5753
5794
|
} catch (error) {
|
|
5795
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5796
|
+
utils.setResponseStatus(event, 403);
|
|
5797
|
+
return { error: "Access denied" };
|
|
5798
|
+
}
|
|
5754
5799
|
utils.setResponseStatus(event, 500);
|
|
5755
5800
|
return {
|
|
5756
5801
|
error: "Failed to compare versions",
|
|
@@ -5778,6 +5823,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5778
5823
|
}
|
|
5779
5824
|
return version;
|
|
5780
5825
|
} catch (error) {
|
|
5826
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5827
|
+
utils.setResponseStatus(event, 403);
|
|
5828
|
+
return { error: "Access denied" };
|
|
5829
|
+
}
|
|
5781
5830
|
utils.setResponseStatus(event, 500);
|
|
5782
5831
|
return {
|
|
5783
5832
|
error: "Failed to fetch version",
|
|
@@ -5802,6 +5851,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5802
5851
|
});
|
|
5803
5852
|
return result;
|
|
5804
5853
|
} catch (error) {
|
|
5854
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5855
|
+
utils.setResponseStatus(event, 403);
|
|
5856
|
+
return { error: "Access denied" };
|
|
5857
|
+
}
|
|
5805
5858
|
utils.setResponseStatus(event, 500);
|
|
5806
5859
|
return {
|
|
5807
5860
|
error: "Failed to fetch versions",
|
|
@@ -5842,12 +5895,7 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5842
5895
|
}
|
|
5843
5896
|
} else {
|
|
5844
5897
|
const contextApi = getContextualAPI(user);
|
|
5845
|
-
|
|
5846
|
-
if (!doc) {
|
|
5847
|
-
utils.setResponseStatus(event, 404);
|
|
5848
|
-
return { error: "Document not found" };
|
|
5849
|
-
}
|
|
5850
|
-
docRecord = doc;
|
|
5898
|
+
docRecord = await contextApi.collection(collectionSlug2).findById(docId);
|
|
5851
5899
|
}
|
|
5852
5900
|
const emailField = getEmailBuilderFieldName(collectionConfig);
|
|
5853
5901
|
const html = emailField ? await renderEmailPreviewHTML(docRecord, emailField) : renderPreviewHTML({ doc: docRecord, collection: collectionConfig });
|
|
@@ -5916,6 +5964,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5916
5964
|
return { message: "Scheduled publish cancelled" };
|
|
5917
5965
|
}
|
|
5918
5966
|
} catch (error) {
|
|
5967
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
5968
|
+
utils.setResponseStatus(event, 403);
|
|
5969
|
+
return { error: "Access denied" };
|
|
5970
|
+
}
|
|
5919
5971
|
utils.setResponseStatus(event, 500);
|
|
5920
5972
|
return {
|
|
5921
5973
|
error: `Failed to ${action.replace(/-/g, " ")}`,
|
|
@@ -5957,6 +6009,10 @@ function createComprehensiveMomentumHandler(config) {
|
|
|
5957
6009
|
const status = await versionOps.getStatus(docId);
|
|
5958
6010
|
return { status };
|
|
5959
6011
|
} catch (error) {
|
|
6012
|
+
if (error instanceof Error && error.name === "AccessDeniedError") {
|
|
6013
|
+
utils.setResponseStatus(event, 403);
|
|
6014
|
+
return { error: "Access denied" };
|
|
6015
|
+
}
|
|
5960
6016
|
utils.setResponseStatus(event, 500);
|
|
5961
6017
|
return {
|
|
5962
6018
|
error: "Failed to get status",
|