@valbuild/server 0.138.4 → 0.138.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @valbuild/server
2
2
 
3
+ ## 0.138.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [#774](https://github.com/valbuild/val/pull/774) [`9d28775`](https://github.com/valbuild/val/commit/9d287750631b239b70bc7545e3b9fa9011e81db7) Thanks [@freekh](https://github.com/freekh)! - Publishing from a phone is quicker to follow, and fails less.
8
+
9
+ - The builder tab closes once it has built and uploaded your change. Checking that the site renders and putting it live no longer need the tab, so you don't have to keep it open.
10
+ - After the builder tab closes you get one "Published" message, not three.
11
+ - If a publish fails, the builder tab gives the same reason as the Studio's message, not a vaguer one.
12
+ - If the builder tab is closed, or your phone pauses it in the background before it finishes, you're no longer stuck with Publish greyed out until you reload. After a short wait the Studio says the tab stopped answering, and pressing Publish again picks the publish up where it left off. Nothing is lost or published twice.
13
+ - A publish no longer fails with "This deployment cannot prepare a publish job for this project" when the site happens to answer from a server that hasn't loaded your changes yet.
14
+
15
+ - [#774](https://github.com/valbuild/val/pull/774) [`9d28775`](https://github.com/valbuild/val/commit/9d287750631b239b70bc7545e3b9fa9011e81db7) Thanks [@freekh](https://github.com/freekh)! - Edits no longer disappear from a site on Val Build for up to a minute after its first publish.
16
+
17
+ For a short while after a publish, the site can still serve the previous build. If that build was the project's starting template, it was treated as though it already had the new changes, so they vanished from the page until the new build reached you. Each build now tells Val's content service which build it is, and gets exactly the changes it is missing.
18
+
19
+ - Updated dependencies [[`9d28775`](https://github.com/valbuild/val/commit/9d287750631b239b70bc7545e3b9fa9011e81db7)]:
20
+ - @valbuild/ui@0.138.6
21
+
22
+ ## 0.138.5
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies [[`c532afc`](https://github.com/valbuild/val/commit/c532afc1818ee0249ad227a7da029c3e8d06baa8)]:
27
+ - @valbuild/ui@0.138.5
28
+
3
29
  ## 0.138.4
4
30
 
5
31
  ### Patch Changes
@@ -74,6 +74,8 @@ export declare class ValOpsHttp extends ValOps {
74
74
  private readonly projectSource;
75
75
  /** See `publishJob` on {@link ValApiOptions}; sent only with no commit. */
76
76
  private readonly publishJob;
77
+ /** See `publishBuild` on {@link ValApiOptions}; sent with every position. */
78
+ private readonly publishBuild;
77
79
  /** Did the host hand over the running build's source? See `projectSource`. */
78
80
  embedsSource(): boolean;
79
81
  /**
@@ -142,6 +144,8 @@ export declare class ValOpsHttp extends ValOps {
142
144
  projectSource?: Record<string, string>;
143
145
  /** See `publishJob` on {@link ValApiOptions}. */
144
146
  publishJob?: string;
147
+ /** See `publishBuild` on {@link ValApiOptions}. */
148
+ publishBuild?: string;
145
149
  });
146
150
  /**
147
151
  * A deployment that cannot mirror a project which expects to be mirrored.
@@ -188,6 +192,20 @@ export declare class ValOpsHttp extends ValOps {
188
192
  * a connected one content says is hosted on the platform (its CI publishes
189
193
  * through content). `false` before anything has been heard.
190
194
  */
195
+ /**
196
+ * Ask the content service what this project expects of its publisher, when
197
+ * nothing has been heard yet.
198
+ *
199
+ * What {@link publishesAsJobs} and {@link sourceMode} read is remembered
200
+ * from the overlay this server last fetched, and a server that has fetched
201
+ * none has heard nothing. That is not rare: the platform runs a site in many
202
+ * isolates, each with a Val server of its own, so a publish's prepare can
203
+ * reach one that has never served an overlay. It was refused ("This
204
+ * deployment cannot prepare a publish job") as though the project did not
205
+ * publish as jobs at all. Best effort: a content service that does not
206
+ * answer leaves it unheard, and the caller refuses as before.
207
+ */
208
+ learnProjectExpectation(): Promise<void>;
191
209
  publishesAsJobs(): boolean;
192
210
  /**
193
211
  * The short-lived publish token, and when it stops being usable.
@@ -147,6 +147,15 @@ type ValServerOverrides = Partial<{
147
147
  * that rather than at whichever build is live.
148
148
  */
149
149
  publishJob?: string;
150
+ /**
151
+ * The build the platform is running this server in, by its hash, when a
152
+ * platform says (`VAL_BUILD`). Sent with every position this server asks
153
+ * the content service about, because it is the one thing that says WHICH
154
+ * build is asking: after a publish, an edge can keep serving the previous
155
+ * build for up to a minute, and without it that build is placed at the new
156
+ * one -- whose changes it does not hold, so they drop out of the overlay.
157
+ */
158
+ publishBuild?: string;
150
159
  /**
151
160
  * The base url of Val.
152
161
  *
@@ -143,6 +143,8 @@ export type ValServerConfig = ValServerOptions & ({
143
143
  projectSource?: Record<string, string>;
144
144
  /** See `publishJob` on {@link ValApiOptions}. */
145
145
  publishJob?: string;
146
+ /** See `publishBuild` on {@link ValApiOptions}. */
147
+ publishBuild?: string;
146
148
  config: ValConfig;
147
149
  }
148
150
  /**
@@ -8640,6 +8640,8 @@ class ValOpsHttp extends ValOps {
8640
8640
  projectSource;
8641
8641
  /** See `publishJob` on {@link ValApiOptions}; sent only with no commit. */
8642
8642
  publishJob;
8643
+ /** See `publishBuild` on {@link ValApiOptions}; sent with every position. */
8644
+ publishBuild;
8643
8645
 
8644
8646
  /** Did the host hand over the running build's source? See `projectSource`. */
8645
8647
  embedsSource() {
@@ -8724,6 +8726,7 @@ class ValOpsHttp extends ValOps {
8724
8726
  this.root = (options === null || options === void 0 ? void 0 : options.root) ?? "";
8725
8727
  this.projectSource = (options === null || options === void 0 ? void 0 : options.projectSource) ?? null;
8726
8728
  this.publishJob = (options === null || options === void 0 ? void 0 : options.publishJob) ?? null;
8729
+ this.publishBuild = (options === null || options === void 0 ? void 0 : options.publishBuild) ?? null;
8727
8730
  this.mirrorsSourceFiles = git !== null || this.projectSource !== null;
8728
8731
  }
8729
8732
  /**
@@ -8801,6 +8804,25 @@ class ValOpsHttp extends ValOps {
8801
8804
  * a connected one content says is hosted on the platform (its CI publishes
8802
8805
  * through content). `false` before anything has been heard.
8803
8806
  */
8807
+ /**
8808
+ * Ask the content service what this project expects of its publisher, when
8809
+ * nothing has been heard yet.
8810
+ *
8811
+ * What {@link publishesAsJobs} and {@link sourceMode} read is remembered
8812
+ * from the overlay this server last fetched, and a server that has fetched
8813
+ * none has heard nothing. That is not rare: the platform runs a site in many
8814
+ * isolates, each with a Val server of its own, so a publish's prepare can
8815
+ * reach one that has never served an overlay. It was refused ("This
8816
+ * deployment cannot prepare a publish job") as though the project did not
8817
+ * publish as jobs at all. Best effort: a content service that does not
8818
+ * answer leaves it unheard, and the caller refuses as before.
8819
+ */
8820
+ async learnProjectExpectation() {
8821
+ if (this.projectExpectation !== null) return;
8822
+ await this.fetchPatchesInternal({
8823
+ excludePatchOps: true
8824
+ }).catch(() => undefined);
8825
+ }
8804
8826
  publishesAsJobs() {
8805
8827
  const expected = this.projectExpectation;
8806
8828
  if (expected === null) return false;
@@ -9254,6 +9276,10 @@ class ValOpsHttp extends ValOps {
9254
9276
  commitSha: this.git.commit
9255
9277
  } : this.publishJob !== null ? {
9256
9278
  job: this.publishJob
9279
+ } : {}),
9280
+ // Which build is asking, beside what it says about itself.
9281
+ ...(this.publishBuild !== null ? {
9282
+ build: this.publishBuild
9257
9283
  } : {})
9258
9284
  }),
9259
9285
  headers: {
@@ -9439,6 +9465,16 @@ class ValOpsHttp extends ValOps {
9439
9465
  // A build a tab made has no commit, and says which job it was made for.
9440
9466
  params.push(["job", this.publishJob]);
9441
9467
  }
9468
+ /*
9469
+ * And WHICH build this is, when the platform running it says: the only
9470
+ * thing that places a build the edge still serves after a publish, which
9471
+ * the service would otherwise take to be the new one. Sent with the commit
9472
+ * or the job, which still say where a build is that the service has no
9473
+ * publish of.
9474
+ */
9475
+ if (this.publishBuild !== null) {
9476
+ params.push(["build", this.publishBuild]);
9477
+ }
9442
9478
  if (filters.patchIds) {
9443
9479
  for (const patchId of filters.patchIds) {
9444
9480
  params.push(["patch_id", patchId]);
@@ -12178,6 +12214,9 @@ async function initHandlerOptions(route, opts, config) {
12178
12214
  ...(opts.publishJob !== undefined ? {
12179
12215
  publishJob: opts.publishJob
12180
12216
  } : {}),
12217
+ ...(opts.publishBuild !== undefined ? {
12218
+ publishBuild: opts.publishBuild
12219
+ } : {}),
12181
12220
  project: maybeValProject,
12182
12221
  valEnableRedirectUrl,
12183
12222
  valDisableRedirectUrl,
@@ -12250,6 +12289,9 @@ function createValOps(valModules, options) {
12250
12289
  } : {}),
12251
12290
  ...(options.publishJob !== undefined ? {
12252
12291
  publishJob: options.publishJob
12292
+ } : {}),
12293
+ ...(options.publishBuild !== undefined ? {
12294
+ publishBuild: options.publishBuild
12253
12295
  } : {})
12254
12296
  });
12255
12297
  }
@@ -14323,6 +14365,10 @@ const ValServer = (valModules, options, callbacks) => {
14323
14365
  }
14324
14366
  };
14325
14367
  }
