@valbuild/server 0.144.6 → 0.144.8

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,34 @@
1
1
  # @valbuild/server
2
2
 
3
+ ## 0.144.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#844](https://github.com/valbuild/val/pull/844) [`b67c03e`](https://github.com/valbuild/val/commit/b67c03ee1876803c31098098ae0becf3f4ad6ade) Thanks [@freekh](https://github.com/freekh)! - Publishing a proposal now says what blocks it, and what to do about it:
8
+
9
+ - When the site's code changed after a proposal with code changes started, the Publish dialog offers **Update from the site**. It moves the proposal onto the site as it is now, and its code then needs building again ("Build required").
10
+ - When someone published changes to the same page since the proposal started, the dialog names the fields each side changed.
11
+
12
+ - Updated dependencies [[`6fd8f79`](https://github.com/valbuild/val/commit/6fd8f791a83d37f95dc3ae12bd8025ccf81e4a7c), [`b67c03e`](https://github.com/valbuild/val/commit/b67c03ee1876803c31098098ae0becf3f4ad6ade)]:
13
+ - @valbuild/ui@0.144.8
14
+
15
+ ## 0.144.7
16
+
17
+ ### Patch Changes
18
+
19
+ - [#842](https://github.com/valbuild/val/pull/842) [`45ee083`](https://github.com/valbuild/val/commit/45ee0831393345dab08093575d4ed652e20e1229) Thanks [@freekh](https://github.com/freekh)! - In a proposal on a hosted project, the Studio's assistant can now change the project's code, not only its content:
20
+
21
+ - `list_files` and `read_file` read the project's code. In a proposal they read the proposal's version of it.
22
+ - `write_files` stages whole files in the proposal, or deletes them.
23
+ - `build_proposal` builds those files in the tab, so the proposal's preview shows them. Nothing is published: the site changes only when the proposal is published.
24
+
25
+ The top bar shows **Build required** while staged code is not in the preview yet, and the same button builds it. A failed build says why on the button, and pressing it again builds again.
26
+
27
+ On the site itself, code is never changed directly. A code change asked for there is refused, and New proposal opens so the change can be made in one.
28
+
29
+ - Updated dependencies [[`45ee083`](https://github.com/valbuild/val/commit/45ee0831393345dab08093575d4ed652e20e1229)]:
30
+ - @valbuild/ui@0.144.7
31
+
3
32
  ## 0.144.6
4
33
 
5
34
  ### Patch Changes
@@ -293,6 +293,16 @@ export declare class ValOpsHttp extends ValOps {
293
293
  * changes into a proposal and has no screen yet.
294
294
  */
295
295
  private static proposalsApiAllowed;
296
+ /**
297
+ * A write to a proposal's FILES -- staging code, serving a build of it
298
+ * (valbuild/home `docs/hosted-publishing.md`, step 7), or moving it onto the
299
+ * site's code (step 8, "Update from the site") -- is made by the
300
+ * proposal's own server and nobody else's: the file tools act on the
301
+ * proposal the Studio is open in (P11), and the site's files change only
302
+ * when a proposal is merged. The proposal it names, or `null` when this
303
+ * path is not such a write.
304
+ */
305
+ private static proposalFilesWrite;
296
306
  /**
297
307
  * What a proposal's address may reach of the publish API: building ITS OWN
298
308
  * merge, and nothing that publishes the site's changes. The merge's prepare
@@ -10129,8 +10129,23 @@ class ValOpsHttp extends ValOps {
10129
10129
  if (path === "") return method === "GET" || method === "POST";
10130
10130
  const one = /^\/[0-9a-f]{20}$/.test(path);
10131
10131
  if (one) return method === "GET" || method === "PATCH";
10132
- if (method === "GET") return /^\/[0-9a-f]{20}\/merge-checks$/.test(path);
10133
- return method === "POST" && /^\/[0-9a-f]{20}\/(close|reopen|setup\/retry|merge)$/.test(path);
10132
+ if (method === "GET") return /^\/[0-9a-f]{20}\/(merge-checks|files)$/.test(path);
10133
+ return method === "POST" && /^\/[0-9a-f]{20}\/(close|reopen|setup\/retry|merge|files|build|update-from-site)$/.test(path);
10134
+ }
10135
+
10136
+ /**
10137
+ * A write to a proposal's FILES -- staging code, serving a build of it
10138
+ * (valbuild/home `docs/hosted-publishing.md`, step 7), or moving it onto the
10139
+ * site's code (step 8, "Update from the site") -- is made by the
10140
+ * proposal's own server and nobody else's: the file tools act on the
10141
+ * proposal the Studio is open in (P11), and the site's files change only
10142
+ * when a proposal is merged. The proposal it names, or `null` when this
10143
+ * path is not such a write.
10144
+ */
10145
+ static proposalFilesWrite(method, path) {
10146
+ var _exec;
10147
+ if (method !== "POST") return null;
10148
+ return ((_exec = /^\/([0-9a-f]{20})\/(files|build|update-from-site)$/.exec(path)) === null || _exec === void 0 ? void 0 : _exec[1]) ?? null;
10134
10149
  }
10135
10150
 
10136
10151
  /**
@@ -10151,6 +10166,7 @@ class ValOpsHttp extends ValOps {
10151
10166
  return /^\/publish-jobs\/[A-Za-z0-9_-]{1,100}\/(merge-prepare|steps|renew|cancel)$/.test(path);
10152
10167
  }
10153
10168
  async proposalsApi(path, init, profileId) {
10169
+ var _this$proposal;
10154
10170
  const json = "application/json";
10155
10171
  if (!ValOpsHttp.proposalsApiAllowed(init.method, path)) {
10156
10172
  return {
@@ -10161,6 +10177,16 @@ class ValOpsHttp extends ValOps {
10161
10177
  })
10162
10178
  };
10163
10179
  }
10180
+ const writes = ValOpsHttp.proposalFilesWrite(init.method, path);
10181
+ if (writes !== null && writes !== ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.name)) {
10182
+ return {
10183
+ status: 403,
10184
+ contentType: json,
10185
+ body: JSON.stringify({
10186
+ message: this.proposal === null ? "The site's files are changed in a proposal: open one, and change them there." : "Files are changed in the proposal this Studio is open in, not in another."
10187
+ })
10188
+ };
10189
+ }
10164
10190
  const res = await fetch(`${this.contentUrl}/v1/${this.project}/proposals${path}`, {
10165
10191
  method: init.method,
10166
10192
  headers: {
@@ -10540,8 +10566,8 @@ class ValOpsHttp extends ValOps {
10540
10566
 
10541
10567
  /** The branch this server's patches are on, where it knows it. */
10542
10568
  ownBranch() {
10543
- var _this$proposal, _this$git;
10544
- return ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.branch) ?? ((_this$git = this.git) === null || _this$git === void 0 ? void 0 : _this$git.branch);
10569
+ var _this$proposal2, _this$git;
10570
+ return ((_this$proposal2 = this.proposal) === null || _this$proposal2 === void 0 ? void 0 : _this$proposal2.branch) ?? ((_this$git = this.git) === null || _this$git === void 0 ? void 0 : _this$git.branch);
10545
10571
  }
10546
10572
  async getWebSocketNonce(profileId) {
10547
10573
  return fetch(`${this.contentUrl}/v1/${this.project}/websocket/nonces`, {
@@ -10129,8 +10129,23 @@ class ValOpsHttp extends ValOps {
10129
10129
  if (path === "") return method === "GET" || method === "POST";
10130
10130
  const one = /^\/[0-9a-f]{20}$/.test(path);
10131
10131
  if (one) return method === "GET" || method === "PATCH";
10132
- if (method === "GET") return /^\/[0-9a-f]{20}\/merge-checks$/.test(path);
10133
- return method === "POST" && /^\/[0-9a-f]{20}\/(close|reopen|setup\/retry|merge)$/.test(path);
10132
+ if (method === "GET") return /^\/[0-9a-f]{20}\/(merge-checks|files)$/.test(path);
10133
+ return method === "POST" && /^\/[0-9a-f]{20}\/(close|reopen|setup\/retry|merge|files|build|update-from-site)$/.test(path);
10134
+ }
10135
+
10136
+ /**
10137
+ * A write to a proposal's FILES -- staging code, serving a build of it
10138
+ * (valbuild/home `docs/hosted-publishing.md`, step 7), or moving it onto the
10139
+ * site's code (step 8, "Update from the site") -- is made by the
10140
+ * proposal's own server and nobody else's: the file tools act on the
10141
+ * proposal the Studio is open in (P11), and the site's files change only
10142
+ * when a proposal is merged. The proposal it names, or `null` when this
10143
+ * path is not such a write.
10144
+ */
10145
+ static proposalFilesWrite(method, path) {
10146
+ var _exec;
10147
+ if (method !== "POST") return null;
10148
+ return ((_exec = /^\/([0-9a-f]{20})\/(files|build|update-from-site)$/.exec(path)) === null || _exec === void 0 ? void 0 : _exec[1]) ?? null;
10134
10149
  }
10135
10150
 
10136
10151
  /**
@@ -10151,6 +10166,7 @@ class ValOpsHttp extends ValOps {
10151
10166
  return /^\/publish-jobs\/[A-Za-z0-9_-]{1,100}\/(merge-prepare|steps|renew|cancel)$/.test(path);
10152
10167
  }
10153
10168
  async proposalsApi(path, init, profileId) {
10169
+ var _this$proposal;
10154
10170
  const json = "application/json";
10155
10171
  if (!ValOpsHttp.proposalsApiAllowed(init.method, path)) {
10156
10172
  return {
@@ -10161,6 +10177,16 @@ class ValOpsHttp extends ValOps {
10161
10177
  })
10162
10178
  };
10163
10179
  }
10180
+ const writes = ValOpsHttp.proposalFilesWrite(init.method, path);
10181
+ if (writes !== null && writes !== ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.name)) {
10182
+ return {
10183
+ status: 403,
10184
+ contentType: json,
10185
+ body: JSON.stringify({
10186
+ message: this.proposal === null ? "The site's files are changed in a proposal: open one, and change them there." : "Files are changed in the proposal this Studio is open in, not in another."
10187
+ })
10188
+ };
10189
+ }
10164
10190
  const res = await fetch(`${this.contentUrl}/v1/${this.project}/proposals${path}`, {
10165
10191
  method: init.method,
10166
10192
  headers: {
@@ -10540,8 +10566,8 @@ class ValOpsHttp extends ValOps {
10540
10566
 
10541
10567
  /** The branch this server's patches are on, where it knows it. */
10542
10568
  ownBranch() {
10543
- var _this$proposal, _this$git;
10544
- return ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.branch) ?? ((_this$git = this.git) === null || _this$git === void 0 ? void 0 : _this$git.branch);
10569
+ var _this$proposal2, _this$git;
10570
+ return ((_this$proposal2 = this.proposal) === null || _this$proposal2 === void 0 ? void 0 : _this$proposal2.branch) ?? ((_this$git = this.git) === null || _this$git === void 0 ? void 0 : _this$git.branch);
10545
10571
  }
10546
10572
  async getWebSocketNonce(profileId) {
10547
10573
  return fetch(`${this.contentUrl}/v1/${this.project}/websocket/nonces`, {
@@ -10092,8 +10092,23 @@ class ValOpsHttp extends ValOps {
10092
10092
  if (path === "") return method === "GET" || method === "POST";
10093
10093
  const one = /^\/[0-9a-f]{20}$/.test(path);
10094
10094
  if (one) return method === "GET" || method === "PATCH";
10095
- if (method === "GET") return /^\/[0-9a-f]{20}\/merge-checks$/.test(path);
10096
- return method === "POST" && /^\/[0-9a-f]{20}\/(close|reopen|setup\/retry|merge)$/.test(path);
10095
+ if (method === "GET") return /^\/[0-9a-f]{20}\/(merge-checks|files)$/.test(path);
10096
+ return method === "POST" && /^\/[0-9a-f]{20}\/(close|reopen|setup\/retry|merge|files|build|update-from-site)$/.test(path);
10097
+ }
10098
+
10099
+ /**
10100
+ * A write to a proposal's FILES -- staging code, serving a build of it
10101
+ * (valbuild/home `docs/hosted-publishing.md`, step 7), or moving it onto the
10102
+ * site's code (step 8, "Update from the site") -- is made by the
10103
+ * proposal's own server and nobody else's: the file tools act on the
10104
+ * proposal the Studio is open in (P11), and the site's files change only
10105
+ * when a proposal is merged. The proposal it names, or `null` when this
10106
+ * path is not such a write.
10107
+ */
10108
+ static proposalFilesWrite(method, path) {
10109
+ var _exec;
10110
+ if (method !== "POST") return null;
10111
+ return ((_exec = /^\/([0-9a-f]{20})\/(files|build|update-from-site)$/.exec(path)) === null || _exec === void 0 ? void 0 : _exec[1]) ?? null;
10097
10112
  }
10098
10113
 
10099
10114
  /**
@@ -10114,6 +10129,7 @@ class ValOpsHttp extends ValOps {
10114
10129
  return /^\/publish-jobs\/[A-Za-z0-9_-]{1,100}\/(merge-prepare|steps|renew|cancel)$/.test(path);
10115
10130
  }
10116
10131
  async proposalsApi(path, init, profileId) {
10132
+ var _this$proposal;
10117
10133
  const json = "application/json";
10118
10134
  if (!ValOpsHttp.proposalsApiAllowed(init.method, path)) {
10119
10135
  return {
@@ -10124,6 +10140,16 @@ class ValOpsHttp extends ValOps {
10124
10140
  })
10125
10141
  };
10126
10142
  }
10143
+ const writes = ValOpsHttp.proposalFilesWrite(init.method, path);
10144
+ if (writes !== null && writes !== ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.name)) {
10145
+ return {
10146
+ status: 403,
10147
+ contentType: json,
10148
+ body: JSON.stringify({
10149
+ message: this.proposal === null ? "The site's files are changed in a proposal: open one, and change them there." : "Files are changed in the proposal this Studio is open in, not in another."
10150
+ })
10151
+ };
10152
+ }
10127
10153
  const res = await fetch(`${this.contentUrl}/v1/${this.project}/proposals${path}`, {
10128
10154
  method: init.method,
10129
10155
  headers: {
@@ -10503,8 +10529,8 @@ class ValOpsHttp extends ValOps {
10503
10529
 
10504
10530
  /** The branch this server's patches are on, where it knows it. */
10505
10531
  ownBranch() {
10506
- var _this$proposal, _this$git;
10507
- return ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.branch) ?? ((_this$git = this.git) === null || _this$git === void 0 ? void 0 : _this$git.branch);
10532
+ var _this$proposal2, _this$git;
10533
+ return ((_this$proposal2 = this.proposal) === null || _this$proposal2 === void 0 ? void 0 : _this$proposal2.branch) ?? ((_this$git = this.git) === null || _this$git === void 0 ? void 0 : _this$git.branch);
10508
10534
  }
10509
10535
  async getWebSocketNonce(profileId) {
10510
10536
  return fetch(`${this.contentUrl}/v1/${this.project}/websocket/nonces`, {
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.6",
19
+ "version": "0.144.8",
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",
33
34
  "@valbuild/shared": "0.144.5",
34
- "@valbuild/ui": "0.144.6",
35
- "@valbuild/core": "0.144.0"
35
+ "@valbuild/ui": "0.144.8"
36
36
  },
37
37
  "engines": {
38
38
  "node": "^20.19.0 || >=22"