@valbuild/server 0.144.6 → 0.144.7

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,22 @@
1
1
  # @valbuild/server
2
2
 
3
+ ## 0.144.7
4
+
5
+ ### Patch Changes
6
+
7
+ - [#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:
8
+
9
+ - `list_files` and `read_file` read the project's code. In a proposal they read the proposal's version of it.
10
+ - `write_files` stages whole files in the proposal, or deletes them.
11
+ - `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.
12
+
13
+ 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.
14
+
15
+ 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.
16
+
17
+ - Updated dependencies [[`45ee083`](https://github.com/valbuild/val/commit/45ee0831393345dab08093575d4ed652e20e1229)]:
18
+ - @valbuild/ui@0.144.7
19
+
3
20
  ## 0.144.6
4
21
 
5
22
  ### Patch Changes
@@ -293,6 +293,15 @@ 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, or serving a build of it
298
+ * (valbuild/home `docs/hosted-publishing.md`, step 7) -- is made by the
299
+ * proposal's own server and nobody else's: the file tools act on the
300
+ * proposal the Studio is open in (P11), and the site's files change only
301
+ * when a proposal is merged. The proposal it names, or `null` when this
302
+ * path is not such a write.
303
+ */
304
+ private static proposalFilesWrite;
296
305
  /**
297
306
  * What a proposal's address may reach of the publish API: building ITS OWN
298
307
  * merge, and nothing that publishes the site's changes. The merge's prepare
@@ -10129,8 +10129,22 @@ 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)$/.test(path);
10134
+ }
10135
+
10136
+ /**
10137
+ * A write to a proposal's FILES -- staging code, or serving a build of it
10138
+ * (valbuild/home `docs/hosted-publishing.md`, step 7) -- is made by the
10139
+ * proposal's own server and nobody else's: the file tools act on the
10140
+ * proposal the Studio is open in (P11), and the site's files change only
10141
+ * when a proposal is merged. The proposal it names, or `null` when this
10142
+ * path is not such a write.
10143
+ */
10144
+ static proposalFilesWrite(method, path) {
10145
+ var _exec;
10146
+ if (method !== "POST") return null;
10147
+ return ((_exec = /^\/([0-9a-f]{20})\/(files|build)$/.exec(path)) === null || _exec === void 0 ? void 0 : _exec[1]) ?? null;
10134
10148
  }
10135
10149
 
10136
10150
  /**
@@ -10151,6 +10165,7 @@ class ValOpsHttp extends ValOps {
10151
10165
  return /^\/publish-jobs\/[A-Za-z0-9_-]{1,100}\/(merge-prepare|steps|renew|cancel)$/.test(path);
10152
10166
  }
10153
10167
  async proposalsApi(path, init, profileId) {
10168
+ var _this$proposal;
10154
10169
  const json = "application/json";
10155
10170
  if (!ValOpsHttp.proposalsApiAllowed(init.method, path)) {
10156
10171
  return {
@@ -10161,6 +10176,16 @@ class ValOpsHttp extends ValOps {
10161
10176
  })
10162
10177
  };
10163
10178
  }
10179
+ const writes = ValOpsHttp.proposalFilesWrite(init.method, path);
10180
+ if (writes !== null && writes !== ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.name)) {
10181
+ return {
10182
+ status: 403,
10183
+ contentType: json,
10184
+ body: JSON.stringify({
10185
+ 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."
10186
+ })
10187
+ };
10188
+ }
10164
10189
  const res = await fetch(`${this.contentUrl}/v1/${this.project}/proposals${path}`, {
10165
10190
  method: init.method,
10166
10191
  headers: {
@@ -10540,8 +10565,8 @@ class ValOpsHttp extends ValOps {
10540
10565
 
10541
10566
  /** The branch this server's patches are on, where it knows it. */
10542
10567
  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);
10568
+ var _this$proposal2, _this$git;
10569
+ 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
10570
  }
10546
10571
  async getWebSocketNonce(profileId) {
10547
10572
  return fetch(`${this.contentUrl}/v1/${this.project}/websocket/nonces`, {
@@ -10129,8 +10129,22 @@ 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)$/.test(path);
10134
+ }
10135
+
10136
+ /**
10137
+ * A write to a proposal's FILES -- staging code, or serving a build of it
10138
+ * (valbuild/home `docs/hosted-publishing.md`, step 7) -- is made by the
10139
+ * proposal's own server and nobody else's: the file tools act on the
10140
+ * proposal the Studio is open in (P11), and the site's files change only
10141
+ * when a proposal is merged. The proposal it names, or `null` when this
10142
+ * path is not such a write.
10143
+ */
10144
+ static proposalFilesWrite(method, path) {
10145
+ var _exec;
10146
+ if (method !== "POST") return null;
10147
+ return ((_exec = /^\/([0-9a-f]{20})\/(files|build)$/.exec(path)) === null || _exec === void 0 ? void 0 : _exec[1]) ?? null;
10134
10148
  }
10135
10149
 
10136
10150
  /**
@@ -10151,6 +10165,7 @@ class ValOpsHttp extends ValOps {
10151
10165
  return /^\/publish-jobs\/[A-Za-z0-9_-]{1,100}\/(merge-prepare|steps|renew|cancel)$/.test(path);
10152
10166
  }
10153
10167
  async proposalsApi(path, init, profileId) {
10168
+ var _this$proposal;
10154
10169
  const json = "application/json";
10155
10170
  if (!ValOpsHttp.proposalsApiAllowed(init.method, path)) {
10156
10171
  return {
@@ -10161,6 +10176,16 @@ class ValOpsHttp extends ValOps {
10161
10176
  })
10162
10177
  };
10163
10178
  }
10179
+ const writes = ValOpsHttp.proposalFilesWrite(init.method, path);
10180
+ if (writes !== null && writes !== ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.name)) {
10181
+ return {
10182
+ status: 403,
10183
+ contentType: json,
10184
+ body: JSON.stringify({
10185
+ 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."
10186
+ })
10187
+ };
10188
+ }
10164
10189
  const res = await fetch(`${this.contentUrl}/v1/${this.project}/proposals${path}`, {
10165
10190
  method: init.method,
10166
10191
  headers: {
@@ -10540,8 +10565,8 @@ class ValOpsHttp extends ValOps {
10540
10565
 
10541
10566
  /** The branch this server's patches are on, where it knows it. */
10542
10567
  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);
10568
+ var _this$proposal2, _this$git;
10569
+ 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
10570
  }
10546
10571
  async getWebSocketNonce(profileId) {
10547
10572
  return fetch(`${this.contentUrl}/v1/${this.project}/websocket/nonces`, {
@@ -10092,8 +10092,22 @@ 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)$/.test(path);
10097
+ }
10098
+
10099
+ /**
10100
+ * A write to a proposal's FILES -- staging code, or serving a build of it
10101
+ * (valbuild/home `docs/hosted-publishing.md`, step 7) -- is made by the
10102
+ * proposal's own server and nobody else's: the file tools act on the
10103
+ * proposal the Studio is open in (P11), and the site's files change only
10104
+ * when a proposal is merged. The proposal it names, or `null` when this
10105
+ * path is not such a write.
10106
+ */
10107
+ static proposalFilesWrite(method, path) {
10108
+ var _exec;
10109
+ if (method !== "POST") return null;
10110
+ return ((_exec = /^\/([0-9a-f]{20})\/(files|build)$/.exec(path)) === null || _exec === void 0 ? void 0 : _exec[1]) ?? null;
10097
10111
  }
10098
10112
 
10099
10113
  /**
@@ -10114,6 +10128,7 @@ class ValOpsHttp extends ValOps {
10114
10128
  return /^\/publish-jobs\/[A-Za-z0-9_-]{1,100}\/(merge-prepare|steps|renew|cancel)$/.test(path);
10115
10129
  }
10116
10130
  async proposalsApi(path, init, profileId) {
10131
+ var _this$proposal;
10117
10132
  const json = "application/json";
10118
10133
  if (!ValOpsHttp.proposalsApiAllowed(init.method, path)) {
10119
10134
  return {
@@ -10124,6 +10139,16 @@ class ValOpsHttp extends ValOps {
10124
10139
  })
10125
10140
  };
10126
10141
  }
10142
+ const writes = ValOpsHttp.proposalFilesWrite(init.method, path);
10143
+ if (writes !== null && writes !== ((_this$proposal = this.proposal) === null || _this$proposal === void 0 ? void 0 : _this$proposal.name)) {
10144
+ return {
10145
+ status: 403,
10146
+ contentType: json,
10147
+ body: JSON.stringify({
10148
+ 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."
10149
+ })
10150
+ };
10151
+ }
10127
10152
  const res = await fetch(`${this.contentUrl}/v1/${this.project}/proposals${path}`, {
10128
10153
  method: init.method,
10129
10154
  headers: {
@@ -10503,8 +10528,8 @@ class ValOpsHttp extends ValOps {
10503
10528
 
10504
10529
  /** The branch this server's patches are on, where it knows it. */
10505
10530
  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);
10531
+ var _this$proposal2, _this$git;
10532
+ 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
10533
  }
10509
10534
  async getWebSocketNonce(profileId) {
10510
10535
  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.7",
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.7"
36
36
  },
37
37
  "engines": {
38
38
  "node": "^20.19.0 || >=22"