14368
+ // A fresh isolate's server has heard nothing yet: ask, rather than refuse.
14369
+ if (serverOps instanceof ValOpsHttp) {
14370
+ await serverOps.learnProjectExpectation();
14371
+ }
14326
14372
  if (!(serverOps instanceof ValOpsHttp) || !serverOps.publishesAsJobs() || serverOps.sourceMode() === "managed" && !serverOps.embedsSource()) {
14327
14373
  return {
14328
14374
  status: 409,
@@ -8640,6 +8640,8 @@ class ValOpsHttp extends ValOps {
8640
8640
  projectSource;
8641
8641
  /** See `publishJob` on {@link ValApiOptions}; sent only with no commit. */
8642
8642
  publishJob;
8643
+ /** See `publishBuild` on {@link ValApiOptions}; sent with every position. */
8644
+ publishBuild;
8643
8645
 
8644
8646
  /** Did the host hand over the running build's source? See `projectSource`. */
8645
8647
  embedsSource() {
@@ -8724,6 +8726,7 @@ class ValOpsHttp extends ValOps {
8724
8726
  this.root = (options === null || options === void 0 ? void 0 : options.root) ?? "";
8725
8727
  this.projectSource = (options === null || options === void 0 ? void 0 : options.projectSource) ?? null;
8726
8728
  this.publishJob = (options === null || options === void 0 ? void 0 : options.publishJob) ?? null;
8729
+ this.publishBuild = (options === null || options === void 0 ? void 0 : options.publishBuild) ?? null;
8727
8730
  this.mirrorsSourceFiles = git !== null || this.projectSource !== null;
8728
8731
  }
8729
8732
  /**
@@ -8801,6 +8804,25 @@ class ValOpsHttp extends ValOps {
8801
8804
  * a connected one content says is hosted on the platform (its CI publishes
8802
8805
  * through content). `false` before anything has been heard.
8803
8806
  */
8807
+ /**
8808
+ * Ask the content service what this project expects of its publisher, when
8809
+ * nothing has been heard yet.
8810
+ *
8811
+ * What {@link publishesAsJobs} and {@link sourceMode} read is remembered
8812
+ * from the overlay this server last fetched, and a server that has fetched
8813
+ * none has heard nothing. That is not rare: the platform runs a site in many
8814
+ * isolates, each with a Val server of its own, so a publish's prepare can
8815
+ * reach one that has never served an overlay. It was refused ("This
8816
+ * deployment cannot prepare a publish job") as though the project did not
8817
+ * publish as jobs at all. Best effort: a content service that does not
8818
+ * answer leaves it unheard, and the caller refuses as before.
8819
+ */
8820
+ async learnProjectExpectation() {
8821
+ if (this.projectExpectation !== null) return;
8822
+ await this.fetchPatchesInternal({
8823
+ excludePatchOps: true
8824
+ }).catch(() => undefined);
8825
+ }
8804
8826
  publishesAsJobs() {
8805
8827
  const expected = this.projectExpectation;
8806
8828
  if (expected === null) return false;
@@ -9254,6 +9276,10 @@ class ValOpsHttp extends ValOps {
9254
9276
  commitSha: this.git.commit
9255
9277
  } : this.publishJob !== null ? {
9256
9278
  job: this.publishJob
9279
+ } : {}),
9280
+ // Which build is asking, beside what it says about itself.
9281
+ ...(this.publishBuild !== null ? {
9282
+ build: this.publishBuild
9257
9283
  } : {})
9258
9284
  }),
9259
9285
  headers: {
@@ -9439,6 +9465,16 @@ class ValOpsHttp extends ValOps {
9439
9465
  // A build a tab made has no commit, and says which job it was made for.
9440
9466
  params.push(["job", this.publishJob]);
9441
9467
  }
9468
+ /*
9469
+ * And WHICH build this is, when the platform running it says: the only
9470
+ * thing that places a build the edge still serves after a publish, which
9471
+ * the service would otherwise take to be the new one. Sent with the commit
9472
+ * or the job, which still say where a build is that the service has no
9473
+ * publish of.
9474
+ */
9475
+ if (this.publishBuild !== null) {
9476
+ params.push(["build", this.publishBuild]);
9477
+ }
9442
9478
  if (filters.patchIds) {
9443
9479
  for (const patchId of filters.patchIds) {
9444
9480
  params.push(["patch_id", patchId]);
@@ -12178,6 +12214,9 @@ async function initHandlerOptions(route, opts, config) {
12178
12214
  ...(opts.publishJob !== undefined ? {
12179
12215
  publishJob: opts.publishJob
12180
12216
  } : {}),
12217
+ ...(opts.publishBuild !== undefined ? {
12218
+ publishBuild: opts.publishBuild
12219
+ } : {}),
12181
12220
  project: maybeValProject,
12182
12221
  valEnableRedirectUrl,
12183
12222
  valDisableRedirectUrl,
@@ -12250,6 +12289,9 @@ function createValOps(valModules, options) {
12250
12289
  } : {}),
12251
12290
  ...(options.publishJob !== undefined ? {
12252
12291
  publishJob: options.publishJob
12292
+ } : {}),
12293
+ ...(options.publishBuild !== undefined ? {
12294
+ publishBuild: options.publishBuild
12253
12295
  } : {})
12254
12296
  });
12255
12297
  }
@@ -14323,6 +14365,10 @@ const ValServer = (valModules, options, callbacks) => {
14323
14365
  }
14324
14366
  };
14325
14367
  }
