@valbuild/shared 0.134.0 → 0.136.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 +72 -0
- package/dist/declarations/src/internal/ApiRoutes.d.ts +2 -0
- package/internal/dist/valbuild-shared-internal.cjs.dev.js +90 -1
- package/internal/dist/valbuild-shared-internal.cjs.prod.js +90 -1
- package/internal/dist/valbuild-shared-internal.esm.js +90 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# @valbuild/shared
|
|
2
2
|
|
|
3
|
+
## 0.136.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#713](https://github.com/valbuild/val/pull/713) [`f3a4bb7`](https://github.com/valbuild/val/commit/f3a4bb7aea604943b92545c122243798c759715c) Thanks [@freekh](https://github.com/freekh)! - The Studio can load a bundler, and it stops telling a managed project that its
|
|
8
|
+
publish is on its way out.
|
|
9
|
+
|
|
10
|
+
**A managed project is one with no repository and no host watching one.** There
|
|
11
|
+
is nothing outside the browser to pick a commit up, so the Studio has been
|
|
12
|
+
showing it a story that belongs to a project with a repository: a `Building`
|
|
13
|
+
spinner, waiting for an event that can never arrive. It does not resolve on a
|
|
14
|
+
reload, on a retry, or tomorrow, and there is no way to tell it from a deploy
|
|
15
|
+
that is merely slow.
|
|
16
|
+
|
|
17
|
+
The content service now reports which kind of project this is, as `sourceMode`
|
|
18
|
+
on `/stat`, and the Studio narrates accordingly:
|
|
19
|
+
|
|
20
|
+
- a **connected** project keeps the deploy feed and keeps `Building`, because
|
|
21
|
+
there a host genuinely does pick the commit up;
|
|
22
|
+
- a **managed** one says `Saved, not yet live` instead — a durable condition,
|
|
23
|
+
not a phase, because nothing else will ever resolve it.
|
|
24
|
+
|
|
25
|
+
A server that reports no source mode keeps the behaviour it has today. Absence
|
|
26
|
+
means "not reported", never "managed": `fs` mode has no project to have a mode,
|
|
27
|
+
and neither does a content service that predates the field.
|
|
28
|
+
|
|
29
|
+
**The Studio also loads `@valbuild/tanstack-build` in the tab**, at mount and at
|
|
30
|
+
idle, for the managed projects that will need it — a browser that is the
|
|
31
|
+
deployer needs a bundler. This is the groundwork for browser-side publishing;
|
|
32
|
+
the publish path itself is unchanged in this release.
|
|
33
|
+
|
|
34
|
+
That bundler is `@rolldown/browser`, whose WebAssembly binary is 10.9 MB and is
|
|
35
|
+
**not** in the npm package. It is served from `static.val.build`, addressed by
|
|
36
|
+
the SHA-256 of its own bytes, so the build and the binary it needs cannot drift
|
|
37
|
+
apart. A deployment that must not reach that host — an air-gapped install, a
|
|
38
|
+
mirror — sets `globalThis.__VAL_ROLLDOWN_WASM_URL__` before the Studio loads and
|
|
39
|
+
needs no rebuild.
|
|
40
|
+
|
|
41
|
+
**Building in the browser requires a cross-origin isolated page.** Rolldown runs
|
|
42
|
+
WebAssembly on worker threads that share memory, and a browser will not hand a
|
|
43
|
+
`SharedArrayBuffer` to a worker otherwise. Without
|
|
44
|
+
`Cross-Origin-Opener-Policy: same-origin` and
|
|
45
|
+
`Cross-Origin-Embedder-Policy: require-corp` on the document Val is mounted in,
|
|
46
|
+
loading the bundler now fails with a message that says exactly that, instead of
|
|
47
|
+
a `DataCloneError` thrown from inside a worker. Nothing else in this release is
|
|
48
|
+
affected: a Studio that never builds in the browser never asks.
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- Updated dependencies [[`f3a4bb7`](https://github.com/valbuild/val/commit/f3a4bb7aea604943b92545c122243798c759715c)]:
|
|
53
|
+
- @valbuild/core@0.136.0
|
|
54
|
+
|
|
55
|
+
## 0.134.1
|
|
56
|
+
|
|
57
|
+
### Patch Changes
|
|
58
|
+
|
|
59
|
+
- [#709](https://github.com/valbuild/val/pull/709) [`821e789`](https://github.com/valbuild/val/commit/821e789c1af47510af5d23eb96384ff78ddd7646) Thanks [@freekh](https://github.com/freekh)! - Show the reason behind a content-service error instead of just "Internal Server
|
|
60
|
+
Error".
|
|
61
|
+
|
|
62
|
+
`content.val.build` answers a handler that threw with `{ message: "Internal
|
|
63
|
+
Server Error", details: "<the actual cause>" }`. Val was reading `message` and
|
|
64
|
+
dropping `details`, so a failed save put exactly this in front of an editor —
|
|
65
|
+
and the same text in the app's own logs, because Val was relaying it:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{ "type": "patch-error", "message": "Internal Server Error", "errors": { … } }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
A string `details` is now appended to the message (capped at 500 characters).
|
|
72
|
+
A structured one is not: that is what a _refusal_ carries, and its summary is
|
|
73
|
+
already the message.
|
|
74
|
+
|
|
3
75
|
## 0.134.0
|
|
4
76
|
|
|
5
77
|
### Minor Changes
|
|
@@ -423,6 +423,7 @@ export declare const Api: {
|
|
|
423
423
|
profileId: z.ZodNullable<z.ZodString>;
|
|
424
424
|
mode: z.ZodUnion<readonly [z.ZodLiteral<"http">, z.ZodLiteral<"fs">]>;
|
|
425
425
|
jsonEntriesSha: z.ZodOptional<z.ZodString>;
|
|
426
|
+
sourceMode: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"managed">, z.ZodLiteral<"connected">]>>;
|
|
426
427
|
publishRefusal: z.ZodOptional<z.ZodObject<{
|
|
427
428
|
code: z.ZodLiteral<"no-base">;
|
|
428
429
|
message: z.ZodString;
|
|
@@ -466,6 +467,7 @@ export declare const Api: {
|
|
|
466
467
|
}, z.core.$strip>;
|
|
467
468
|
profileId: z.ZodNullable<z.ZodString>;
|
|
468
469
|
mode: z.ZodUnion<readonly [z.ZodLiteral<"http">, z.ZodLiteral<"fs">]>;
|
|
470
|
+
sourceMode: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"managed">, z.ZodLiteral<"connected">]>>;
|
|
469
471
|
publishRefusal: z.ZodOptional<z.ZodObject<{
|
|
470
472
|
code: z.ZodLiteral<"no-base">;
|
|
471
473
|
message: z.ZodString;
|
|
@@ -1864,6 +1864,27 @@ var Api = {
|
|
|
1864
1864
|
profileId: zod.z.string().nullable(),
|
|
1865
1865
|
mode: zod.z.union([zod.z.literal("http"), zod.z.literal("fs")]),
|
|
1866
1866
|
jsonEntriesSha: zod.z.string().optional(),
|
|
1867
|
+
/**
|
|
1868
|
+
* How this project's SOURCE is kept, when the server knows.
|
|
1869
|
+
*
|
|
1870
|
+
* `"managed"` -- the content service is the store of record,
|
|
1871
|
+
* there is no repository, and the Studio is the deployer: the
|
|
1872
|
+
* build that makes a publish live happens in the tab that started
|
|
1873
|
+
* it. `"connected"` -- commits are mirrored into a repository a
|
|
1874
|
+
* host watches, so something outside the browser finishes the
|
|
1875
|
+
* job.
|
|
1876
|
+
*
|
|
1877
|
+
* The Studio narrates a publish differently for each, because a
|
|
1878
|
+
* `building` state in managed mode is a spinner with no event
|
|
1879
|
+
* that can ever end it -- not on a reload, not on a retry, not
|
|
1880
|
+
* tomorrow.
|
|
1881
|
+
*
|
|
1882
|
+
* Optional, and absent means "not reported", never "managed":
|
|
1883
|
+
* `fs` mode has no project to have a mode, and so does an `http`
|
|
1884
|
+
* server that predates the field. Both keep the connected story,
|
|
1885
|
+
* which is the one the Studio has always told.
|
|
1886
|
+
*/
|
|
1887
|
+
sourceMode: zod.z.union([zod.z.literal("managed"), zod.z.literal("connected")]).optional(),
|
|
1867
1888
|
publishRefusal: PublishRefusal.optional()
|
|
1868
1889
|
}), zod.z.object({
|
|
1869
1890
|
type: zod.z.literal("use-websocket"),
|
|
@@ -1926,6 +1947,27 @@ var Api = {
|
|
|
1926
1947
|
config: ValConfig,
|
|
1927
1948
|
profileId: zod.z.string().nullable(),
|
|
1928
1949
|
mode: zod.z.union([zod.z.literal("http"), zod.z.literal("fs")]),
|
|
1950
|
+
/**
|
|
1951
|
+
* How this project's SOURCE is kept, when the server knows.
|
|
1952
|
+
*
|
|
1953
|
+
* `"managed"` -- the content service is the store of record,
|
|
1954
|
+
* there is no repository, and the Studio is the deployer: the
|
|
1955
|
+
* build that makes a publish live happens in the tab that started
|
|
1956
|
+
* it. `"connected"` -- commits are mirrored into a repository a
|
|
1957
|
+
* host watches, so something outside the browser finishes the
|
|
1958
|
+
* job.
|
|
1959
|
+
*
|
|
1960
|
+
* The Studio narrates a publish differently for each, because a
|
|
1961
|
+
* `building` state in managed mode is a spinner with no event
|
|
1962
|
+
* that can ever end it -- not on a reload, not on a retry, not
|
|
1963
|
+
* tomorrow.
|
|
1964
|
+
*
|
|
1965
|
+
* Optional, and absent means "not reported", never "managed":
|
|
1966
|
+
* `fs` mode has no project to have a mode, and so does an `http`
|
|
1967
|
+
* server that predates the field. Both keep the connected story,
|
|
1968
|
+
* which is the one the Studio has always told.
|
|
1969
|
+
*/
|
|
1970
|
+
sourceMode: zod.z.union([zod.z.literal("managed"), zod.z.literal("connected")]).optional(),
|
|
1929
1971
|
publishRefusal: PublishRefusal.optional()
|
|
1930
1972
|
})])
|
|
1931
1973
|
})])
|
|
@@ -3057,12 +3099,59 @@ var Api = {
|
|
|
3057
3099
|
// `number` is allowed because the client stringifies every query value before it
|
|
3058
3100
|
// goes on the URL (see createValClient), so a numeric param round-trips fine.
|
|
3059
3101
|
|
|
3102
|
+
/**
|
|
3103
|
+
* How long an appended `details` may be before it is cut.
|
|
3104
|
+
*
|
|
3105
|
+
* A thrown DAL error in the content service quotes the whole offending ROW back
|
|
3106
|
+
* — which for a patch is every op the editor just made — so an uncapped append
|
|
3107
|
+
* puts kilobytes of JSON in a dialog. The head is where the cause is; the tail
|
|
3108
|
+
* is the evidence, and it belongs in the service's own logs.
|
|
3109
|
+
*/
|
|
3110
|
+
var MAX_DETAILS_LENGTH = 500;
|
|
3060
3111
|
function getErrorMessageFromUnknownJson(json, fallback) {
|
|
3061
3112
|
if (getSitemapTree._typeof(json) === "object" && json !== null && "message" in json && typeof json.message === "string") {
|
|
3062
|
-
|
|
3113
|
+
var details = detailsOf(json);
|
|
3114
|
+
if (details === null || details === json.message) {
|
|
3115
|
+
return json.message;
|
|
3116
|
+
}
|
|
3117
|
+
return "".concat(json.message, ": ").concat(details);
|
|
3063
3118
|
}
|
|
3064
3119
|
return fallback;
|
|
3065
3120
|
}
|
|
3121
|
+
|
|
3122
|
+
/**
|
|
3123
|
+
* The cause the content service put beside its message, when it wrote one a
|
|
3124
|
+
* person can read.
|
|
3125
|
+
*
|
|
3126
|
+
* `HttpError` in `home` is `{ statusCode, message?, details? }`, and `details`
|
|
3127
|
+
* is filled in two quite different ways. Where a handler REFUSED, it holds the
|
|
3128
|
+
* structured zod error whose summary is already the `message` — repeating it
|
|
3129
|
+
* adds nothing. Where a handler THREW, `sendResult` writes `message:
|
|
3130
|
+
* "Internal Server Error"` and puts the exception's own message in `details` —
|
|
3131
|
+
* so there the message says nothing and the details say everything.
|
|
3132
|
+
*
|
|
3133
|
+
* Which is why the test is the TYPE rather than the status code: a string
|
|
3134
|
+
* `details` is prose meant to be read, an object is a payload meant to be
|
|
3135
|
+
* parsed. This takes the first and leaves the second.
|
|
3136
|
+
*
|
|
3137
|
+
* It was written after an hour was lost to the second case. A patch save
|
|
3138
|
+
* against a content service that threw showed the Studio exactly
|
|
3139
|
+
* `"Internal Server Error"` and nothing else, in a dialog with no other clue,
|
|
3140
|
+
* while the service's answer had been carrying the reason the whole time.
|
|
3141
|
+
*/
|
|
3142
|
+
function detailsOf(json) {
|
|
3143
|
+
if (!("details" in json) || typeof json.details !== "string") {
|
|
3144
|
+
return null;
|
|
3145
|
+
}
|
|
3146
|
+
var details = json.details.trim();
|
|
3147
|
+
if (details === "") {
|
|
3148
|
+
return null;
|
|
3149
|
+
}
|
|
3150
|
+
if (details.length <= MAX_DETAILS_LENGTH) {
|
|
3151
|
+
return details;
|
|
3152
|
+
}
|
|
3153
|
+
return "".concat(details.slice(0, MAX_DETAILS_LENGTH), "\u2026");
|
|
3154
|
+
}
|
|
3066
3155
|
var DEFAULT_ERROR_MESSAGE = "Unknown error with unknown message from server";
|
|
3067
3156
|
|
|
3068
3157
|
var createValClient = function createValClient(host, config // We want to use this in the future
|
|
@@ -1864,6 +1864,27 @@ var Api = {
|
|
|
1864
1864
|
profileId: zod.z.string().nullable(),
|
|
1865
1865
|
mode: zod.z.union([zod.z.literal("http"), zod.z.literal("fs")]),
|
|
1866
1866
|
jsonEntriesSha: zod.z.string().optional(),
|
|
1867
|
+
/**
|
|
1868
|
+
* How this project's SOURCE is kept, when the server knows.
|
|
1869
|
+
*
|
|
1870
|
+
* `"managed"` -- the content service is the store of record,
|
|
1871
|
+
* there is no repository, and the Studio is the deployer: the
|
|
1872
|
+
* build that makes a publish live happens in the tab that started
|
|
1873
|
+
* it. `"connected"` -- commits are mirrored into a repository a
|
|
1874
|
+
* host watches, so something outside the browser finishes the
|
|
1875
|
+
* job.
|
|
1876
|
+
*
|
|
1877
|
+
* The Studio narrates a publish differently for each, because a
|
|
1878
|
+
* `building` state in managed mode is a spinner with no event
|
|
1879
|
+
* that can ever end it -- not on a reload, not on a retry, not
|
|
1880
|
+
* tomorrow.
|
|
1881
|
+
*
|
|
1882
|
+
* Optional, and absent means "not reported", never "managed":
|
|
1883
|
+
* `fs` mode has no project to have a mode, and so does an `http`
|
|
1884
|
+
* server that predates the field. Both keep the connected story,
|
|
1885
|
+
* which is the one the Studio has always told.
|
|
1886
|
+
*/
|
|
1887
|
+
sourceMode: zod.z.union([zod.z.literal("managed"), zod.z.literal("connected")]).optional(),
|
|
1867
1888
|
publishRefusal: PublishRefusal.optional()
|
|
1868
1889
|
}), zod.z.object({
|
|
1869
1890
|
type: zod.z.literal("use-websocket"),
|
|
@@ -1926,6 +1947,27 @@ var Api = {
|
|
|
1926
1947
|
config: ValConfig,
|
|
1927
1948
|
profileId: zod.z.string().nullable(),
|
|
1928
1949
|
mode: zod.z.union([zod.z.literal("http"), zod.z.literal("fs")]),
|
|
1950
|
+
/**
|
|
1951
|
+
* How this project's SOURCE is kept, when the server knows.
|
|
1952
|
+
*
|
|
1953
|
+
* `"managed"` -- the content service is the store of record,
|
|
1954
|
+
* there is no repository, and the Studio is the deployer: the
|
|
1955
|
+
* build that makes a publish live happens in the tab that started
|
|
1956
|
+
* it. `"connected"` -- commits are mirrored into a repository a
|
|
1957
|
+
* host watches, so something outside the browser finishes the
|
|
1958
|
+
* job.
|
|
1959
|
+
*
|
|
1960
|
+
* The Studio narrates a publish differently for each, because a
|
|
1961
|
+
* `building` state in managed mode is a spinner with no event
|
|
1962
|
+
* that can ever end it -- not on a reload, not on a retry, not
|
|
1963
|
+
* tomorrow.
|
|
1964
|
+
*
|
|
1965
|
+
* Optional, and absent means "not reported", never "managed":
|
|
1966
|
+
* `fs` mode has no project to have a mode, and so does an `http`
|
|
1967
|
+
* server that predates the field. Both keep the connected story,
|
|
1968
|
+
* which is the one the Studio has always told.
|
|
1969
|
+
*/
|
|
1970
|
+
sourceMode: zod.z.union([zod.z.literal("managed"), zod.z.literal("connected")]).optional(),
|
|
1929
1971
|
publishRefusal: PublishRefusal.optional()
|
|
1930
1972
|
})])
|
|
1931
1973
|
})])
|
|
@@ -3057,12 +3099,59 @@ var Api = {
|
|
|
3057
3099
|
// `number` is allowed because the client stringifies every query value before it
|
|
3058
3100
|
// goes on the URL (see createValClient), so a numeric param round-trips fine.
|
|
3059
3101
|
|
|
3102
|
+
/**
|
|
3103
|
+
* How long an appended `details` may be before it is cut.
|
|
3104
|
+
*
|
|
3105
|
+
* A thrown DAL error in the content service quotes the whole offending ROW back
|
|
3106
|
+
* — which for a patch is every op the editor just made — so an uncapped append
|
|
3107
|
+
* puts kilobytes of JSON in a dialog. The head is where the cause is; the tail
|
|
3108
|
+
* is the evidence, and it belongs in the service's own logs.
|
|
3109
|
+
*/
|
|
3110
|
+
var MAX_DETAILS_LENGTH = 500;
|
|
3060
3111
|
function getErrorMessageFromUnknownJson(json, fallback) {
|
|
3061
3112
|
if (getSitemapTree._typeof(json) === "object" && json !== null && "message" in json && typeof json.message === "string") {
|
|
3062
|
-
|
|
3113
|
+
var details = detailsOf(json);
|
|
3114
|
+
if (details === null || details === json.message) {
|
|
3115
|
+
return json.message;
|
|
3116
|
+
}
|
|
3117
|
+
return "".concat(json.message, ": ").concat(details);
|
|
3063
3118
|
}
|
|
3064
3119
|
return fallback;
|
|
3065
3120
|
}
|
|
3121
|
+
|
|
3122
|
+
/**
|
|
3123
|
+
* The cause the content service put beside its message, when it wrote one a
|
|
3124
|
+
* person can read.
|
|
3125
|
+
*
|
|
3126
|
+
* `HttpError` in `home` is `{ statusCode, message?, details? }`, and `details`
|
|
3127
|
+
* is filled in two quite different ways. Where a handler REFUSED, it holds the
|
|
3128
|
+
* structured zod error whose summary is already the `message` — repeating it
|
|
3129
|
+
* adds nothing. Where a handler THREW, `sendResult` writes `message:
|
|
3130
|
+
* "Internal Server Error"` and puts the exception's own message in `details` —
|
|
3131
|
+
* so there the message says nothing and the details say everything.
|
|
3132
|
+
*
|
|
3133
|
+
* Which is why the test is the TYPE rather than the status code: a string
|
|
3134
|
+
* `details` is prose meant to be read, an object is a payload meant to be
|
|
3135
|
+
* parsed. This takes the first and leaves the second.
|
|
3136
|
+
*
|
|
3137
|
+
* It was written after an hour was lost to the second case. A patch save
|
|
3138
|
+
* against a content service that threw showed the Studio exactly
|
|
3139
|
+
* `"Internal Server Error"` and nothing else, in a dialog with no other clue,
|
|
3140
|
+
* while the service's answer had been carrying the reason the whole time.
|
|
3141
|
+
*/
|
|
3142
|
+
function detailsOf(json) {
|
|
3143
|
+
if (!("details" in json) || typeof json.details !== "string") {
|
|
3144
|
+
return null;
|
|
3145
|
+
}
|
|
3146
|
+
var details = json.details.trim();
|
|
3147
|
+
if (details === "") {
|
|
3148
|
+
return null;
|
|
3149
|
+
}
|
|
3150
|
+
if (details.length <= MAX_DETAILS_LENGTH) {
|
|
3151
|
+
return details;
|
|
3152
|
+
}
|
|
3153
|
+
return "".concat(details.slice(0, MAX_DETAILS_LENGTH), "\u2026");
|
|
3154
|
+
}
|
|
3066
3155
|
var DEFAULT_ERROR_MESSAGE = "Unknown error with unknown message from server";
|
|
3067
3156
|
|
|
3068
3157
|
var createValClient = function createValClient(host, config // We want to use this in the future
|
|
@@ -1857,6 +1857,27 @@ var Api = {
|
|
|
1857
1857
|
profileId: z.string().nullable(),
|
|
1858
1858
|
mode: z.union([z.literal("http"), z.literal("fs")]),
|
|
1859
1859
|
jsonEntriesSha: z.string().optional(),
|
|
1860
|
+
/**
|
|
1861
|
+
* How this project's SOURCE is kept, when the server knows.
|
|
1862
|
+
*
|
|
1863
|
+
* `"managed"` -- the content service is the store of record,
|
|
1864
|
+
* there is no repository, and the Studio is the deployer: the
|
|
1865
|
+
* build that makes a publish live happens in the tab that started
|
|
1866
|
+
* it. `"connected"` -- commits are mirrored into a repository a
|
|
1867
|
+
* host watches, so something outside the browser finishes the
|
|
1868
|
+
* job.
|
|
1869
|
+
*
|
|
1870
|
+
* The Studio narrates a publish differently for each, because a
|
|
1871
|
+
* `building` state in managed mode is a spinner with no event
|
|
1872
|
+
* that can ever end it -- not on a reload, not on a retry, not
|
|
1873
|
+
* tomorrow.
|
|
1874
|
+
*
|
|
1875
|
+
* Optional, and absent means "not reported", never "managed":
|
|
1876
|
+
* `fs` mode has no project to have a mode, and so does an `http`
|
|
1877
|
+
* server that predates the field. Both keep the connected story,
|
|
1878
|
+
* which is the one the Studio has always told.
|
|
1879
|
+
*/
|
|
1880
|
+
sourceMode: z.union([z.literal("managed"), z.literal("connected")]).optional(),
|
|
1860
1881
|
publishRefusal: PublishRefusal.optional()
|
|
1861
1882
|
}), z.object({
|
|
1862
1883
|
type: z.literal("use-websocket"),
|
|
@@ -1919,6 +1940,27 @@ var Api = {
|
|
|
1919
1940
|
config: ValConfig,
|
|
1920
1941
|
profileId: z.string().nullable(),
|
|
1921
1942
|
mode: z.union([z.literal("http"), z.literal("fs")]),
|
|
1943
|
+
/**
|
|
1944
|
+
* How this project's SOURCE is kept, when the server knows.
|
|
1945
|
+
*
|
|
1946
|
+
* `"managed"` -- the content service is the store of record,
|
|
1947
|
+
* there is no repository, and the Studio is the deployer: the
|
|
1948
|
+
* build that makes a publish live happens in the tab that started
|
|
1949
|
+
* it. `"connected"` -- commits are mirrored into a repository a
|
|
1950
|
+
* host watches, so something outside the browser finishes the
|
|
1951
|
+
* job.
|
|
1952
|
+
*
|
|
1953
|
+
* The Studio narrates a publish differently for each, because a
|
|
1954
|
+
* `building` state in managed mode is a spinner with no event
|
|
1955
|
+
* that can ever end it -- not on a reload, not on a retry, not
|
|
1956
|
+
* tomorrow.
|
|
1957
|
+
*
|
|
1958
|
+
* Optional, and absent means "not reported", never "managed":
|
|
1959
|
+
* `fs` mode has no project to have a mode, and so does an `http`
|
|
1960
|
+
* server that predates the field. Both keep the connected story,
|
|
1961
|
+
* which is the one the Studio has always told.
|
|
1962
|
+
*/
|
|
1963
|
+
sourceMode: z.union([z.literal("managed"), z.literal("connected")]).optional(),
|
|
1922
1964
|
publishRefusal: PublishRefusal.optional()
|
|
1923
1965
|
})])
|
|
1924
1966
|
})])
|
|
@@ -3050,12 +3092,59 @@ var Api = {
|
|
|
3050
3092
|
// `number` is allowed because the client stringifies every query value before it
|
|
3051
3093
|
// goes on the URL (see createValClient), so a numeric param round-trips fine.
|
|
3052
3094
|
|
|
3095
|
+
/**
|
|
3096
|
+
* How long an appended `details` may be before it is cut.
|
|
3097
|
+
*
|
|
3098
|
+
* A thrown DAL error in the content service quotes the whole offending ROW back
|
|
3099
|
+
* — which for a patch is every op the editor just made — so an uncapped append
|
|
3100
|
+
* puts kilobytes of JSON in a dialog. The head is where the cause is; the tail
|
|
3101
|
+
* is the evidence, and it belongs in the service's own logs.
|
|
3102
|
+
*/
|
|
3103
|
+
var MAX_DETAILS_LENGTH = 500;
|
|
3053
3104
|
function getErrorMessageFromUnknownJson(json, fallback) {
|
|
3054
3105
|
if (_typeof(json) === "object" && json !== null && "message" in json && typeof json.message === "string") {
|
|
3055
|
-
|
|
3106
|
+
var details = detailsOf(json);
|
|
3107
|
+
if (details === null || details === json.message) {
|
|
3108
|
+
return json.message;
|
|
3109
|
+
}
|
|
3110
|
+
return "".concat(json.message, ": ").concat(details);
|
|
3056
3111
|
}
|
|
3057
3112
|
return fallback;
|
|
3058
3113
|
}
|
|
3114
|
+
|
|
3115
|
+
/**
|
|
3116
|
+
* The cause the content service put beside its message, when it wrote one a
|
|
3117
|
+
* person can read.
|
|
3118
|
+
*
|
|
3119
|
+
* `HttpError` in `home` is `{ statusCode, message?, details? }`, and `details`
|
|
3120
|
+
* is filled in two quite different ways. Where a handler REFUSED, it holds the
|
|
3121
|
+
* structured zod error whose summary is already the `message` — repeating it
|
|
3122
|
+
* adds nothing. Where a handler THREW, `sendResult` writes `message:
|
|
3123
|
+
* "Internal Server Error"` and puts the exception's own message in `details` —
|
|
3124
|
+
* so there the message says nothing and the details say everything.
|
|
3125
|
+
*
|
|
3126
|
+
* Which is why the test is the TYPE rather than the status code: a string
|
|
3127
|
+
* `details` is prose meant to be read, an object is a payload meant to be
|
|
3128
|
+
* parsed. This takes the first and leaves the second.
|
|
3129
|
+
*
|
|
3130
|
+
* It was written after an hour was lost to the second case. A patch save
|
|
3131
|
+
* against a content service that threw showed the Studio exactly
|
|
3132
|
+
* `"Internal Server Error"` and nothing else, in a dialog with no other clue,
|
|
3133
|
+
* while the service's answer had been carrying the reason the whole time.
|
|
3134
|
+
*/
|
|
3135
|
+
function detailsOf(json) {
|
|
3136
|
+
if (!("details" in json) || typeof json.details !== "string") {
|
|
3137
|
+
return null;
|
|
3138
|
+
}
|
|
3139
|
+
var details = json.details.trim();
|
|
3140
|
+
if (details === "") {
|
|
3141
|
+
return null;
|
|
3142
|
+
}
|
|
3143
|
+
if (details.length <= MAX_DETAILS_LENGTH) {
|
|
3144
|
+
return details;
|
|
3145
|
+
}
|
|
3146
|
+
return "".concat(details.slice(0, MAX_DETAILS_LENGTH), "\u2026");
|
|
3147
|
+
}
|
|
3059
3148
|
var DEFAULT_ERROR_MESSAGE = "Unknown error with unknown message from server";
|
|
3060
3149
|
|
|
3061
3150
|
var createValClient = function createValClient(host, config // We want to use this in the future
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valbuild/shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.136.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Val shared types and utilities",
|
|
6
6
|
"repository": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"flexsearch": "^0.8.212",
|
|
38
38
|
"zod": "^4.4.3",
|
|
39
39
|
"zod-validation-error": "^5.0.0",
|
|
40
|
-
"@valbuild/core": "0.
|
|
40
|
+
"@valbuild/core": "0.136.0"
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
43
|
"CHANGELOG.md",
|