@valbuild/server 0.144.12 → 0.145.1

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,5 +1,30 @@
1
1
  # @valbuild/server
2
2
 
3
+ ## 0.145.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`a45f595`](https://github.com/valbuild/val/commit/a45f595a5e20b009d4110bbef8ebdc08b2d731d7)]:
8
+ - @valbuild/shared@0.145.1
9
+ - @valbuild/ui@0.145.1
10
+
11
+ ## 0.145.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [#859](https://github.com/valbuild/val/pull/859) [`f085be0`](https://github.com/valbuild/val/commit/f085be0eb5bdc195e9d8cdb15dd5f8acfdabe23c) Thanks [@freekh](https://github.com/freekh)! - An edit Val Build refuses to save because of the project's plan — the Free plan's 1,000 changes a week are used, or a Hosted trial has ended — is now kept in the Studio instead of being reverted.
16
+
17
+ - `PUT /patches` answers such a save with a `403` of type `plan-refused`, carrying Val Build's reason and fix as data and which patches of the request it did save. It used to answer `400 patch-error`, which the Studio reads as a bad patch and drops.
18
+ - The Studio keeps the refused edits and any made after them, shows the plan notice with **Upgrade** or **Add a card** beside it, and saves them by itself once the plan allows it: as soon as Val Build says editing is open again (an owner added a card, the week moved on), and otherwise by trying again now and then. A publish or a restore that meets held edits says why, in Val Build's words, instead of suggesting the connection.
19
+ - The MCP write tools answer a refused write as `forbidden`, with Val Build's sentence, instead of `internal`.
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [[`b6cb939`](https://github.com/valbuild/val/commit/b6cb9395d8bdcd5182e9c6ba84f5284930de2fa5), [`f085be0`](https://github.com/valbuild/val/commit/f085be0eb5bdc195e9d8cdb15dd5f8acfdabe23c), [`dda5c52`](https://github.com/valbuild/val/commit/dda5c523698395c6dfb96ae8e39dae04307ec332), [`ac0bb7c`](https://github.com/valbuild/val/commit/ac0bb7cb5a99df022b198326a5f8a0cf61e45388)]:
24
+ - @valbuild/core@0.145.0
25
+ - @valbuild/shared@0.145.0
26
+ - @valbuild/ui@0.145.0
27
+
3
28
  ## 0.144.12
4
29
 
5
30
  ### Patch Changes
@@ -2,7 +2,7 @@ import { MediaSource, FileMetadata, FileSource, ImageMetadata, ModuleFilePath, P
2
2
  import { result } from "@valbuild/core/fp";
3
3
  import { JSONValue, ParentRef, Patch, PatchError } from "@valbuild/core/patch";
4
4
  import type { HistoryError } from "./history/HistoryError.js";
5
- import type { PatchGroupT } from "@valbuild/shared/internal";
5
+ import type { PatchGroupT, PlanRefusalErrorT } from "@valbuild/shared/internal";
6
6
  import type { AffectedFile, StoredModuleVersion, CommitPage, CommitPatch, HistoricalCommit } from "./history/types.js";
7
7
  import { ValSyntaxError, ValSyntaxErrorTree } from "./patch/ts/syntax.js";
8
8
  import { ParentPatchId } from "@valbuild/core";
@@ -456,7 +456,7 @@ export declare abstract class ValOps {
456
456
  error: GenericErrorMessage;
457
457
  } | {
458
458
  errorType: "patch-head-conflict";
459
- }>>;
459
+ } | PlanRefusedError>>;
460
460
  /**
461
461
  * Why a publish cannot happen here, or `null` when one can.
462
462
  *
@@ -789,7 +789,21 @@ export type SaveSourceFilePatchResult = result.Result<{
789
789
  errorType: "other";
790
790
  } & GenericErrorMessage) | {
791
791
  errorType: "patch-head-conflict";
792
- }>;
792
+ } | PlanRefusedError>;
793
+ /**
794
+ * The content API refused a write for the project's plan (a 403 that says why
795
+ * as data), as opposed to refusing the patch.
796
+ *
797
+ * Its own error rather than an `other`: an `other` becomes a 400, and the
798
+ * Studio drops a patch it is told is bad. This one is good, and is saved once
799
+ * the plan allows it. `error` has the same shape as `other`'s so a caller that
800
+ * only wants a sentence reads it the same way.
801
+ */
802
+ export type PlanRefusedError = {
803
+ errorType: "plan-refused";
804
+ error: GenericErrorMessage;
805
+ refusal: PlanRefusalErrorT;
806
+ };
793
807
  export type PatchAnalysis = {
794
808
  patchesByModule: {
795
809
  [path: ModuleFilePath]: {
@@ -5639,6 +5639,11 @@ class ValOps {
5639
5639
  patchGroup) {
5640
5640
  const saveRes = await this.saveSourceFilePatch(path, patch, patchId, parentRef, authorId, sessionId, patchGroup);
5641
5641
  if (fp.result.isErr(saveRes)) {
5642
+ if (saveRes.error.errorType === "plan-refused") {
5643
+ // The project's plan, not a failure: the Studio keeps the edit and
5644
+ // sends it again later, so an error line here would be one a minute.
5645
+ return fp.result.err(saveRes.error);
5646
+ }
5642
5647
  console.error(`Could not save source patch at path: '${path}'. Error: ${saveRes.error.errorType === "other" ? saveRes.error.message : saveRes.error.errorType}`);
5643
5648
  if (saveRes.error.errorType === "patch-head-conflict") {
5644
5649
  return fp.result.err({
@@ -5965,6 +5970,16 @@ function isFileSource(value) {
5965
5970
  * after the fact.
5966
5971
  */
5967
5972
 
5973
+ /**
5974
+ * The content API refused a write for the project's plan (a 403 that says why
5975
+ * as data), as opposed to refusing the patch.
5976
+ *
5977
+ * Its own error rather than an `other`: an `other` becomes a 400, and the
5978
+ * Studio drops a patch it is told is bad. This one is good, and is saved once
5979
+ * the plan allows it. `error` has the same shape as `other`'s so a caller that
5980
+ * only wants a sentence reads it the same way.
5981
+ */
5982
+
5968
5983
  function formatPatchSourceError(error) {
5969
5984
  if ("message" in error) {
5970
5985
  return error.message;
@@ -9371,6 +9386,11 @@ function isJsonValue(value) {
9371
9386
  }
9372
9387
 
9373
9388
  const textEncoder$2 = new TextEncoder();
9389
+
9390
+ /** The body of the content API's 403 for a write the project's plan refuses. */
9391
+ const PlanRefusedBody = z.z.object({
9392
+ error: internal.PlanRefusalError
9393
+ });
9374
9394
  const PatchId = z.z.string().refine(s => !!s); // TODO: validate
9375
9395
  const CommitSha = z.z.string().refine(s => !!s); // TODO: validate
9376
9396
  z.z.string().refine(s => !!s); // TODO: validate
@@ -11395,6 +11415,22 @@ class ValOpsHttp extends ValOps {
11395
11415
  if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
11396
11416
  const json = await res.json();
11397
11417
  const message = internal.getErrorMessageFromUnknownJson(json, "Unknown error");
11418
+ /*
11419
+ * Refused for the plan: the patch is fine, and the reason comes as
11420
+ * data. Kept apart from every other error, which the Studio is told
11421
+ * is a bad patch and drops. A 403 without a refusal in it (a
11422
+ * credential missing the write scope) is still one of those.
11423
+ */
11424
+ const refusal = res.status === 403 ? PlanRefusedBody.safeParse(json) : null;
11425
+ if (refusal !== null && refusal !== void 0 && refusal.success) {
11426
+ return fp.result.err({
11427
+ errorType: "plan-refused",
11428
+ error: {
11429
+ message
11430
+ },
11431
+ refusal: refusal.data.error
11432
+ });
11433
+ }
11398
11434
  return fp.result.err({
11399
11435
  errorType: "other",
11400
11436
  message
@@ -15541,6 +15577,24 @@ const ValServer = (valModules, options, callbacks) => {
15541
15577
  * `fs` mode and from an older content API.
15542
15578
  */
15543
15579
  let headVersion;
15580
+ /*
15581
+ * What this request has saved so far: the whole answer to a save, and
15582
+ * the saved part of one refused for the plan. One builder for both, so
15583
+ * the client records a partly saved batch exactly as a saved one.
15584
+ */
15585
+ const savedSoFar = () => ({
15586
+ newPatchIds,
15587
+ parentRef,
15588
+ // Absent rather than null where there are no groups: `fs` mode and
15589
+ // a content API that predates them both answer without one, and the
15590
+ // client reads absence as "staging is not available here".
15591
+ ...(patchGroupIdFromStore !== undefined ? {
15592
+ patchGroupId: patchGroupIdFromStore
15593
+ } : {}),
15594
+ ...(headVersion !== undefined ? {
15595
+ headVersion
15596
+ } : {})
15597
+ });
15544
15598
  for (const patch of patches) {
15545
15599
  const createPatchRes = await serverOps.createPatch(patch.path, patch.patch, patch.patchId, parentRef, sessionId, authorId, patchGroup);
15546
15600
  if (fp.result.isErr(createPatchRes)) {
@@ -15552,6 +15606,23 @@ const ValServer = (valModules, options, callbacks) => {
15552
15606
  message: "The change was written against a different starting point than the server has."
15553
15607
  }
15554
15608
  };
15609
+ } else if (createPatchRes.error.errorType === "plan-refused") {
15610
+ /*
15611
+ * Val Build refused it for the plan. Passed on as its 403 rather
15612
+ * than a patch error: the patch is fine and the Studio keeps it,
15613
+ * and the reason travels as data so the fix can sit beside it.
15614
+ * The patches before this one in the batch ARE saved, and are
15615
+ * reported as a 200 would report them.
15616
+ */
15617
+ return {
15618
+ status: 403,
15619
+ json: {
15620
+ type: "plan-refused",
15621
+ message: createPatchRes.error.error.message,
15622
+ error: createPatchRes.error.refusal,
15623
+ ...savedSoFar()
15624
+ }
15625
+ };
15555
15626
  } else {
15556
15627
  return {
15557
15628
  status: 400,
@@ -15582,19 +15653,7 @@ const ValServer = (valModules, options, callbacks) => {
15582
15653
  }
15583
15654
  return {
15584
15655
  status: 200,
15585
- json: {
15586
- newPatchIds,
15587
- parentRef,
15588
- // Absent rather than null where there are no groups: `fs` mode and
15589
- // a content API that predates them both answer without one, and the
15590
- // client reads absence as "staging is not available here".
15591
- ...(patchGroupIdFromStore !== undefined ? {
15592
- patchGroupId: patchGroupIdFromStore
15593
- } : {}),
15594
- ...(headVersion !== undefined ? {
15595
- headVersion
15596
- } : {})
15597
- }
15656
+ json: savedSoFar()
15598
15657
  };
15599
15658
  },
15600
15659
  GET: async req => {
@@ -5639,6 +5639,11 @@ class ValOps {
5639
5639
  patchGroup) {
5640
5640
  const saveRes = await this.saveSourceFilePatch(path, patch, patchId, parentRef, authorId, sessionId, patchGroup);
5641
5641
  if (fp.result.isErr(saveRes)) {
5642
+ if (saveRes.error.errorType === "plan-refused") {
5643
+ // The project's plan, not a failure: the Studio keeps the edit and
5644
+ // sends it again later, so an error line here would be one a minute.
5645
+ return fp.result.err(saveRes.error);
5646
+ }
5642
5647
  console.error(`Could not save source patch at path: '${path}'. Error: ${saveRes.error.errorType === "other" ? saveRes.error.message : saveRes.error.errorType}`);
5643
5648
  if (saveRes.error.errorType === "patch-head-conflict") {
5644
5649
  return fp.result.err({
@@ -5965,6 +5970,16 @@ function isFileSource(value) {
5965
5970
  * after the fact.
5966
5971
  */
5967
5972
 
5973
+ /**
5974
+ * The content API refused a write for the project's plan (a 403 that says why
5975
+ * as data), as opposed to refusing the patch.
5976
+ *
5977
+ * Its own error rather than an `other`: an `other` becomes a 400, and the
5978
+ * Studio drops a patch it is told is bad. This one is good, and is saved once
5979
+ * the plan allows it. `error` has the same shape as `other`'s so a caller that
5980
+ * only wants a sentence reads it the same way.
5981
+ */
5982
+
5968
5983
  function formatPatchSourceError(error) {
5969
5984
  if ("message" in error) {
5970
5985
  return error.message;
@@ -9371,6 +9386,11 @@ function isJsonValue(value) {
9371
9386
  }
9372
9387
 
9373
9388
  const textEncoder$2 = new TextEncoder();
9389
+
9390
+ /** The body of the content API's 403 for a write the project's plan refuses. */
9391
+ const PlanRefusedBody = z.z.object({
9392
+ error: internal.PlanRefusalError
9393
+ });
9374
9394
  const PatchId = z.z.string().refine(s => !!s); // TODO: validate
9375
9395
  const CommitSha = z.z.string().refine(s => !!s); // TODO: validate
9376
9396
  z.z.string().refine(s => !!s); // TODO: validate
@@ -11395,6 +11415,22 @@ class ValOpsHttp extends ValOps {
11395
11415
  if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
11396
11416
  const json = await res.json();
11397
11417
  const message = internal.getErrorMessageFromUnknownJson(json, "Unknown error");
11418
+ /*
11419
+ * Refused for the plan: the patch is fine, and the reason comes as
11420
+ * data. Kept apart from every other error, which the Studio is told
11421
+ * is a bad patch and drops. A 403 without a refusal in it (a
11422
+ * credential missing the write scope) is still one of those.
11423
+ */
11424
+ const refusal = res.status === 403 ? PlanRefusedBody.safeParse(json) : null;
11425
+ if (refusal !== null && refusal !== void 0 && refusal.success) {
11426
+ return fp.result.err({
11427
+ errorType: "plan-refused",
11428
+ error: {
11429
+ message
11430
+ },
11431
+ refusal: refusal.data.error
11432
+ });
11433
+ }
11398
11434
  return fp.result.err({
11399
11435
  errorType: "other",
11400
11436
  message
@@ -15541,6 +15577,24 @@ const ValServer = (valModules, options, callbacks) => {
15541
15577
  * `fs` mode and from an older content API.
15542
15578
  */
15543
15579
  let headVersion;
15580
+ /*
15581
+ * What this request has saved so far: the whole answer to a save, and
15582
+ * the saved part of one refused for the plan. One builder for both, so
15583
+ * the client records a partly saved batch exactly as a saved one.
15584
+ */
15585
+ const savedSoFar = () => ({
15586
+ newPatchIds,
15587
+ parentRef,
15588
+ // Absent rather than null where there are no groups: `fs` mode and
15589
+ // a content API that predates them both answer without one, and the
15590
+ // client reads absence as "staging is not available here".
15591
+ ...(patchGroupIdFromStore !== undefined ? {
15592
+ patchGroupId: patchGroupIdFromStore
15593
+ } : {}),
15594
+ ...(headVersion !== undefined ? {
15595
+ headVersion
15596
+ } : {})
15597
+ });
15544
15598
  for (const patch of patches) {
15545
15599
  const createPatchRes = await serverOps.createPatch(patch.path, patch.patch, patch.patchId, parentRef, sessionId, authorId, patchGroup);
15546
15600
  if (fp.result.isErr(createPatchRes)) {
@@ -15552,6 +15606,23 @@ const ValServer = (valModules, options, callbacks) => {
15552
15606
  message: "The change was written against a different starting point than the server has."
15553
15607
  }
15554
15608
  };
15609
+ } else if (createPatchRes.error.errorType === "plan-refused") {
15610
+ /*
15611
+ * Val Build refused it for the plan. Passed on as its 403 rather
15612
+ * than a patch error: the patch is fine and the Studio keeps it,
15613
+ * and the reason travels as data so the fix can sit beside it.
15614
+ * The patches before this one in the batch ARE saved, and are
15615
+ * reported as a 200 would report them.
15616
+ */
15617
+ return {
15618
+ status: 403,
15619
+ json: {
15620
+ type: "plan-refused",
15621
+ message: createPatchRes.error.error.message,
15622
+ error: createPatchRes.error.refusal,
15623
+ ...savedSoFar()
15624
+ }
15625
+ };
15555
15626
  } else {
15556
15627
  return {
15557
15628
  status: 400,
@@ -15582,19 +15653,7 @@ const ValServer = (valModules, options, callbacks) => {
15582
15653
  }
15583
15654
  return {
15584
15655
  status: 200,
15585
- json: {
15586
- newPatchIds,
15587
- parentRef,
15588
- // Absent rather than null where there are no groups: `fs` mode and
15589
- // a content API that predates them both answer without one, and the
15590
- // client reads absence as "staging is not available here".
15591
- ...(patchGroupIdFromStore !== undefined ? {
15592
- patchGroupId: patchGroupIdFromStore
15593
- } : {}),
15594
- ...(headVersion !== undefined ? {
15595
- headVersion
15596
- } : {})
15597
- }
15656
+ json: savedSoFar()
15598
15657
  };
15599
15658
  },
15600
15659
  GET: async req => {
@@ -8,7 +8,7 @@ import path__default from 'path';
8
8
  import fs from 'fs';
9
9
  import vm from 'node:vm';
10
10
  import { Module } from 'node:module';
11
- import { isSchemaSourceFixError, resolveSchemaSourceFixForError, Patch, getErrorMessageFromUnknownJson, PatchId as PatchId$1, JSONValue, PatchGroup, newestCommitSha, SerializedSchema, VAL_ENABLE_COOKIE_NAME, VAL_STATE_COOKIE, VAL_SESSION_COOKIE, parseJob, VAL_STUDIO_HEADER, Api, traverseSchemaSource, richTextImageSchema, forEachRichTextImage } from '@valbuild/shared/internal';
11
+ import { isSchemaSourceFixError, resolveSchemaSourceFixForError, Patch, getErrorMessageFromUnknownJson, PlanRefusalError, PatchId as PatchId$1, JSONValue, PatchGroup, newestCommitSha, SerializedSchema, VAL_ENABLE_COOKIE_NAME, VAL_STATE_COOKIE, VAL_SESSION_COOKIE, parseJob, VAL_STUDIO_HEADER, Api, traverseSchemaSource, richTextImageSchema, forEachRichTextImage } from '@valbuild/shared/internal';
12
12
  import { createUIRequestHandler } from '@valbuild/ui/server';
13
13
  import crypto$1 from 'crypto';
14
14
  import z$1, { z } from 'zod';
@@ -5602,6 +5602,11 @@ class ValOps {
5602
5602
  patchGroup) {
5603
5603
  const saveRes = await this.saveSourceFilePatch(path, patch, patchId, parentRef, authorId, sessionId, patchGroup);
5604
5604
  if (result.isErr(saveRes)) {
5605
+ if (saveRes.error.errorType === "plan-refused") {
5606
+ // The project's plan, not a failure: the Studio keeps the edit and
5607
+ // sends it again later, so an error line here would be one a minute.
5608
+ return result.err(saveRes.error);
5609
+ }
5605
5610
  console.error(`Could not save source patch at path: '${path}'. Error: ${saveRes.error.errorType === "other" ? saveRes.error.message : saveRes.error.errorType}`);
5606
5611
  if (saveRes.error.errorType === "patch-head-conflict") {
5607
5612
  return result.err({
@@ -5928,6 +5933,16 @@ function isFileSource(value) {
5928
5933
  * after the fact.
5929
5934
  */
5930
5935
 
5936
+ /**
5937
+ * The content API refused a write for the project's plan (a 403 that says why
5938
+ * as data), as opposed to refusing the patch.
5939
+ *
5940
+ * Its own error rather than an `other`: an `other` becomes a 400, and the
5941
+ * Studio drops a patch it is told is bad. This one is good, and is saved once
5942
+ * the plan allows it. `error` has the same shape as `other`'s so a caller that
5943
+ * only wants a sentence reads it the same way.
5944
+ */
5945
+
5931
5946
  function formatPatchSourceError(error) {
5932
5947
  if ("message" in error) {
5933
5948
  return error.message;
@@ -9334,6 +9349,11 @@ function isJsonValue(value) {
9334
9349
  }
9335
9350
 
9336
9351
  const textEncoder$2 = new TextEncoder();
9352
+
9353
+ /** The body of the content API's 403 for a write the project's plan refuses. */
9354
+ const PlanRefusedBody = z.object({
9355
+ error: PlanRefusalError
9356
+ });
9337
9357
  const PatchId = z.string().refine(s => !!s); // TODO: validate
9338
9358
  const CommitSha = z.string().refine(s => !!s); // TODO: validate
9339
9359
  z.string().refine(s => !!s); // TODO: validate
@@ -11358,6 +11378,22 @@ class ValOpsHttp extends ValOps {
11358
11378
  if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
11359
11379
  const json = await res.json();
11360
11380
  const message = getErrorMessageFromUnknownJson(json, "Unknown error");
11381
+ /*
11382
+ * Refused for the plan: the patch is fine, and the reason comes as
11383
+ * data. Kept apart from every other error, which the Studio is told
11384
+ * is a bad patch and drops. A 403 without a refusal in it (a
11385
+ * credential missing the write scope) is still one of those.
11386
+ */
11387
+ const refusal = res.status === 403 ? PlanRefusedBody.safeParse(json) : null;
11388
+ if (refusal !== null && refusal !== void 0 && refusal.success) {
11389
+ return result.err({
11390
+ errorType: "plan-refused",
11391
+ error: {
11392
+ message
11393
+ },
11394
+ refusal: refusal.data.error
11395
+ });
11396
+ }
11361
11397
  return result.err({
11362
11398
  errorType: "other",
11363
11399
  message
@@ -15504,6 +15540,24 @@ const ValServer = (valModules, options, callbacks) => {
15504
15540
  * `fs` mode and from an older content API.
15505
15541
  */
15506
15542
  let headVersion;
15543
+ /*
15544
+ * What this request has saved so far: the whole answer to a save, and
15545
+ * the saved part of one refused for the plan. One builder for both, so
15546
+ * the client records a partly saved batch exactly as a saved one.
15547
+ */
15548
+ const savedSoFar = () => ({
15549
+ newPatchIds,
15550
+ parentRef,
15551
+ // Absent rather than null where there are no groups: `fs` mode and
15552
+ // a content API that predates them both answer without one, and the
15553
+ // client reads absence as "staging is not available here".
15554
+ ...(patchGroupIdFromStore !== undefined ? {
15555
+ patchGroupId: patchGroupIdFromStore
15556
+ } : {}),
15557
+ ...(headVersion !== undefined ? {
15558
+ headVersion
15559
+ } : {})
15560
+ });
15507
15561
  for (const patch of patches) {
15508
15562
  const createPatchRes = await serverOps.createPatch(patch.path, patch.patch, patch.patchId, parentRef, sessionId, authorId, patchGroup);
15509
15563
  if (result.isErr(createPatchRes)) {
@@ -15515,6 +15569,23 @@ const ValServer = (valModules, options, callbacks) => {
15515
15569
  message: "The change was written against a different starting point than the server has."
15516
15570
  }
15517
15571
  };
15572
+ } else if (createPatchRes.error.errorType === "plan-refused") {
15573
+ /*
15574
+ * Val Build refused it for the plan. Passed on as its 403 rather
15575
+ * than a patch error: the patch is fine and the Studio keeps it,
15576
+ * and the reason travels as data so the fix can sit beside it.
15577
+ * The patches before this one in the batch ARE saved, and are
15578
+ * reported as a 200 would report them.
15579
+ */
15580
+ return {
15581
+ status: 403,
15582
+ json: {
15583
+ type: "plan-refused",
15584
+ message: createPatchRes.error.error.message,
15585
+ error: createPatchRes.error.refusal,
15586
+ ...savedSoFar()
15587
+ }
15588
+ };
15518
15589
  } else {
15519
15590
  return {
15520
15591
  status: 400,
@@ -15545,19 +15616,7 @@ const ValServer = (valModules, options, callbacks) => {
15545
15616
  }
15546
15617
  return {
15547
15618
  status: 200,
15548
- json: {
15549
- newPatchIds,
15550
- parentRef,
15551
- // Absent rather than null where there are no groups: `fs` mode and
15552
- // a content API that predates them both answer without one, and the
15553
- // client reads absence as "staging is not available here".
15554
- ...(patchGroupIdFromStore !== undefined ? {
15555
- patchGroupId: patchGroupIdFromStore
15556
- } : {}),
15557
- ...(headVersion !== undefined ? {
15558
- headVersion
15559
- } : {})
15560
- }
15619
+ json: savedSoFar()
15561
15620
  };
15562
15621
  },
15563
15622
  GET: async req => {
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "./package.json": "./package.json"
17
17
  },
18
18
  "types": "dist/valbuild-server.cjs.d.ts",
19
- "version": "0.144.12",
19
+ "version": "0.145.1",
20
20
  "devDependencies": {
21
21
  "@prettier/sync": "^0.6.1",
22
22
  "@types/jest": "^30.0.0",
@@ -30,9 +30,9 @@
30
30
  "typescript": "^6.0.3",
31
31
  "zod": "^4.4.3",
32
32
  "zod-validation-error": "^5.0.0",
33
- "@valbuild/core": "0.144.0",
34
- "@valbuild/shared": "0.144.9",
35
- "@valbuild/ui": "0.144.12"
33
+ "@valbuild/core": "0.145.0",
34
+ "@valbuild/shared": "0.145.1",
35
+ "@valbuild/ui": "0.145.1"
36
36
  },
37
37
  "engines": {
38
38
  "node": "^20.19.0 || >=22"