@valbuild/shared 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 +79 -0
- package/dist/declarations/src/internal/ApiRoutes.d.ts +90 -19
- package/dist/declarations/src/internal/publish/contentApi.d.ts +207 -4
- package/dist/declarations/src/internal/publish/protocol.d.ts +98 -1
- package/internal/dist/valbuild-shared-internal.cjs.dev.js +280 -23
- package/internal/dist/valbuild-shared-internal.cjs.prod.js +280 -23
- package/internal/dist/valbuild-shared-internal.esm.js +273 -24
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
1
|
# @valbuild/shared
|
|
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), [`5876fe0`](https://github.com/valbuild/val/commit/5876fe075fdee1f76f1cdaa2488ac52c58c894a8)]:
|
|
32
|
+
- @valbuild/core@0.138.0
|
|
33
|
+
|
|
34
|
+
## 0.137.0
|
|
35
|
+
|
|
36
|
+
### Minor Changes
|
|
37
|
+
|
|
38
|
+
- [#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
|
|
39
|
+
still there.
|
|
40
|
+
|
|
41
|
+
`POST /external-urls/check` opens up to twenty URLs and reports what answered:
|
|
42
|
+
the final status after redirects, where it ended up, and how long it took. The
|
|
43
|
+
Studio's Check button in the external pages dialog is the only caller, and it
|
|
44
|
+
cannot do this itself — a cross-origin `fetch` from a browser cannot read a
|
|
45
|
+
response status without CORS headers no ordinary site sends.
|
|
46
|
+
|
|
47
|
+
It is an endpoint that makes outbound requests to addresses your content
|
|
48
|
+
supplies, so it is built as one:
|
|
49
|
+
|
|
50
|
+
- It is behind the same session check as every other authenticated route —
|
|
51
|
+
which, in fs mode, means the same anonymous access every other route allows
|
|
52
|
+
on a developer's own machine. It is not a new way in; it is the same door.
|
|
53
|
+
- It refuses to connect to anything that is not a public internet address —
|
|
54
|
+
loopback, link-local, the private ranges, the carrier-grade NAT range, and
|
|
55
|
+
the cloud metadata service that hands out instance credentials. The check is
|
|
56
|
+
on the RESOLVED address rather than the hostname, so a name that resolves to
|
|
57
|
+
`127.0.0.1` is refused, and it runs again at every redirect hop.
|
|
58
|
+
- It answers with one generic message for anything it refused, so the endpoint
|
|
59
|
+
cannot be used to find out what a hostname resolves to from inside your
|
|
60
|
+
network. The reason is logged on the server.
|
|
61
|
+
- `HEAD` first, `GET` only where a site answers 405 or 501 to it, and no
|
|
62
|
+
connection reuse between targets.
|
|
63
|
+
|
|
64
|
+
- [#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**.
|
|
65
|
+
|
|
66
|
+
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.
|
|
67
|
+
|
|
68
|
+
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.
|
|
69
|
+
|
|
70
|
+
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.
|
|
71
|
+
|
|
72
|
+
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.
|
|
73
|
+
|
|
74
|
+
For hosts: `@valbuild/server` forwards `GET` and `POST /api/val/publish-api/update-target` to the content service, beside `/build-target` and `/project-source`.
|
|
75
|
+
|
|
76
|
+
### Patch Changes
|
|
77
|
+
|
|
78
|
+
- [#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.
|
|
79
|
+
- Updated dependencies [[`43b58f2`](https://github.com/valbuild/val/commit/43b58f2962840883badf91950da2c51b89d1c7cb)]:
|
|
80
|
+
- @valbuild/core@0.137.0
|
|
81
|
+
|
|
3
82
|
## 0.136.10
|
|
4
83
|
|
|
5
84
|
### Patch Changes
|
|
@@ -424,6 +424,7 @@ export declare const Api: {
|
|
|
424
424
|
mode: z.ZodUnion<readonly [z.ZodLiteral<"http">, z.ZodLiteral<"fs">]>;
|
|
425
425
|
jsonEntriesSha: z.ZodOptional<z.ZodString>;
|
|
426
426
|
sourceMode: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"managed">, z.ZodLiteral<"connected">]>>;
|
|
427
|
+
publishJobs: z.ZodOptional<z.ZodBoolean>;
|
|
427
428
|
publishRefusal: z.ZodOptional<z.ZodObject<{
|
|
428
429
|
code: z.ZodLiteral<"no-base">;
|
|
429
430
|
message: z.ZodString;
|
|
@@ -440,6 +441,7 @@ export declare const Api: {
|
|
|
440
441
|
appliedPatches: z.ZodOptional<z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>>;
|
|
441
442
|
headCommitSha: z.ZodOptional<z.ZodString>;
|
|
442
443
|
headPatchId: z.ZodOptional<z.ZodNullable<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>>;
|
|
444
|
+
headVersion: z.ZodOptional<z.ZodNumber>;
|
|
443
445
|
commits: z.ZodArray<z.ZodObject<{
|
|
444
446
|
commitSha: z.ZodString;
|
|
445
447
|
clientCommitSha: z.ZodNullable<z.ZodString>;
|
|
@@ -469,6 +471,7 @@ export declare const Api: {
|
|
|
469
471
|
profileId: z.ZodNullable<z.ZodString>;
|
|
470
472
|
mode: z.ZodUnion<readonly [z.ZodLiteral<"http">, z.ZodLiteral<"fs">]>;
|
|
471
473
|
sourceMode: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"managed">, z.ZodLiteral<"connected">]>>;
|
|
474
|
+
publishJobs: z.ZodOptional<z.ZodBoolean>;
|
|
472
475
|
publishRefusal: z.ZodOptional<z.ZodObject<{
|
|
473
476
|
code: z.ZodLiteral<"no-base">;
|
|
474
477
|
message: z.ZodString;
|
|
@@ -567,6 +570,55 @@ export declare const Api: {
|
|
|
567
570
|
}, z.core.$strip>]>;
|
|
568
571
|
};
|
|
569
572
|
};
|
|
573
|
+
/**
|
|
574
|
+
* Open a batch of external URLs and report what answered.
|
|
575
|
+
*
|
|
576
|
+
* A batch rather than one URL because the client checks a list, and a POST
|
|
577
|
+
* rather than a GET because the list is the input and does not belong in a
|
|
578
|
+
* URL or a cache.
|
|
579
|
+
*
|
|
580
|
+
* The server makes outbound requests to addresses this body supplies, which
|
|
581
|
+
* is SSRF by construction - see `linkCheck/addressGuard.ts` for the deny
|
|
582
|
+
* list that makes it safe, and `docs/plans/external-page-link-checks.md` for
|
|
583
|
+
* why it is a deny list on the RESOLVED address.
|
|
584
|
+
*/
|
|
585
|
+
"/external-urls/check": {
|
|
586
|
+
POST: {
|
|
587
|
+
req: {
|
|
588
|
+
body: z.ZodObject<{
|
|
589
|
+
urls: z.ZodArray<z.ZodString>;
|
|
590
|
+
}, z.core.$strip>;
|
|
591
|
+
cookies: {
|
|
592
|
+
val_session: z.ZodOptional<z.ZodString>;
|
|
593
|
+
};
|
|
594
|
+
};
|
|
595
|
+
res: z.ZodUnion<readonly [z.ZodObject<{
|
|
596
|
+
status: z.ZodLiteral<401>;
|
|
597
|
+
json: z.ZodObject<{
|
|
598
|
+
message: z.ZodString;
|
|
599
|
+
}, z.core.$strip>;
|
|
600
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
601
|
+
status: z.ZodLiteral<200>;
|
|
602
|
+
json: z.ZodObject<{
|
|
603
|
+
results: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
604
|
+
kind: z.ZodLiteral<"answered">;
|
|
605
|
+
code: z.ZodNumber;
|
|
606
|
+
finalUrl: z.ZodString;
|
|
607
|
+
ms: z.ZodNumber;
|
|
608
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
609
|
+
kind: z.ZodLiteral<"unreachable">;
|
|
610
|
+
message: z.ZodString;
|
|
611
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
612
|
+
kind: z.ZodLiteral<"timeout">;
|
|
613
|
+
ms: z.ZodNumber;
|
|
614
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
615
|
+
kind: z.ZodLiteral<"skipped">;
|
|
616
|
+
message: z.ZodString;
|
|
617
|
+
}, z.core.$strip>]>>;
|
|
618
|
+
}, z.core.$strip>;
|
|
619
|
+
}, z.core.$strip>]>;
|
|
620
|
+
};
|
|
621
|
+
};
|
|
570
622
|
"/direct-file-upload-settings": {
|
|
571
623
|
POST: {
|
|
572
624
|
req: {
|
|
@@ -608,6 +660,7 @@ export declare const Api: {
|
|
|
608
660
|
};
|
|
609
661
|
body: z.ZodOptional<z.ZodObject<{
|
|
610
662
|
unstagePatchIds: z.ZodOptional<z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>>;
|
|
663
|
+
reportHeadVersion: z.ZodOptional<z.ZodLiteral<true>>;
|
|
611
664
|
}, z.core.$strip>>;
|
|
612
665
|
cookies: {
|
|
613
666
|
val_session: z.ZodOptional<z.ZodString>;
|
|
@@ -632,7 +685,10 @@ export declare const Api: {
|
|
|
632
685
|
}, z.core.$strip>;
|
|
633
686
|
}, z.core.$strip>, z.ZodObject<{
|
|
634
687
|
status: z.ZodLiteral<200>;
|
|
635
|
-
json: z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string
|
|
688
|
+
json: z.ZodUnion<readonly [z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>, z.ZodObject<{
|
|
689
|
+
deleted: z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>;
|
|
690
|
+
headVersion: z.ZodOptional<z.ZodNumber>;
|
|
691
|
+
}, z.core.$strip>]>;
|
|
636
692
|
}, z.core.$strip>]>;
|
|
637
693
|
};
|
|
638
694
|
PUT: {
|
|
@@ -692,6 +748,7 @@ export declare const Api: {
|
|
|
692
748
|
patchId: z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>;
|
|
693
749
|
}, z.core.$strip>]>;
|
|
694
750
|
patchGroupId: z.ZodOptional<z.ZodString>;
|
|
751
|
+
headVersion: z.ZodOptional<z.ZodNumber>;
|
|
695
752
|
}, z.core.$strip>;
|
|
696
753
|
}, z.core.$strip>]>;
|
|
697
754
|
};
|
|
@@ -1023,24 +1080,14 @@ export declare const Api: {
|
|
|
1023
1080
|
}, z.core.$strip>]>;
|
|
1024
1081
|
};
|
|
1025
1082
|
};
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
* with every commit since it applied, for a build made in the browser.
|
|
1029
|
-
*
|
|
1030
|
-
* A Studio build starts from the source stored with the live build. A commit
|
|
1031
|
-
* whose own publish failed -- or the first commit of a project that started
|
|
1032
|
-
* as a copy of a template -- is in content and in no stored source, so a build
|
|
1033
|
-
* that added only its own save's files shipped without it. Only this server
|
|
1034
|
-
* can render those commits back into text: content keeps a managed project's
|
|
1035
|
-
* content as Source, not as files.
|
|
1036
|
-
*
|
|
1037
|
-
* Committed patches only. A pending one is somebody's unpublished work, and
|
|
1038
|
-
* is not this build's to ship. 409 where there is nothing to answer with: a
|
|
1039
|
-
* project with a repository, or a build that did not embed its source.
|
|
1040
|
-
*/
|
|
1041
|
-
"/built-source": {
|
|
1042
|
-
GET: {
|
|
1083
|
+
"/publish-job-prepare": {
|
|
1084
|
+
POST: {
|
|
1043
1085
|
req: {
|
|
1086
|
+
body: z.ZodObject<{
|
|
1087
|
+
jobId: z.ZodString;
|
|
1088
|
+
tab: z.ZodString;
|
|
1089
|
+
patchIds: z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>;
|
|
1090
|
+
}, z.core.$strip>;
|
|
1044
1091
|
cookies: {
|
|
1045
1092
|
val_session: z.ZodOptional<z.ZodString>;
|
|
1046
1093
|
};
|
|
@@ -1050,6 +1097,11 @@ export declare const Api: {
|
|
|
1050
1097
|
json: z.ZodObject<{
|
|
1051
1098
|
message: z.ZodString;
|
|
1052
1099
|
}, z.core.$strip>;
|
|
1100
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1101
|
+
status: z.ZodLiteral<400>;
|
|
1102
|
+
json: z.ZodObject<{
|
|
1103
|
+
message: z.ZodString;
|
|
1104
|
+
}, z.core.$strip>;
|
|
1053
1105
|
}, z.core.$strip>, z.ZodObject<{
|
|
1054
1106
|
status: z.ZodLiteral<409>;
|
|
1055
1107
|
json: z.ZodObject<{
|
|
@@ -1060,10 +1112,28 @@ export declare const Api: {
|
|
|
1060
1112
|
json: z.ZodObject<{
|
|
1061
1113
|
message: z.ZodString;
|
|
1062
1114
|
}, z.core.$strip>;
|
|
1115
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1116
|
+
status: z.ZodLiteral<502>;
|
|
1117
|
+
json: z.ZodObject<{
|
|
1118
|
+
message: z.ZodString;
|
|
1119
|
+
}, z.core.$strip>;
|
|
1063
1120
|
}, z.core.$strip>, z.ZodObject<{
|
|
1064
1121
|
status: z.ZodLiteral<200>;
|
|
1065
1122
|
json: z.ZodObject<{
|
|
1066
|
-
|
|
1123
|
+
job: z.ZodNullable<z.ZodObject<{
|
|
1124
|
+
id: z.ZodString;
|
|
1125
|
+
step: z.ZodNullable<z.ZodEnum<{
|
|
1126
|
+
prepare: "prepare";
|
|
1127
|
+
build: "build";
|
|
1128
|
+
upload: "upload";
|
|
1129
|
+
}>>;
|
|
1130
|
+
base: z.ZodNullable<z.ZodString>;
|
|
1131
|
+
patches: z.ZodArray<z.ZodString>;
|
|
1132
|
+
}, z.core.$strip>>;
|
|
1133
|
+
sourceFiles: z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodString>>;
|
|
1134
|
+
binaryFiles: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
1135
|
+
binaryFilesUnread: z.ZodArray<z.ZodString>;
|
|
1136
|
+
branch: z.ZodNullable<z.ZodString>;
|
|
1067
1137
|
}, z.core.$strip>;
|
|
1068
1138
|
}, z.core.$strip>]>;
|
|
1069
1139
|
};
|
|
@@ -1131,6 +1201,7 @@ export declare const Api: {
|
|
|
1131
1201
|
moduleFilePath: z.ZodString & z.ZodType<ModuleFilePath, string, z.core.$ZodTypeInternals<ModuleFilePath, string>>;
|
|
1132
1202
|
message: z.ZodString;
|
|
1133
1203
|
}, z.core.$strip>>>;
|
|
1204
|
+
headVersion: z.ZodOptional<z.ZodNumber>;
|
|
1134
1205
|
}, z.core.$strip>;
|
|
1135
1206
|
}, z.core.$strip>, z.ZodObject<{
|
|
1136
1207
|
status: z.ZodLiteral<403>;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The publish API's types, COPIED from the service that serves them.
|
|
3
3
|
*
|
|
4
|
-
* Source: `content/src/handlers/Api.ts` in valbuild/home
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Source: `content/src/handlers/Api.ts` in valbuild/home. The routes below
|
|
5
|
+
* are that file's `/publish*` entries and the types they use, verbatim,
|
|
6
|
+
* comments included, so that the two can be diffed by eye: the publish
|
|
7
|
+
* lifecycle from branch `claude/new-project-studio-saves-0g9ksb`, commit
|
|
8
|
+
* `ecf3b8d`; the publish-job routes (`/publish-requests`, `/publish-jobs`)
|
|
9
|
+
* and `PublishRequestStatus` / `PublishTabJob` from `main`, commit `acb4a49`, with `/ci-runs`.
|
|
8
10
|
*
|
|
9
11
|
* **Copied rather than imported, because it cannot be imported.** That file
|
|
10
12
|
* lives in a private repository which publishes nothing to npm, and its own
|
|
@@ -23,6 +25,7 @@
|
|
|
23
25
|
* A copy is not a guarantee, only a tripwire: nothing checks it against the
|
|
24
26
|
* service, and the parsers in `protocol.ts` are what actually holds at runtime.
|
|
25
27
|
*/
|
|
28
|
+
import type { Json } from "@valbuild/core";
|
|
26
29
|
export type ContentPublishApi = {
|
|
27
30
|
/**
|
|
28
31
|
* Publishing a build, as a resource with a lifecycle.
|
|
@@ -175,6 +178,173 @@ export type ContentPublishApi = {
|
|
|
175
178
|
};
|
|
176
179
|
};
|
|
177
180
|
};
|
|
181
|
+
/**
|
|
182
|
+
* Publishing as a queued job: a press of Publish is a REQUEST, and returns
|
|
183
|
+
* at once. A job takes every queued request and everything pending; the tab
|
|
184
|
+
* that pressed runs its prepare (through the Val server), build and upload,
|
|
185
|
+
* reporting each step; then content runs verify and the seal itself. See
|
|
186
|
+
* docs/app-mode.md, "Publishing is a queued job".
|
|
187
|
+
*
|
|
188
|
+
* ```
|
|
189
|
+
* POST /publish-requests press -> the request, and a job to build
|
|
190
|
+
* GET /publish-requests/{id} where it is: queued, publishing, live, failed
|
|
191
|
+
* POST /publish-requests/try-again Try again: resume a paused queue, press anew
|
|
192
|
+
* POST /publish-jobs/next a free tab asks for queued work
|
|
193
|
+
* POST /publish-jobs/{id}/prepare the job's sources, archived (the Val server's)
|
|
194
|
+
* POST /publish-jobs/{id}/steps the tab reports build and upload
|
|
195
|
+
* POST /publish-jobs/{id}/renew the tab is still building
|
|
196
|
+
* POST /publish-jobs/{id}/cancel Cancel, before the seal
|
|
197
|
+
* POST /publish-jobs/{id}/discard Discard these changes, on a failed job
|
|
198
|
+
* ```
|
|
199
|
+
*
|
|
200
|
+
* Every id the Studio sends -- a request's, a tab's -- is its own, minted by
|
|
201
|
+
* it, `[A-Za-z0-9_-]{1,100}`. A press is idempotent on its request id; a step
|
|
202
|
+
* report names its step, so one retried after a lost answer does nothing
|
|
203
|
+
* twice.
|
|
204
|
+
*/
|
|
205
|
+
/**
|
|
206
|
+
* CI's own report of how a build of a git commit went, sent by the
|
|
207
|
+
* connected workflow's last step with its project token. See `ciRuns.ts`.
|
|
208
|
+
*/
|
|
209
|
+
"/ci-runs": {
|
|
210
|
+
POST: {
|
|
211
|
+
body: {
|
|
212
|
+
commit: string;
|
|
213
|
+
branch?: string;
|
|
214
|
+
status: "failed" | "succeeded";
|
|
215
|
+
url?: string;
|
|
216
|
+
};
|
|
217
|
+
res: {
|
|
218
|
+
recorded: true;
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
"/ci-runs/newest": {
|
|
223
|
+
GET: {
|
|
224
|
+
res: {
|
|
225
|
+
run: {
|
|
226
|
+
commit: string;
|
|
227
|
+
status: "failed" | "succeeded";
|
|
228
|
+
url: string | null;
|
|
229
|
+
} | null;
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
"/publish-requests": {
|
|
234
|
+
POST: {
|
|
235
|
+
body: {
|
|
236
|
+
requestId: string;
|
|
237
|
+
tab: string;
|
|
238
|
+
};
|
|
239
|
+
res: {
|
|
240
|
+
request: PublishRequestStatus;
|
|
241
|
+
job: PublishTabJob | null;
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
"/publish-requests/try-again": {
|
|
246
|
+
POST: {
|
|
247
|
+
body: {
|
|
248
|
+
requestId: string;
|
|
249
|
+
tab: string;
|
|
250
|
+
};
|
|
251
|
+
res: {
|
|
252
|
+
request: PublishRequestStatus;
|
|
253
|
+
job: PublishTabJob | null;
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
"/publish-requests/:requestId": {
|
|
258
|
+
GET: {
|
|
259
|
+
res: {
|
|
260
|
+
request: PublishRequestStatus;
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
};
|
|
264
|
+
"/publish-jobs/next": {
|
|
265
|
+
POST: {
|
|
266
|
+
body: {
|
|
267
|
+
tab: string;
|
|
268
|
+
};
|
|
269
|
+
res: {
|
|
270
|
+
job: PublishTabJob | null;
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
"/publish-jobs/:jobId/prepare": {
|
|
275
|
+
POST: {
|
|
276
|
+
/**
|
|
277
|
+
* `/commit`'s body, less what names a commit: the job's commit is minted
|
|
278
|
+
* at the seal. `modules` is required here -- a managed commit's archive,
|
|
279
|
+
* written from it, is the only copy of what it published.
|
|
280
|
+
*/
|
|
281
|
+
body: {
|
|
282
|
+
tab: string;
|
|
283
|
+
root: string;
|
|
284
|
+
filesDirectory?: string;
|
|
285
|
+
patchedSourceFiles: Record<string, string | null>;
|
|
286
|
+
patchedBinaryFilesDescriptors: Record<string, {
|
|
287
|
+
patchId: string;
|
|
288
|
+
remote?: boolean;
|
|
289
|
+
}>;
|
|
290
|
+
modules: Record<string, {
|
|
291
|
+
source: Json;
|
|
292
|
+
schema: Json;
|
|
293
|
+
}>;
|
|
294
|
+
/**
|
|
295
|
+
* Connected: the git commit the Studio's deployment was built from. A
|
|
296
|
+
* branch whose tip is that commit has nothing it has not seen.
|
|
297
|
+
*/
|
|
298
|
+
gitCommit?: string;
|
|
299
|
+
};
|
|
300
|
+
res: {
|
|
301
|
+
job: PublishTabJob | null;
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
"/publish-jobs/:jobId/steps": {
|
|
306
|
+
POST: {
|
|
307
|
+
body: {
|
|
308
|
+
tab: string;
|
|
309
|
+
step: "prepare" | "build" | "upload";
|
|
310
|
+
ok: boolean;
|
|
311
|
+
/** A finished build step: the id of the publish (`POST /publish`) it declared. */
|
|
312
|
+
build?: string;
|
|
313
|
+
};
|
|
314
|
+
res: {
|
|
315
|
+
job: PublishTabJob | null;
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
"/publish-jobs/:jobId/renew": {
|
|
320
|
+
POST: {
|
|
321
|
+
body: {
|
|
322
|
+
tab: string;
|
|
323
|
+
};
|
|
324
|
+
res: {
|
|
325
|
+
renewed: boolean;
|
|
326
|
+
};
|
|
327
|
+
};
|
|
328
|
+
};
|
|
329
|
+
"/publish-jobs/:jobId/cancel": {
|
|
330
|
+
POST: {
|
|
331
|
+
res: {
|
|
332
|
+
cancelled: boolean;
|
|
333
|
+
};
|
|
334
|
+
};
|
|
335
|
+
};
|
|
336
|
+
"/publish-jobs/:jobId/discard": {
|
|
337
|
+
POST: {
|
|
338
|
+
/** The forward closure, as `DELETE /patches` takes it. */
|
|
339
|
+
body: {
|
|
340
|
+
unstagePatchIds?: string[];
|
|
341
|
+
};
|
|
342
|
+
/** Changes it could not discard: another job in flight holds them. */
|
|
343
|
+
res: {
|
|
344
|
+
stillHeld: string[];
|
|
345
|
+
};
|
|
346
|
+
};
|
|
347
|
+
};
|
|
178
348
|
};
|
|
179
349
|
/**
|
|
180
350
|
* Where a publish is. Mirrors `PublishState` in `utils/publishPlan.ts`, which
|
|
@@ -199,3 +369,36 @@ export type PublishProblem = {
|
|
|
199
369
|
hint?: string;
|
|
200
370
|
keys?: string[];
|
|
201
371
|
};
|
|
372
|
+
/**
|
|
373
|
+
* Where a press of Publish is. `live` names the commit that carries it -- its
|
|
374
|
+
* own, or a newer one that contains it; `failed` names what the editor can do.
|
|
375
|
+
* The same shape as `RequestStatus` in `utils/jobPlan.ts`, which decides it.
|
|
376
|
+
*/
|
|
377
|
+
export type PublishRequestStatus = {
|
|
378
|
+
kind: "queued";
|
|
379
|
+
} | {
|
|
380
|
+
kind: "publishing";
|
|
381
|
+
} | {
|
|
382
|
+
kind: "live";
|
|
383
|
+
commit: string;
|
|
384
|
+
} | {
|
|
385
|
+
kind: "failed";
|
|
386
|
+
message: string;
|
|
387
|
+
actions: ("try-again" | "discard" | "re-run-build")[];
|
|
388
|
+
/** The job that failed: what Discard is pressed on. */
|
|
389
|
+
job: string;
|
|
390
|
+
} | {
|
|
391
|
+
kind: "cancelled";
|
|
392
|
+
} | {
|
|
393
|
+
kind: "nothing-to-publish";
|
|
394
|
+
};
|
|
395
|
+
/** What a tab needs to know about a job it is running. */
|
|
396
|
+
export type PublishTabJob = {
|
|
397
|
+
id: string;
|
|
398
|
+
/** The step the tab is to run next; null once the job is content's. */
|
|
399
|
+
step: "prepare" | "build" | "upload" | null;
|
|
400
|
+
/** The recorded commit its build is based on. */
|
|
401
|
+
base: string | null;
|
|
402
|
+
/** The changes its build is to include, on top of `base`. */
|
|
403
|
+
patches: string[];
|
|
404
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ContentPublishApi, PublishProblem, PublishState } from "./contentApi.js";
|
|
2
|
+
import { ContentPublishApi, PublishProblem, PublishRequestStatus, PublishState, PublishTabJob } from "./contentApi.js";
|
|
3
3
|
/**
|
|
4
4
|
* Reading what content answers.
|
|
5
5
|
*
|
|
@@ -115,8 +115,105 @@ declare const projectSourceResponse: z.ZodObject<{
|
|
|
115
115
|
publicPaths: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
116
116
|
}, z.core.$strip>;
|
|
117
117
|
export type ProjectSourceResponse = z.infer<typeof projectSourceResponse>;
|
|
118
|
+
/**
|
|
119
|
+
* Whether a managed project can be updated onto its template's current seed,
|
|
120
|
+
* and -- when it is asked with `POST`, the press -- what to build against.
|
|
121
|
+
*
|
|
122
|
+
* An update rebuilds the site as it is on newer dependencies. The loader
|
|
123
|
+
* decides whether there is one; content adds whether the project is managed at
|
|
124
|
+
* all, and the branch head the rebuild is wired at, because an update
|
|
125
|
+
* publishes no content of its own.
|
|
126
|
+
*
|
|
127
|
+
* `target` is a `/build-target` answer whose project half is the SEED's
|
|
128
|
+
* dependency layer, already copied into the project so a publish can name it.
|
|
129
|
+
* Only a `POST` carries it.
|
|
130
|
+
*/
|
|
131
|
+
declare const dependencyChange: z.ZodObject<{
|
|
132
|
+
name: z.ZodString;
|
|
133
|
+
section: z.ZodEnum<{
|
|
134
|
+
dependencies: "dependencies";
|
|
135
|
+
devDependencies: "devDependencies";
|
|
136
|
+
}>;
|
|
137
|
+
from: z.ZodNullable<z.ZodString>;
|
|
138
|
+
to: z.ZodNullable<z.ZodString>;
|
|
139
|
+
}, z.core.$strip>;
|
|
140
|
+
declare const updateTargetResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
141
|
+
status: z.ZodLiteral<"current">;
|
|
142
|
+
template: z.ZodString;
|
|
143
|
+
layerRev: z.ZodString;
|
|
144
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
145
|
+
status: z.ZodLiteral<"available">;
|
|
146
|
+
template: z.ZodString;
|
|
147
|
+
changes: z.ZodArray<z.ZodObject<{
|
|
148
|
+
name: z.ZodString;
|
|
149
|
+
section: z.ZodEnum<{
|
|
150
|
+
dependencies: "dependencies";
|
|
151
|
+
devDependencies: "devDependencies";
|
|
152
|
+
}>;
|
|
153
|
+
from: z.ZodNullable<z.ZodString>;
|
|
154
|
+
to: z.ZodNullable<z.ZodString>;
|
|
155
|
+
}, z.core.$strip>>;
|
|
156
|
+
layerRev: z.ZodObject<{
|
|
157
|
+
from: z.ZodNullable<z.ZodString>;
|
|
158
|
+
to: z.ZodString;
|
|
159
|
+
}, z.core.$strip>;
|
|
160
|
+
packageJson: z.ZodString;
|
|
161
|
+
commit: z.ZodNullable<z.ZodString>;
|
|
162
|
+
branch: z.ZodString;
|
|
163
|
+
target: z.ZodOptional<z.ZodObject<{
|
|
164
|
+
base: z.ZodObject<{
|
|
165
|
+
rev: z.ZodString;
|
|
166
|
+
shellRev: z.ZodString;
|
|
167
|
+
rscShellRev: z.ZodString;
|
|
168
|
+
modules: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
169
|
+
rscModules: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
170
|
+
paths: z.ZodObject<{
|
|
171
|
+
baseFromProject: z.ZodString;
|
|
172
|
+
projectVendorDir: z.ZodString;
|
|
173
|
+
rscVendorBase: z.ZodString;
|
|
174
|
+
rscRuntimeSpecifier: z.ZodString;
|
|
175
|
+
rscRuntimePath: z.ZodString;
|
|
176
|
+
flightServer: z.ZodString;
|
|
177
|
+
serverFnBase: z.ZodString;
|
|
178
|
+
}, z.core.$strip>;
|
|
179
|
+
}, z.core.$strip>;
|
|
180
|
+
project: z.ZodObject<{
|
|
181
|
+
rev: z.ZodNullable<z.ZodString>;
|
|
182
|
+
rsc: z.ZodBoolean;
|
|
183
|
+
modules: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
184
|
+
css: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
185
|
+
workerOnly: z.ZodArray<z.ZodString>;
|
|
186
|
+
}, z.core.$strip>;
|
|
187
|
+
}, z.core.$strip>>;
|
|
188
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
189
|
+
status: z.ZodLiteral<"unavailable">;
|
|
190
|
+
reason: z.ZodString;
|
|
191
|
+
message: z.ZodString;
|
|
192
|
+
}, z.core.$strip>], "status">;
|
|
193
|
+
export type UpdateTargetResponse = z.infer<typeof updateTargetResponse>;
|
|
194
|
+
export type DependencyChange = z.infer<typeof dependencyChange>;
|
|
195
|
+
export declare const parseUpdateTarget: (body: unknown) => UpdateTargetResponse;
|
|
118
196
|
export declare const parseBuildTarget: (body: unknown) => BuildTargetResponse;
|
|
119
197
|
export declare const parseProjectSource: (body: unknown) => ProjectSourceResponse;
|
|
198
|
+
export type { PublishRequestStatus, PublishTabJob };
|
|
199
|
+
export type PressResponse = ContentPublishApi["/publish-requests"]["POST"]["res"];
|
|
200
|
+
export type RequestStatusResponse = ContentPublishApi["/publish-requests/:requestId"]["GET"]["res"];
|
|
201
|
+
export type NextJobResponse = ContentPublishApi["/publish-jobs/next"]["POST"]["res"];
|
|
202
|
+
export type JobPrepareBody = ContentPublishApi["/publish-jobs/:jobId/prepare"]["POST"]["body"];
|
|
203
|
+
export type JobStepBody = ContentPublishApi["/publish-jobs/:jobId/steps"]["POST"]["body"];
|
|
204
|
+
export type JobStepResponse = ContentPublishApi["/publish-jobs/:jobId/steps"]["POST"]["res"];
|
|
205
|
+
export type JobRenewResponse = ContentPublishApi["/publish-jobs/:jobId/renew"]["POST"]["res"];
|
|
206
|
+
export type JobCancelResponse = ContentPublishApi["/publish-jobs/:jobId/cancel"]["POST"]["res"];
|
|
207
|
+
export type JobDiscardResponse = ContentPublishApi["/publish-jobs/:jobId/discard"]["POST"]["res"];
|
|
208
|
+
export declare const parsePress: (body: unknown, call: string) => PressResponse;
|
|
209
|
+
export declare const parseRequestStatus: (body: unknown) => RequestStatusResponse;
|
|
210
|
+
export declare const parseJob: (body: unknown, call: string) => JobStepResponse;
|
|
211
|
+
export declare const parseRenew: (body: unknown) => JobRenewResponse;
|
|
212
|
+
export declare const parseCancel: (body: unknown) => JobCancelResponse;
|
|
213
|
+
export declare const parseDiscard: (body: unknown) => JobDiscardResponse;
|
|
214
|
+
export type CiRunReportBody = ContentPublishApi["/ci-runs"]["POST"]["body"];
|
|
215
|
+
export type NewestCiRunResponse = ContentPublishApi["/ci-runs/newest"]["GET"]["res"];
|
|
216
|
+
export declare const parseNewestCiRun: (body: unknown) => NewestCiRunResponse;
|
|
120
217
|
/**
|
|
121
218
|
* The `details` of a refusal, when it carries a list of problems.
|
|
122
219
|
*
|