14368
+ // A fresh isolate's server has heard nothing yet: ask, rather than refuse.
14369
+ if (serverOps instanceof ValOpsHttp) {
14370
+ await serverOps.learnProjectExpectation();
14371
+ }
14326
14372
  if (!(serverOps instanceof ValOpsHttp) || !serverOps.publishesAsJobs() || serverOps.sourceMode() === "managed" && !serverOps.embedsSource()) {
14327
14373
  return {
14328
14374
  status: 409,
@@ -8603,6 +8603,8 @@ class ValOpsHttp extends ValOps {
8603
8603
  projectSource;
8604
8604
  /** See `publishJob` on {@link ValApiOptions}; sent only with no commit. */
8605
8605
  publishJob;
8606
+ /** See `publishBuild` on {@link ValApiOptions}; sent with every position. */
8607
+ publishBuild;
8606
8608
 
8607
8609
  /** Did the host hand over the running build's source? See `projectSource`. */
8608
8610
  embedsSource() {
@@ -8687,6 +8689,7 @@ class ValOpsHttp extends ValOps {
8687
8689
  this.root = (options === null || options === void 0 ? void 0 : options.root) ?? "";
8688
8690
  this.projectSource = (options === null || options === void 0 ? void 0 : options.projectSource) ?? null;
8689
8691
  this.publishJob = (options === null || options === void 0 ? void 0 : options.publishJob) ?? null;
8692
+ this.publishBuild = (options === null || options === void 0 ? void 0 : options.publishBuild) ?? null;
8690
8693
  this.mirrorsSourceFiles = git !== null || this.projectSource !== null;
8691
8694
  }
8692
8695
  /**
@@ -8764,6 +8767,25 @@ class ValOpsHttp extends ValOps {
8764
8767
  * a connected one content says is hosted on the platform (its CI publishes
8765
8768
  * through content). `false` before anything has been heard.
8766
8769
  */
8770
+ /**
8771
+ * Ask the content service what this project expects of its publisher, when
8772
+ * nothing has been heard yet.
8773
+ *
8774
+ * What {@link publishesAsJobs} and {@link sourceMode} read is remembered
8775
+ * from the overlay this server last fetched, and a server that has fetched
8776
+ * none has heard nothing. That is not rare: the platform runs a site in many
8777
+ * isolates, each with a Val server of its own, so a publish's prepare can
8778
+ * reach one that has never served an overlay. It was refused ("This
8779
+ * deployment cannot prepare a publish job") as though the project did not
8780
+ * publish as jobs at all. Best effort: a content service that does not
8781
+ * answer leaves it unheard, and the caller refuses as before.
8782
+ */
8783
+ async learnProjectExpectation() {
8784
+ if (this.projectExpectation !== null) return;
8785
+ await this.fetchPatchesInternal({
8786
+ excludePatchOps: true
8787
+ }).catch(() => undefined);
8788
+ }
8767
8789
  publishesAsJobs() {
8768
8790
  const expected = this.projectExpectation;
8769
8791
  if (expected === null) return false;
@@ -9217,6 +9239,10 @@ class ValOpsHttp extends ValOps {
9217
9239
  commitSha: this.git.commit
9218
9240
  } : this.publishJob !== null ? {
9219
9241
  job: this.publishJob
9242
+ } : {}),
9243
+ // Which build is asking, beside what it says about itself.
9244
+ ...(this.publishBuild !== null ? {
9245
+ build: this.publishBuild
9220
9246
  } : {})
9221
9247
  }),
9222
9248
  headers: {
@@ -9402,6 +9428,16 @@ class ValOpsHttp extends ValOps {
9402
9428
  // A build a tab made has no commit, and says which job it was made for.
9403
9429
  params.push(["job", this.publishJob]);
9404
9430
  }
9431
+ /*
9432
+ * And WHICH build this is, when the platform running it says: the only
9433
+ * thing that places a build the edge still serves after a publish, which
9434
+ * the service would otherwise take to be the new one. Sent with the commit
9435
+ * or the job, which still say where a build is that the service has no
9436
+ * publish of.
9437
+ */
9438
+ if (this.publishBuild !== null) {
9439
+ params.push(["build", this.publishBuild]);
9440
+ }
9405
9441
  if (filters.patchIds) {
9406
9442
  for (const patchId of filters.patchIds) {
9407
9443
  params.push(["patch_id", patchId]);
@@ -12141,6 +12177,9 @@ async function initHandlerOptions(route, opts, config) {
12141
12177
  ...(opts.publishJob !== undefined ? {
12142
12178
  publishJob: opts.publishJob
12143
12179
  } : {}),
12180
+ ...(opts.publishBuild !== undefined ? {
12181
+ publishBuild: opts.publishBuild
12182
+ } : {}),
12144
12183
  project: maybeValProject,
12145
12184
  valEnableRedirectUrl,
12146
12185
  valDisableRedirectUrl,
@@ -12213,6 +12252,9 @@ function createValOps(valModules, options) {
12213
12252
  } : {}),
12214
12253
  ...(options.publishJob !== undefined ? {
12215
12254
  publishJob: options.publishJob
12255
+ } : {}),
12256
+ ...(options.publishBuild !== undefined ? {
12257
+ publishBuild: options.publishBuild
12216
12258
  } : {})
12217
12259
  });
12218
12260
  }
@@ -14286,6 +14328,10 @@ const ValServer = (valModules, options, callbacks) => {
14286
14328
  }
14287
14329
  };
14288
14330
  }
14331
+ // A fresh isolate's server has heard nothing yet: ask, rather than refuse.
14332
+ if (serverOps instanceof ValOpsHttp) {
14333
+ await serverOps.learnProjectExpectation();
14334
+ }
14289
14335
  if (!(serverOps instanceof ValOpsHttp) || !serverOps.publishesAsJobs() || serverOps.sourceMode() === "managed" && !serverOps.embedsSource()) {
14290
14336
  return {
14291
14337
  status: 409,
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.138.4",
19
+ "version": "0.138.6",
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/shared": "0.138.4",
34
33
  "@valbuild/core": "0.138.2",
35
- "@valbuild/ui": "0.138.4"
34
+ "@valbuild/shared": "0.138.4",
35
+ "@valbuild/ui": "0.138.6"
36
36
  },
37
37
  "engines": {
38
38
  "node": "^20.19.0 || >=22"