@momentumcms/server-analog 0.5.3 → 0.5.4

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 CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.5.4 (2026-03-07)
2
+
3
+ This was a version bump only for server-analog to align it with other projects, there were no code changes.
4
+
1
5
  ## 0.5.0 (2026-02-23)
2
6
 
3
7
  This was a version bump only for server-analog to align it with other projects, there were no code changes.
package/index.cjs CHANGED
@@ -1452,6 +1452,14 @@ var MediaCollection = defineCollection({
1452
1452
  }
1453
1453
  });
1454
1454
 
1455
+ // libs/core/src/lib/versions/version.types.ts
1456
+ function hasVersionDrafts(collection) {
1457
+ const v = collection.versions;
1458
+ if (!v || typeof v === "boolean")
1459
+ return false;
1460
+ return !!v.drafts;
1461
+ }
1462
+
1455
1463
  // libs/server-core/src/lib/field-access.ts
1456
1464
  function hasFieldAccessControl(fields) {
1457
1465
  for (const field of fields) {
@@ -2038,13 +2046,18 @@ var VersionOperationsImpl = class {
2038
2046
  }
2039
2047
  return "draft";
2040
2048
  }
2041
- async compare(versionId1, versionId2) {
2049
+ async compare(versionId1, versionId2, parentId) {
2042
2050
  await this.checkAccess("readVersions");
2043
2051
  const version1 = await this.findVersionById(versionId1);
2044
2052
  const version2 = await this.findVersionById(versionId2);
2045
2053
  if (!version1 || !version2) {
2046
2054
  throw new Error("One or both versions not found");
2047
2055
  }
2056
+ if (parentId) {
2057
+ if (version1.parent !== parentId || version2.parent !== parentId) {
2058
+ throw new Error("Version does not belong to the specified document");
2059
+ }
2060
+ }
2048
2061
  const data1 = version1.version;
2049
2062
  const data2 = version2.version;
2050
2063
  if (!isRecord(data1) || !isRecord(data2)) {
@@ -2099,6 +2112,9 @@ var VersionOperationsImpl = class {
2099
2112
  // Private Helpers
2100
2113
  // ============================================
2101
2114
  async checkAccess(operation) {
2115
+ if (this.context.overrideAccess) {
2116
+ return;
2117
+ }
2102
2118
  const accessFn = this.collectionConfig.access?.[operation];
2103
2119
  if (!accessFn) {
2104
2120
  return;
@@ -2255,6 +2271,12 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
2255
2271
  Object.assign(whereParams, constraints);
2256
2272
  }
2257
2273
  }
2274
+ if (hasVersionDrafts(this.collectionConfig) && !this.context.overrideAccess) {
2275
+ const canSeeDrafts = await this.canReadDrafts();
2276
+ if (!canSeeDrafts) {
2277
+ whereParams["_status"] = "published";
2278
+ }
2279
+ }
2258
2280
  const query = {
2259
2281
  ...queryOptions,
2260
2282
  ...whereParams,
@@ -2317,6 +2339,15 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
2317
2339
  doc[softDeleteField]) {
2318
2340
  return null;
2319
2341
  }
2342
+ if (hasVersionDrafts(this.collectionConfig) && !this.context.overrideAccess) {
2343
+ const canSeeDrafts = await this.canReadDrafts();
2344
+ if (!canSeeDrafts) {
2345
+ const record = doc;
2346
+ if (record["_status"] !== "published") {
2347
+ return null;
2348
+ }
2349
+ }
2350
+ }
2320
2351
  if (!this.matchesDefaultWhereConstraints(doc)) {
2321
2352
  return null;
2322
2353
  }
@@ -2402,6 +2433,15 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
2402
2433
  if (!this.matchesDefaultWhereConstraints(originalDoc)) {
2403
2434
  throw new DocumentNotFoundError(this.slug, id);
2404
2435
  }
2436
+ if (hasVersionDrafts(this.collectionConfig) && this.adapter.createVersion) {
2437
+ const status = originalDoc["_status"] ?? "draft";
2438
+ await this.adapter.createVersion(this.slug, id, originalDoc, { status });
2439
+ const versionsConfig = this.collectionConfig.versions;
2440
+ const maxPerDoc = typeof versionsConfig === "object" && versionsConfig !== null ? versionsConfig.maxPerDoc : void 0;
2441
+ if (maxPerDoc && this.adapter.deleteVersions) {
2442
+ await this.adapter.deleteVersions(this.slug, id, maxPerDoc);
2443
+ }
2444
+ }
2405
2445
  let processedData = data;
2406
2446
  const softDeleteField = getSoftDeleteField(this.collectionConfig);
2407
2447
  if (softDeleteField && softDeleteField in processedData) {
@@ -2733,6 +2773,30 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
2733
2773
  throw new AccessDeniedError(operation, this.slug);
2734
2774
  }
2735
2775
  }
2776
+ /**
2777
+ * Check if the current user can see draft documents (non-throwing).
2778
+ * Uses `access.readDrafts` if configured, otherwise falls back to `access.update`.
2779
+ */
2780
+ async canReadDrafts() {
2781
+ if (!this.context.user)
2782
+ return false;
2783
+ const readDraftsFn = this.collectionConfig.access?.readDrafts;
2784
+ if (readDraftsFn) {
2785
+ try {
2786
+ return !!await Promise.resolve(readDraftsFn({ req: this.buildRequestContext() }));
2787
+ } catch {
2788
+ return false;
2789
+ }
2790
+ }
2791
+ const updateFn = this.collectionConfig.access?.update;
2792
+ if (!updateFn)
2793
+ return true;
2794
+ try {
2795
+ return !!await Promise.resolve(updateFn({ req: this.buildRequestContext() }));
2796
+ } catch {
2797
+ return false;
2798
+ }
2799
+ }
2736
2800
  buildRequestContext() {
2737
2801
  return {
2738
2802
  user: this.context.user
@@ -3412,8 +3476,9 @@ function buildGraphQLSchema(collections) {
3412
3476
  }
3413
3477
  function getOrCreateEnum(field, parentName) {
3414
3478
  const key = `${parentName}_${field.name}`;
3415
- if (enumCache.has(key)) {
3416
- return enumCache.get(key);
3479
+ const cached = enumCache.get(key);
3480
+ if (cached) {
3481
+ return cached;
3417
3482
  }
3418
3483
  const values = {};
3419
3484
  for (const opt of field.options) {
@@ -3524,8 +3589,9 @@ function buildGraphQLSchema(collections) {
3524
3589
  }
3525
3590
  }
3526
3591
  function getOrCreateObjectType(fields, typeName) {
3527
- if (typeCache.has(typeName)) {
3528
- return typeCache.get(typeName);
3592
+ const cachedType = typeCache.get(typeName);
3593
+ if (cachedType) {
3594
+ return cachedType;
3529
3595
  }
3530
3596
  const objType = new import_graphql2.GraphQLObjectType({
3531
3597
  name: typeName,
@@ -3546,8 +3612,9 @@ function buildGraphQLSchema(collections) {
3546
3612
  }
3547
3613
  function getOrCreateInputType(fields, typeName) {
3548
3614
  const inputName = `${typeName}Input`;
3549
- if (inputCache.has(inputName)) {
3550
- return inputCache.get(inputName);
3615
+ const cachedInput = inputCache.get(inputName);
3616
+ if (cachedInput) {
3617
+ return cachedInput;
3551
3618
  }
3552
3619
  const inputType = new import_graphql2.GraphQLInputObjectType({
3553
3620
  name: inputName,
package/index.js CHANGED
@@ -1419,6 +1419,14 @@ var MediaCollection = defineCollection({
1419
1419
  }
1420
1420
  });
1421
1421
 
1422
+ // libs/core/src/lib/versions/version.types.ts
1423
+ function hasVersionDrafts(collection) {
1424
+ const v = collection.versions;
1425
+ if (!v || typeof v === "boolean")
1426
+ return false;
1427
+ return !!v.drafts;
1428
+ }
1429
+
1422
1430
  // libs/server-core/src/lib/field-access.ts
1423
1431
  function hasFieldAccessControl(fields) {
1424
1432
  for (const field of fields) {
@@ -2005,13 +2013,18 @@ var VersionOperationsImpl = class {
2005
2013
  }
2006
2014
  return "draft";
2007
2015
  }
2008
- async compare(versionId1, versionId2) {
2016
+ async compare(versionId1, versionId2, parentId) {
2009
2017
  await this.checkAccess("readVersions");
2010
2018
  const version1 = await this.findVersionById(versionId1);
2011
2019
  const version2 = await this.findVersionById(versionId2);
2012
2020
  if (!version1 || !version2) {
2013
2021
  throw new Error("One or both versions not found");
2014
2022
  }
2023
+ if (parentId) {
2024
+ if (version1.parent !== parentId || version2.parent !== parentId) {
2025
+ throw new Error("Version does not belong to the specified document");
2026
+ }
2027
+ }
2015
2028
  const data1 = version1.version;
2016
2029
  const data2 = version2.version;
2017
2030
  if (!isRecord(data1) || !isRecord(data2)) {
@@ -2066,6 +2079,9 @@ var VersionOperationsImpl = class {
2066
2079
  // Private Helpers
2067
2080
  // ============================================
2068
2081
  async checkAccess(operation) {
2082
+ if (this.context.overrideAccess) {
2083
+ return;
2084
+ }
2069
2085
  const accessFn = this.collectionConfig.access?.[operation];
2070
2086
  if (!accessFn) {
2071
2087
  return;
@@ -2222,6 +2238,12 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
2222
2238
  Object.assign(whereParams, constraints);
2223
2239
  }
2224
2240
  }
2241
+ if (hasVersionDrafts(this.collectionConfig) && !this.context.overrideAccess) {
2242
+ const canSeeDrafts = await this.canReadDrafts();
2243
+ if (!canSeeDrafts) {
2244
+ whereParams["_status"] = "published";
2245
+ }
2246
+ }
2225
2247
  const query = {
2226
2248
  ...queryOptions,
2227
2249
  ...whereParams,
@@ -2284,6 +2306,15 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
2284
2306
  doc[softDeleteField]) {
2285
2307
  return null;
2286
2308
  }
2309
+ if (hasVersionDrafts(this.collectionConfig) && !this.context.overrideAccess) {
2310
+ const canSeeDrafts = await this.canReadDrafts();
2311
+ if (!canSeeDrafts) {
2312
+ const record = doc;
2313
+ if (record["_status"] !== "published") {
2314
+ return null;
2315
+ }
2316
+ }
2317
+ }
2287
2318
  if (!this.matchesDefaultWhereConstraints(doc)) {
2288
2319
  return null;
2289
2320
  }
@@ -2369,6 +2400,15 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
2369
2400
  if (!this.matchesDefaultWhereConstraints(originalDoc)) {
2370
2401
  throw new DocumentNotFoundError(this.slug, id);
2371
2402
  }
2403
+ if (hasVersionDrafts(this.collectionConfig) && this.adapter.createVersion) {
2404
+ const status = originalDoc["_status"] ?? "draft";
2405
+ await this.adapter.createVersion(this.slug, id, originalDoc, { status });
2406
+ const versionsConfig = this.collectionConfig.versions;
2407
+ const maxPerDoc = typeof versionsConfig === "object" && versionsConfig !== null ? versionsConfig.maxPerDoc : void 0;
2408
+ if (maxPerDoc && this.adapter.deleteVersions) {
2409
+ await this.adapter.deleteVersions(this.slug, id, maxPerDoc);
2410
+ }
2411
+ }
2372
2412
  let processedData = data;
2373
2413
  const softDeleteField = getSoftDeleteField(this.collectionConfig);
2374
2414
  if (softDeleteField && softDeleteField in processedData) {
@@ -2700,6 +2740,30 @@ var CollectionOperationsImpl = class _CollectionOperationsImpl {
2700
2740
  throw new AccessDeniedError(operation, this.slug);
2701
2741
  }
2702
2742
  }
2743
+ /**
2744
+ * Check if the current user can see draft documents (non-throwing).
2745
+ * Uses `access.readDrafts` if configured, otherwise falls back to `access.update`.
2746
+ */
2747
+ async canReadDrafts() {
2748
+ if (!this.context.user)
2749
+ return false;
2750
+ const readDraftsFn = this.collectionConfig.access?.readDrafts;
2751
+ if (readDraftsFn) {
2752
+ try {
2753
+ return !!await Promise.resolve(readDraftsFn({ req: this.buildRequestContext() }));
2754
+ } catch {
2755
+ return false;
2756
+ }
2757
+ }
2758
+ const updateFn = this.collectionConfig.access?.update;
2759
+ if (!updateFn)
2760
+ return true;
2761
+ try {
2762
+ return !!await Promise.resolve(updateFn({ req: this.buildRequestContext() }));
2763
+ } catch {
2764
+ return false;
2765
+ }
2766
+ }
2703
2767
  buildRequestContext() {
2704
2768
  return {
2705
2769
  user: this.context.user
@@ -3392,8 +3456,9 @@ function buildGraphQLSchema(collections) {
3392
3456
  }
3393
3457
  function getOrCreateEnum(field, parentName) {
3394
3458
  const key = `${parentName}_${field.name}`;
3395
- if (enumCache.has(key)) {
3396
- return enumCache.get(key);
3459
+ const cached = enumCache.get(key);
3460
+ if (cached) {
3461
+ return cached;
3397
3462
  }
3398
3463
  const values = {};
3399
3464
  for (const opt of field.options) {
@@ -3504,8 +3569,9 @@ function buildGraphQLSchema(collections) {
3504
3569
  }
3505
3570
  }
3506
3571
  function getOrCreateObjectType(fields, typeName) {
3507
- if (typeCache.has(typeName)) {
3508
- return typeCache.get(typeName);
3572
+ const cachedType = typeCache.get(typeName);
3573
+ if (cachedType) {
3574
+ return cachedType;
3509
3575
  }
3510
3576
  const objType = new GraphQLObjectType({
3511
3577
  name: typeName,
@@ -3526,8 +3592,9 @@ function buildGraphQLSchema(collections) {
3526
3592
  }
3527
3593
  function getOrCreateInputType(fields, typeName) {
3528
3594
  const inputName = `${typeName}Input`;
3529
- if (inputCache.has(inputName)) {
3530
- return inputCache.get(inputName);
3595
+ const cachedInput = inputCache.get(inputName);
3596
+ if (cachedInput) {
3597
+ return cachedInput;
3531
3598
  }
3532
3599
  const inputType = new GraphQLInputObjectType({
3533
3600
  name: inputName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momentumcms/server-analog",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Nitro/h3 adapter for Momentum CMS with Analog.js support",
5
5
  "license": "MIT",
6
6
  "author": "Momentum CMS Contributors",