@valbuild/server 0.136.10 → 0.138.0

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,107 @@
1
1
  # @valbuild/server
2
2
 
3
+ ## 0.138.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#754](https://github.com/valbuild/val/pull/754) [`6216172`](https://github.com/valbuild/val/commit/62161729aa40f737590b0a8093c0394385fffd8d) Thanks [@freekh](https://github.com/freekh)! - Connected projects hosted on the Val platform publish as a queued job too.
8
+
9
+ For a project with a GitHub repository whose site runs on the Val platform, pressing **Publish** is now a request, just as it is for a managed project. The Studio sends the job's changes; the content service pushes them as one commit on top of whatever is on the branch at that moment, so a developer's code push in between is kept. CI then builds it. A developer's change to the site's content files that this deployment has not seen stops the publish before anything is pushed, and says so.
10
+
11
+ - A build that CI reports as failed shows "Published, not on the site yet", with **View run**. The next publish builds again.
12
+ - New CLI command, `val ci-report --status failed|succeeded`, for a workflow's last step. It reads the commit, the branch and the run's address from GitHub Actions, uses the same `VAL_PROJECT_TOKEN` as `val publish`, and never fails the job.
13
+
14
+ Connected projects on a host of their own (for example Vercel) publish exactly as before.
15
+
16
+ - [#754](https://github.com/valbuild/val/pull/754) [`40e933d`](https://github.com/valbuild/val/commit/40e933da7fe01cfe1c3f4a43c156f0b2f8a11f62) Thanks [@freekh](https://github.com/freekh)! - Publishing a managed project is now a queued job, and a publish is either live or it did not happen.
17
+
18
+ Pressing **Publish** in a managed project no longer commits first and builds after. It asks the content service for a publish job and returns at once; the Studio tab that pressed builds the job and uploads it, and the content service checks the build renders and makes it live — recording the commit only then. So there is no longer a "Saved, not yet live" state to get stuck in, and no **Finish publishing** button to get out of it.
19
+
20
+ - A press made while another publish is going out is queued behind it, and built when its turn comes by whichever open Studio tab is free.
21
+ - A tab that closes after uploading costs nothing: the rest of the publish is the content service's.
22
+ - A publish that fails before it goes live says so, with **Try again** and **Discard changes**. Your changes are kept either way.
23
+ - Publishing from the site (a page that cannot build) still opens a Studio window to build it; the window now runs the publish job for the page.
24
+
25
+ Connected projects (with a repository) that are hosted on the Val platform publish as a queued job too — see the note on connected projects. Those hosted elsewhere, for example on Vercel, publish exactly as before.
26
+
27
+ For the Val server: the publish proxy now forwards the publish-job routes, `/api/val/publish-job-prepare` renders a job's sources and hands content its archive, and `/api/val/built-source` is removed.
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [[`57af895`](https://github.com/valbuild/val/commit/57af8959cc46519a405b1ed7441623f8bf2e6d27), [`c523506`](https://github.com/valbuild/val/commit/c523506c8b5e148864f401c005b913330e436499), [`6216172`](https://github.com/valbuild/val/commit/62161729aa40f737590b0a8093c0394385fffd8d), [`40e933d`](https://github.com/valbuild/val/commit/40e933da7fe01cfe1c3f4a43c156f0b2f8a11f62), [`5876fe0`](https://github.com/valbuild/val/commit/5876fe075fdee1f76f1cdaa2488ac52c58c894a8), [`c523506`](https://github.com/valbuild/val/commit/c523506c8b5e148864f401c005b913330e436499)]:
32
+ - @valbuild/core@0.138.0
33
+ - @valbuild/ui@0.138.0
34
+ - @valbuild/shared@0.138.0
35
+
36
+ ## 0.137.0
37
+
38
+ ### Minor Changes
39
+
40
+ - [#676](https://github.com/valbuild/val/pull/676) [`48ac9f0`](https://github.com/valbuild/val/commit/48ac9f06dd59a5b4ca60232b1ef198cf42f23aa6) Thanks [@freekh](https://github.com/freekh)! - A link-check endpoint, so the Studio can find out whether an external page is
41
+ still there.
42
+
43
+ `POST /external-urls/check` opens up to twenty URLs and reports what answered:
44
+ the final status after redirects, where it ended up, and how long it took. The
45
+ Studio's Check button in the external pages dialog is the only caller, and it
46
+ cannot do this itself — a cross-origin `fetch` from a browser cannot read a
47
+ response status without CORS headers no ordinary site sends.
48
+
49
+ It is an endpoint that makes outbound requests to addresses your content
50
+ supplies, so it is built as one:
51
+
52
+ - It is behind the same session check as every other authenticated route —
53
+ which, in fs mode, means the same anonymous access every other route allows
54
+ on a developer's own machine. It is not a new way in; it is the same door.
55
+ - It refuses to connect to anything that is not a public internet address —
56
+ loopback, link-local, the private ranges, the carrier-grade NAT range, and
57
+ the cloud metadata service that hands out instance credentials. The check is
58
+ on the RESOLVED address rather than the hostname, so a name that resolves to
59
+ `127.0.0.1` is refused, and it runs again at every redirect hop.
60
+ - It answers with one generic message for anything it refused, so the endpoint
61
+ cannot be used to find out what a hostname resolves to from inside your
62
+ network. The reason is logged on the server.
63
+ - `HEAD` first, `GET` only where a site answers 405 or 501 to it, and no
64
+ connection reuse between targets.
65
+
66
+ - [#746](https://github.com/valbuild/val/pull/746) [`e2bfc0e`](https://github.com/valbuild/val/commit/e2bfc0e40383fe25d3ec0473d1032f6264a8939f) Thanks [@freekh](https://github.com/freekh)! - A site hosted on Val (a managed project, with no repository of its own) can now be updated from the Studio. **Settings → Updates** says whether a newer version of the software the site runs on is available, lists the packages that move and their versions, and offers **Update site**.
67
+
68
+ Updating rebuilds the site in the browser on the new versions and publishes it through the ordinary publish, so it is checked before it goes live: if the updated site does not render, nothing changes and the site keeps running the old versions. Unpublished changes are kept and are **not** published by an update. After it goes live, reload the Studio to use the new one.
69
+
70
+ In Safari, which cannot build the site in the Studio's own page, Update site opens a tab that builds and publishes it, the same way a publish does there, and the Studio follows its progress.
71
+
72
+ A Studio that was opened before the site was updated no longer publishes: pressing Publish asks you to reload first, and nothing is saved until you do. Your unpublished changes are kept. Without this, a Studio left open from before an update would have built the site with the previous version of itself.
73
+
74
+ The versions come from the template the project was made from, as the platform last built it. A project whose code lives in a repository is not offered this; its dependencies are updated there.
75
+
76
+ For hosts: `@valbuild/server` forwards `GET` and `POST /api/val/publish-api/update-target` to the content service, beside `/build-target` and `/project-source`.
77
+
78
+ ### Patch Changes
79
+
80
+ - [#722](https://github.com/valbuild/val/pull/722) [`9b09bf3`](https://github.com/valbuild/val/commit/9b09bf38c9d5912f41fec1c18aa87455fd32f616) Thanks [@freekh](https://github.com/freekh)! - Show history for projects whose git branch is resolved by the server
81
+
82
+ A proxy-mode project that mirrors into a repository is committing to some
83
+ branch, and every commit and history listing is filed under it. But the Studio
84
+ reads `gitBranch` from `val.config` alone, where it is optional — so a project
85
+ that named its branch the usual deployment way (in the environment, e.g. from
86
+ `VERCEL_GIT_COMMIT_REF`) got a History pane reading "this project has no
87
+ `gitBranch` configured" and a status bar with no branch on it, while the server
88
+ behind it was busy committing to one.
89
+
90
+ `/stat` now fills in the branch the server resolved when `val.config` does not
91
+ name one. A branch in `val.config` still wins.
92
+
93
+ Nothing changes where there is no branch to name, and that is a real case
94
+ rather than a gap: git is optional in proxy mode — a project can run on
95
+ credentials alone, with no repository to mirror into — and `fs` mode has no
96
+ commits of its own. Those projects are handed no branch, and the Studio hides
97
+ what needs one rather than offering a History page that can only apologise.
98
+
99
+ - [#748](https://github.com/valbuild/val/pull/748) [`beda04b`](https://github.com/valbuild/val/commit/beda04bd326cbab18ed103e8d43917b16f43bd8c) Thanks [@freekh](https://github.com/freekh)! - A save is no longer refused once because an older answer from the server arrived after a newer one. The content service now reports a version of its list of changes, which goes up with every save, discard and publish. The Studio ignores any answer older than one it already has, including the answer to its own last save, discard or publish, so a discarded change can no longer briefly come back, and a published one can no longer briefly show as unpublished.
100
+ - Updated dependencies [[`8f60073`](https://github.com/valbuild/val/commit/8f60073e5490971a615cebbe8ea1243c67e43530), [`af7a4ba`](https://github.com/valbuild/val/commit/af7a4baa63da5d8a226166377a354cf2fc0c1d77), [`48ac9f0`](https://github.com/valbuild/val/commit/48ac9f06dd59a5b4ca60232b1ef198cf42f23aa6), [`daecf41`](https://github.com/valbuild/val/commit/daecf416f51990569a47a6a9ee9174b1a57f98c2), [`43b58f2`](https://github.com/valbuild/val/commit/43b58f2962840883badf91950da2c51b89d1c7cb), [`e2bfc0e`](https://github.com/valbuild/val/commit/e2bfc0e40383fe25d3ec0473d1032f6264a8939f), [`9b09bf3`](https://github.com/valbuild/val/commit/9b09bf38c9d5912f41fec1c18aa87455fd32f616), [`8e49bf4`](https://github.com/valbuild/val/commit/8e49bf41ad6a8ad3b01e502fb7ce0369baa316db), [`370d0df`](https://github.com/valbuild/val/commit/370d0df7ea45aeeafb4520318018d7c4e1c040d6), [`14877a8`](https://github.com/valbuild/val/commit/14877a85c5add4daa16836470b8739180a9fe8c6), [`beda04b`](https://github.com/valbuild/val/commit/beda04bd326cbab18ed103e8d43917b16f43bd8c)]:
101
+ - @valbuild/ui@0.137.0
102
+ - @valbuild/shared@0.137.0
103
+ - @valbuild/core@0.137.0
104
+
3
105
  ## 0.136.10
4
106
 
5
107
  ### Patch Changes
@@ -146,6 +146,8 @@ export declare abstract class ValOps {
146
146
  * {@link OrderedPatches.headPatchId}.
147
147
  */
148
148
  headPatchId?: PatchId | null;
149
+ /** The chain version of that head. See {@link OrderedPatches.headVersion}. */
150
+ headVersion?: number;
149
151
  } | {
150
152
  type: "error";
151
153
  error: GenericErrorMessage;
@@ -401,6 +403,8 @@ export declare abstract class ValOps {
401
403
  createdAt: string;
402
404
  /** See {@link SaveSourceFilePatchResult} — absent where there are no groups. */
403
405
  patchGroupId?: string;
406
+ /** See {@link SaveSourceFilePatchResult}. */
407
+ headVersion?: number;
404
408
  }, {
405
409
  errorType: "other";
406
410
  error: GenericErrorMessage;
@@ -438,6 +442,12 @@ export declare abstract class ValOps {
438
442
  * an older service.
439
443
  */
440
444
  sourceMode(): "managed" | "connected" | null;
445
+ /**
446
+ * Does a press of Publish run as a publish job (valbuild/home,
447
+ * docs/app-mode.md, "Publishing is a queued job")? Never for a project
448
+ * with no content service.
449
+ */
450
+ publishesAsJobs(): boolean;
441
451
  /**
442
452
  * The branch the content service keeps this project's commits on, or `null`
443
453
  * where there is no such service, or it has not said yet.
@@ -588,9 +598,12 @@ export declare abstract class ValOps {
588
598
  deleted: PatchId[];
589
599
  errors?: undefined;
590
600
  error?: undefined;
601
+ /** The chain version the delete moved the branch to, where reported. */
602
+ headVersion?: number;
591
603
  } | {
592
604
  deleted: PatchId[];
593
605
  errors: Record<PatchId, GenericErrorMessage>;
606
+ headVersion?: number;
594
607
  } | {
595
608
  error: GenericErrorMessage;
596
609
  errors?: undefined;
@@ -685,6 +698,12 @@ export type SaveSourceFilePatchResult = result.Result<{
685
698
  * client uses it to learn the id of the group its own first write created.
686
699
  */
687
700
  patchGroupId?: string;
701
+ /**
702
+ * The chain version this write made — see
703
+ * {@link OrderedPatches.headVersion}. Absent in `fs` mode and against a
704
+ * content service that predates it.
705
+ */
706
+ headVersion?: number;
688
707
  }, ({
689
708
  errorType: "other";
690
709
  } & GenericErrorMessage) | {
@@ -866,6 +885,18 @@ export type OrderedPatches = {
866
885
  * ignores the parent) and a content service that predates the field.
867
886
  */
868
887
  headPatchId?: PatchId | null;
888
+ /**
889
+ * The version of the chain {@link headPatchId} was read at.
890
+ *
891
+ * The content service bumps it with every write and every delete, in the
892
+ * transaction that makes the change, and reads it in the same statement as
893
+ * the head. `/stat` has more than one caller, so two answers can be in
894
+ * flight at once and land in either order; a client keeps the head with the
895
+ * highest version, and an answer that arrives after a newer one no longer
896
+ * puts its parent back. Absent wherever `headPatchId` is, and for the same
897
+ * reasons.
898
+ */
899
+ headVersion?: number;
869
900
  error?: GenericErrorMessage;
870
901
  errors?: PatchReadError[];
871
902
  unauthorized?: boolean;
@@ -879,6 +910,8 @@ export type OrderedPatchesMetadata = {
879
910
  deployments?: ValDeployment[];
880
911
  /** See {@link OrderedPatches.headPatchId}. */
881
912
  headPatchId?: OrderedPatches["headPatchId"];
913
+ /** See {@link OrderedPatches.headVersion}. */
914
+ headVersion?: OrderedPatches["headVersion"];
882
915
  error?: GenericErrorMessage;
883
916
  errors?: OrderedPatches["errors"];
884
917
  unauthorized?: boolean;
@@ -138,9 +138,11 @@ export declare class ValOpsFS extends ValOps {
138
138
  deleted: PatchId[];
139
139
  errors?: undefined;
140
140
  error?: undefined;
141
+ headVersion?: undefined;
141
142
  } | {
142
143
  deleted: PatchId[];
143
144
  errors: Record<PatchId, GenericErrorMessage>;
145
+ headVersion?: undefined;
144
146
  } | {
145
147
  error: GenericErrorMessage;
146
148
  errors?: undefined;
@@ -11,6 +11,15 @@ declare const CommitSha: z.ZodString & z.ZodType<CommitSha, string, z.core.$ZodT
11
11
  declare const BaseSha: z.ZodString & z.ZodType<BaseSha, string, z.core.$ZodTypeInternals<BaseSha, string>>;
12
12
  declare const AuthorId: z.ZodString & z.ZodType<AuthorId, string, z.core.$ZodTypeInternals<AuthorId, string>>;
13
13
  declare const ModuleFilePath: z.ZodString & z.ZodType<ModuleFilePath, string, z.core.$ZodTypeInternals<ModuleFilePath, string>>;
14
+ /**
15
+ * This client's own branch's entry in a per-branch version map.
16
+ *
17
+ * A delete can span branches, so the content service answers per branch. With
18
+ * no branch of its own (a build with no repository, where the service resolves
19
+ * it), the only entry is ours when there is exactly one; with several, none can
20
+ * be picked, and a wrong one would floor this client at another chain's count.
21
+ */
22
+ export declare function ownBranchVersion(headVersions: Record<string, number> | undefined, branch: string | undefined): number | undefined;
14
23
  export type PatchGroupMutationResult = {
15
24
  patchIds: PatchId[];
16
25
  status?: undefined;
@@ -158,6 +167,12 @@ export declare class ValOpsHttp extends ValOps {
158
167
  sourceMode(): "managed" | "connected" | null;
159
168
  /** Remembered with {@link sourceMode}, from the same response. */
160
169
  projectBranch(): string | null;
170
+ /**
171
+ * Does a press of Publish run as a publish job? Every managed project, and
172
+ * a connected one content says is hosted on the platform (its CI publishes
173
+ * through content). `false` before anything has been heard.
174
+ */
175
+ publishesAsJobs(): boolean;
161
176
  /**
162
177
  * The short-lived publish token, and when it stops being usable.
163
178
  *
@@ -197,7 +212,9 @@ export declare class ValOpsHttp extends ValOps {
197
212
  * An allow list rather than a prefix check, because this method holds a
198
213
  * credential and the browser chooses the path. `/publish/{id}` and its three
199
214
  * steps are the publish conversation; `/build-target` is what a build needs
200
- * to know before it starts; `/project-source` is what it builds.
215
+ * to know before it starts; `/project-source` is what it builds;
216
+ * `/update-target` is the same question as `/build-target` for a managed
217
+ * project moving onto its template's current dependencies.
201
218
  *
202
219
  * `/project-source` is here rather than on a route of its own because it is
203
220
  * one of the three things a publish asks for and none of them are useful
@@ -219,6 +236,26 @@ export declare class ValOpsHttp extends ValOps {
219
236
  body: string;
220
237
  contentType: string;
221
238
  }>;
239
+ /**
240
+ * A publish job's prepare, sent to content: the job's sources, archived
241
+ * there before the job is built (valbuild/home, docs/app-mode.md, "The
242
+ * archive, before the seal"). With this server's publish token, as every
243
+ * publish call is, and never through `publishApi` -- see the allowlist.
244
+ */
245
+ prepareJob(jobId: string, body: {
246
+ tab: string;
247
+ filesDirectory: string;
248
+ patchedSourceFiles: Record<string, string | null>;
249
+ patchedBinaryFilesDescriptors: PreparedCommit["patchedBinaryFilesDescriptors"];
250
+ modules: PreparedCommit["moduleVersions"];
251
+ /** Connected: the git commit this deployment was built from. */
252
+ gitCommit?: string;
253
+ }): Promise<{
254
+ status: number;
255
+ body: string;
256
+ contentType: string;
257
+ }>;
258
+ private callPublishApi;
222
259
  onInit(): Promise<void>;
223
260
  getPresignedAuthNonce(profileId: string, corsOrigin: string): Promise<{
224
261
  status: "success";
@@ -258,6 +295,8 @@ export declare class ValOpsHttp extends ValOps {
258
295
  appliedPatches: PatchId[];
259
296
  /** The head of the chain. See {@link OrderedPatchesMetadata.headPatchId}. */
260
297
  headPatchId?: PatchId | null;
298
+ /** The chain version of that head. See {@link OrderedPatchesMetadata.headVersion}. */
299
+ headVersion?: number;
261
300
  /** The newest commit, which is the publish head. */
262
301
  headCommitSha?: string;
263
302
  } | {
@@ -427,9 +466,11 @@ export declare class ValOpsHttp extends ValOps {
427
466
  deleted: PatchId[];
428
467
  errors?: undefined;
429
468
  error?: undefined;
469
+ headVersion?: number;
430
470
  } | {
431
471
  deleted: PatchId[];
432
472
  errors: Record<PatchId, GenericErrorMessage>;
473
+ headVersion?: number;
433
474
  } | {
434
475
  error: GenericErrorMessage;
435
476
  errors?: undefined;
@@ -459,6 +500,8 @@ export declare class ValOpsHttp extends ValOps {
459
500
  /** See `CommitResult.tree`: absent means not reported. */
460
501
  tree?: string;
461
502
  branch: string;
503
+ /** The chain version the publish moved the branch to, where reported. */
504
+ headVersion?: number;
462
505
  error?: undefined;
463
506
  } | {
464
507
  isNotFastForward?: boolean;
@@ -108,6 +108,12 @@ export type CommitResult = {
108
108
  */
109
109
  tree?: string;
110
110
  branch: string;
111
+ /**
112
+ * The chain version the publish moved the branch to, where the content
113
+ * service versions its chain and the publish applied anything. Passed
114
+ * on to the Studio, so a `/stat` read before the publish is dropped.
115
+ */
116
+ headVersion?: number;
111
117
  error?: undefined;
112
118
  } | {
113
119
  isNotFastForward?: boolean;