@valbuild/shared 0.139.0 → 0.140.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,36 @@
1
1
  # @valbuild/shared
2
2
 
3
+ ## 0.140.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#769](https://github.com/valbuild/val/pull/769) [`cb93874`](https://github.com/valbuild/val/commit/cb938748aec15fd0ac3814c1696a2dd78ad63c27) Thanks [@freekh](https://github.com/freekh)! - The project name in the Studio's top bar is now a project switcher, for projects connected to Val Build. It shows the project you are in, the projects you pinned and the five you opened most recently, and searches every project in your organisations. Choosing one opens its Studio.
8
+
9
+ The top bar also gets a **Share** button (an icon on a phone). It shows who is in the project's organisation. Owners can create invite links for a role (each works once and expires after 7 days), see and revoke pending links, and change members' roles. Everyone else can see the members and which owners to ask.
10
+
11
+ The assistant can be set up from the Studio too. Settings › Assistant shows the AI key this project runs on and whether it works. From there you can add a key, update it, remove it, or choose one that already exists: the organisation's, your own, or another project's. The assistant's empty state offers the same when no key is set up. Every key is checked with the provider before it is saved, and once a key is saved the assistant turns on without a reload.
12
+
13
+ The panels are served by Val's content server (`content.val.build/wc/v1/project-switcher.js`, `members.js` and `ai-setup.js`), beside the API they read and write, so they can improve without a Val release. The Studio draws the project name and the Share button itself, and loads the switcher and Share panels only when the button is first hovered or clicked, so opening the Studio fetches nothing extra. If a panel cannot load, for example offline or under a strict Content Security Policy, the click opens the same page in Val Build instead, and the AI setup is a link to the project's AI keys there. If your app sets a CSP, allow `script-src https://content.val.build` to get them.
14
+
15
+ They reach Val Build through a new route on your app's Val server, `/api/val/admin/proxy/*`, which adds the editor's existing Val Build session. That route forwards only to the Studio API on Val's content server (`/v1/studio/*` on `VAL_CONTENT_URL`, `https://content.val.build` by default), and only with the `x-val-studio` header that a cross-site request cannot send.
16
+
17
+ In local development they appear once you have run `val login`, and use that login. Without one the Studio keeps the plain project name, as before; it does not load them just to say you are not logged in.
18
+
19
+ ## 0.139.1
20
+
21
+ ### Patch Changes
22
+
23
+ - [#781](https://github.com/valbuild/val/pull/781) [`5ea70ce`](https://github.com/valbuild/val/commit/5ea70cefde3c74961cfa76b4a5f4c333b850b60a) Thanks [@freekh](https://github.com/freekh)! - Every open Studio now shows the same changes, staged the same way, as a reload would.
24
+
25
+ - Staging or unstaging a change in one browser or tab now shows up in your other open Studios right away, without a reload, and publishing from any of them ships the same set.
26
+ - A change you stage before you have made any edit of your own is saved straight away, instead of being kept in the tab until your first edit and lost if you reloaded first.
27
+ - If staging a change fails, the Studio now goes back to showing what is actually saved, instead of keeping the failed change on screen until a reload.
28
+
29
+ This needs the Val Build content service released alongside this version.
30
+
31
+ - Updated dependencies [[`db13bed`](https://github.com/valbuild/val/commit/db13bed902f9f9147feb5be07ce47fe8b5b143f9)]:
32
+ - @valbuild/core@0.139.1
33
+
3
34
  ## 0.139.0
4
35
 
5
36
  ### Minor Changes
@@ -1,6 +1,12 @@
1
1
  import { z } from "zod";
2
2
  import { type ModuleFilePath } from "@valbuild/core";
3
3
  declare const ModuleFilePath: z.ZodString & z.ZodType<ModuleFilePath, string, z.core.$ZodTypeInternals<ModuleFilePath, string>>;
4
+ /**
5
+ * The header a request to `/admin/proxy` must carry. A cross-site form or
6
+ * `<img>` cannot set a custom header, so without it the proxy cannot be driven
7
+ * with the editor's cookie from another site.
8
+ */
9
+ export declare const VAL_STUDIO_HEADER = "x-val-studio";
4
10
  /**
5
11
  * A patch group: the set of patches one user has chosen to publish.
6
12
  *
@@ -442,6 +448,13 @@ export declare const Api: {
442
448
  headCommitSha: z.ZodOptional<z.ZodString>;
443
449
  headPatchId: z.ZodOptional<z.ZodNullable<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>>;
444
450
  headVersion: z.ZodOptional<z.ZodNumber>;
451
+ patchGroups: z.ZodOptional<z.ZodArray<z.ZodObject<{
452
+ patchGroupId: z.ZodString;
453
+ authorId: z.ZodNullable<z.ZodString>;
454
+ createdAt: z.ZodString;
455
+ publishedAt: z.ZodNullable<z.ZodString>;
456
+ patchIds: z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>;
457
+ }, z.core.$strip>>>;
445
458
  commits: z.ZodArray<z.ZodObject<{
446
459
  commitSha: z.ZodString;
447
460
  clientCommitSha: z.ZodNullable<z.ZodString>;
@@ -863,7 +876,7 @@ export declare const Api: {
863
876
  PUT: {
864
877
  req: {
865
878
  body: z.ZodObject<{
866
- patchGroupId: z.ZodString;
879
+ patchGroupId: z.ZodOptional<z.ZodString>;
867
880
  patchIds: z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>;
868
881
  withPatchIds: z.ZodOptional<z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>>;
869
882
  }, z.core.$strip>;
@@ -894,15 +907,16 @@ export declare const Api: {
894
907
  }, z.core.$strip>, z.ZodObject<{
895
908
  status: z.ZodLiteral<200>;
896
909
  json: z.ZodObject<{
897
- patchGroupId: z.ZodString;
910
+ patchGroupId: z.ZodNullable<z.ZodString>;
898
911
  patchIds: z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>;
912
+ headVersion: z.ZodOptional<z.ZodNumber>;
899
913
  }, z.core.$strip>;
900
914
  }, z.core.$strip>]>;
901
915
  };
902
916
  DELETE: {
903
917
  req: {
904
918
  body: z.ZodObject<{
905
- patchGroupId: z.ZodString;
919
+ patchGroupId: z.ZodOptional<z.ZodString>;
906
920
  patchIds: z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>;
907
921
  withPatchIds: z.ZodOptional<z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>>;
908
922
  }, z.core.$strip>;
@@ -933,8 +947,9 @@ export declare const Api: {
933
947
  }, z.core.$strip>, z.ZodObject<{
934
948
  status: z.ZodLiteral<200>;
935
949
  json: z.ZodObject<{
936
- patchGroupId: z.ZodString;
950
+ patchGroupId: z.ZodNullable<z.ZodString>;
937
951
  patchIds: z.ZodArray<z.ZodString & z.ZodType<import("@valbuild/core").PatchId, string, z.core.$ZodTypeInternals<import("@valbuild/core").PatchId, string>>>;
952
+ headVersion: z.ZodOptional<z.ZodNumber>;
938
953
  }, z.core.$strip>;
939
954
  }, z.core.$strip>]>;
940
955
  };
@@ -1966,6 +1981,95 @@ export declare const Api: {
1966
1981
  }, z.core.$strip>]>;
1967
1982
  };
1968
1983
  };
1984
+ "/admin/status": {
1985
+ GET: {
1986
+ req: {
1987
+ cookies: {
1988
+ val_session: z.ZodOptional<z.ZodString>;
1989
+ };
1990
+ };
1991
+ res: z.ZodObject<{
1992
+ status: z.ZodLiteral<200>;
1993
+ json: z.ZodObject<{
1994
+ connected: z.ZodBoolean;
1995
+ signIn: z.ZodOptional<z.ZodEnum<{
1996
+ "val-login": "val-login";
1997
+ studio: "studio";
1998
+ }>>;
1999
+ }, z.core.$strip>;
2000
+ }, z.core.$strip>;
2001
+ };
2002
+ };
2003
+ "/admin/proxy": {
2004
+ GET: {
2005
+ req: {
2006
+ path: z.ZodString;
2007
+ rawQuery: z.ZodString;
2008
+ headers: {
2009
+ "x-val-studio": z.ZodOptional<z.ZodString>;
2010
+ };
2011
+ cookies: {
2012
+ val_session: z.ZodOptional<z.ZodString>;
2013
+ };
2014
+ body: z.ZodUnknown;
2015
+ };
2016
+ res: z.ZodObject<{
2017
+ status: z.ZodUnion<readonly [z.ZodLiteral<200>, z.ZodLiteral<400>, z.ZodLiteral<401>, z.ZodLiteral<403>, z.ZodLiteral<404>, z.ZodLiteral<500>]>;
2018
+ json: z.ZodUnknown;
2019
+ }, z.core.$strip>;
2020
+ };
2021
+ POST: {
2022
+ req: {
2023
+ path: z.ZodString;
2024
+ rawQuery: z.ZodString;
2025
+ headers: {
2026
+ "x-val-studio": z.ZodOptional<z.ZodString>;
2027
+ };
2028
+ cookies: {
2029
+ val_session: z.ZodOptional<z.ZodString>;
2030
+ };
2031
+ body: z.ZodUnknown;
2032
+ };
2033
+ res: z.ZodObject<{
2034
+ status: z.ZodUnion<readonly [z.ZodLiteral<200>, z.ZodLiteral<400>, z.ZodLiteral<401>, z.ZodLiteral<403>, z.ZodLiteral<404>, z.ZodLiteral<500>]>;
2035
+ json: z.ZodUnknown;
2036
+ }, z.core.$strip>;
2037
+ };
2038
+ PUT: {
2039
+ req: {
2040
+ path: z.ZodString;
2041
+ rawQuery: z.ZodString;
2042
+ headers: {
2043
+ "x-val-studio": z.ZodOptional<z.ZodString>;
2044
+ };
2045
+ cookies: {
2046
+ val_session: z.ZodOptional<z.ZodString>;
2047
+ };
2048
+ body: z.ZodUnknown;
2049
+ };
2050
+ res: z.ZodObject<{
2051
+ status: z.ZodUnion<readonly [z.ZodLiteral<200>, z.ZodLiteral<400>, z.ZodLiteral<401>, z.ZodLiteral<403>, z.ZodLiteral<404>, z.ZodLiteral<500>]>;
2052
+ json: z.ZodUnknown;
2053
+ }, z.core.$strip>;
2054
+ };
2055
+ DELETE: {
2056
+ req: {
2057
+ path: z.ZodString;
2058
+ rawQuery: z.ZodString;
2059
+ headers: {
2060
+ "x-val-studio": z.ZodOptional<z.ZodString>;
2061
+ };
2062
+ cookies: {
2063
+ val_session: z.ZodOptional<z.ZodString>;
2064
+ };
2065
+ body: z.ZodUnknown;
2066
+ };
2067
+ res: z.ZodObject<{
2068
+ status: z.ZodUnion<readonly [z.ZodLiteral<200>, z.ZodLiteral<400>, z.ZodLiteral<401>, z.ZodLiteral<403>, z.ZodLiteral<404>, z.ZodLiteral<500>]>;
2069
+ json: z.ZodUnknown;
2070
+ }, z.core.$strip>;
2071
+ };
2072
+ };
1969
2073
  };
1970
2074
  /**
1971
2075
  * Extracts the keys of an object where the value is not undefined.
@@ -1999,6 +2103,16 @@ export type ApiEndpoint = {
1999
2103
  body?: z.ZodTypeAny;
2000
2104
  query?: Record<string, z.ZodSchema<ValidQueryParamTypes, string[] | undefined>>;
2001
2105
  cookies?: Record<string, z.ZodSchema<string | undefined>>;
2106
+ /**
2107
+ * Request headers, by lower-case name, parsed the way `cookies` are.
2108
+ * Absent ones are `undefined`.
2109
+ */
2110
+ headers?: Record<string, z.ZodSchema<string | undefined>>;
2111
+ /**
2112
+ * The query string exactly as sent (`?a=1&b=2`, or `""`), for a route that
2113
+ * forwards it rather than reading it. `query` is for routes that read it.
2114
+ */
2115
+ rawQuery?: z.ZodString;
2002
2116
  };
2003
2117
  res: z.ZodSchema<{
2004
2118
  status: number;
@@ -2027,6 +2141,10 @@ export type ServerOf<Api extends ApiGuard> = {
2027
2141
  cookies: Api[Route][Method]["req"]["cookies"] extends Record<string, z.ZodSchema<string | undefined>> ? {
2028
2142
  [key in keyof Api[Route][Method]["req"]["cookies"]]: z.infer<Api[Route][Method]["req"]["cookies"][key]>;
2029
2143
  } : undefined;
2144
+ headers: Api[Route][Method]["req"]["headers"] extends Record<string, z.ZodSchema<string | undefined>> ? {
2145
+ [key in keyof Api[Route][Method]["req"]["headers"]]: z.infer<Api[Route][Method]["req"]["headers"][key]>;
2146
+ } : undefined;
2147
+ rawQuery: Api[Route][Method]["req"]["rawQuery"] extends z.ZodString ? string : undefined;
2030
2148
  }>) => Promise<z.infer<Api[Route][Method]["res"]>> : never;
2031
2149
  };
2032
2150
  };
@@ -1504,6 +1504,35 @@ var GenericError = zod.z.object({
1504
1504
  message: zod.z.string()
1505
1505
  });
1506
1506
 
1507
+ /**
1508
+ * The header a request to `/admin/proxy` must carry. A cross-site form or
1509
+ * `<img>` cannot set a custom header, so without it the proxy cannot be driven
1510
+ * with the editor's cookie from another site.
1511
+ */
1512
+ var VAL_STUDIO_HEADER = "x-val-studio";
1513
+
1514
+ /**
1515
+ * What Val Build answered, mapped onto the statuses this server speaks: a
1516
+ * `code` in the JSON is what the web components act on, so it is passed
1517
+ * through untouched.
1518
+ */
1519
+ var AdminProxyResponse = zod.z.object({
1520
+ status: zod.z.union([zod.z.literal(200), zod.z.literal(400), zod.z.literal(401), zod.z.literal(403), zod.z.literal(404), zod.z.literal(500)]),
1521
+ json: zod.z.unknown()
1522
+ });
1523
+ function adminProxyEndpoint() {
1524
+ return {
1525
+ req: {
1526
+ path: zod.z.string(),
1527
+ rawQuery: zod.z.string(),
1528
+ headers: getSitemapTree._defineProperty({}, VAL_STUDIO_HEADER, zod.z.string().optional()),
1529
+ cookies: getSitemapTree._defineProperty({}, VAL_SESSION_COOKIE, zod.z.string().optional()),
1530
+ body: zod.z.unknown()
1531
+ },
1532
+ res: AdminProxyResponse
1533
+ };
1534
+ }
1535
+
1507
1536
  /**
1508
1537
  * What answered when one URL was opened.
1509
1538
  *
@@ -2028,6 +2057,14 @@ var Api = {
2028
2057
  * highest version. Optional, for the same reason `headPatchId` is.
2029
2058
  */
2030
2059
  headVersion: zod.z.number().optional(),
2060
+ /**
2061
+ * Every group on the branch and which listed patches it holds,
2062
+ * read with the list and `headVersion`. What a Studio's view of
2063
+ * the groups is taken from, so a stage or an unstage made in
2064
+ * another browser reaches it with the next stat. Absent where
2065
+ * the content service has no groups.
2066
+ */
2067
+ patchGroups: zod.z.array(PatchGroup).optional(),
2031
2068
  commits: zod.z.array(ValCommit),
2032
2069
  /**
2033
2070
  * The publishes the content service knows about.
@@ -2427,7 +2464,12 @@ var Api = {
2427
2464
  PUT: {
2428
2465
  req: {
2429
2466
  body: zod.z.object({
2430
- patchGroupId: zod.z.string(),
2467
+ /**
2468
+ * The group to stage into. Absent means the caller's open group on
2469
+ * the branch, created if there is none — which is what the Studio
2470
+ * sends, so a stage never has to wait for a group to exist.
2471
+ */
2472
+ patchGroupId: zod.z.string().optional(),
2431
2473
  /** What the user asked to stage. */
2432
2474
  patchIds: zod.z.array(PatchId),
2433
2475
  /*
@@ -2465,15 +2507,23 @@ var Api = {
2465
2507
  }), zod.z.object({
2466
2508
  status: zod.z.literal(200),
2467
2509
  json: zod.z.object({
2468
- patchGroupId: zod.z.string(),
2469
- patchIds: zod.z.array(PatchId)
2510
+ /** `null` for an unstage when the caller has no open group. */
2511
+ patchGroupId: zod.z.string().nullable(),
2512
+ patchIds: zod.z.array(PatchId),
2513
+ /**
2514
+ * The chain version the change committed at. The client keeps its
2515
+ * own view of the change until a stat at least this new shows it.
2516
+ * Absent from a content service that predates it.
2517
+ */
2518
+ headVersion: zod.z.number().optional()
2470
2519
  })
2471
2520
  })])
2472
2521
  },
2473
2522
  DELETE: {
2474
2523
  req: {
2475
2524
  body: zod.z.object({
2476
- patchGroupId: zod.z.string(),
2525
+ /** See the PUT. Absent with no open group is a no-op. */
2526
+ patchGroupId: zod.z.string().optional(),
2477
2527
  /** What the user asked to unstage. */
2478
2528
  patchIds: zod.z.array(PatchId),
2479
2529
  /** What has to go with it: everything built on top of it. */
@@ -2498,8 +2548,15 @@ var Api = {
2498
2548
  }), zod.z.object({
2499
2549
  status: zod.z.literal(200),
2500
2550
  json: zod.z.object({
2501
- patchGroupId: zod.z.string(),
2502
- patchIds: zod.z.array(PatchId)
2551
+ /** `null` for an unstage when the caller has no open group. */
2552
+ patchGroupId: zod.z.string().nullable(),
2553
+ patchIds: zod.z.array(PatchId),
2554
+ /**
2555
+ * The chain version the change committed at. The client keeps its
2556
+ * own view of the change until a stat at least this new shows it.
2557
+ * Absent from a content service that predates it.
2558
+ */
2559
+ headVersion: zod.z.number().optional()
2503
2560
  })
2504
2561
  })])
2505
2562
  }
@@ -3418,6 +3475,50 @@ var Api = {
3418
3475
  json: GenericError
3419
3476
  })])
3420
3477
  }
3478
+ },
3479
+ /*
3480
+ * Val Build, on the editor's behalf, for the web components the Studio
3481
+ * mounts from admin.val.build (`<val-project-switcher>` and the ones after
3482
+ * it). `/admin/proxy/projects/overview?current=…` is
3483
+ * `{valBuildUrl}/api/studio/v1/projects/overview?current=…`, with the
3484
+ * editor's token from the session cookie: the component cannot send that
3485
+ * token itself, because it is in an httpOnly cookie only this server reads.
3486
+ *
3487
+ * A pipe, deliberately: the path, the query and the JSON body go through as
3488
+ * they are, so a new component or endpoint on Val Build needs no Val
3489
+ * release. What it does NOT pass through is anything that would let it be
3490
+ * aimed elsewhere — see `adminProxy.ts`.
3491
+ */
3492
+ /*
3493
+ * Whether this Studio has a Val Build credential for the editor: a session,
3494
+ * or in local development a `val login`. The Studio asks before it loads a
3495
+ * web component, so a developer who never logged in sees the plain project
3496
+ * name rather than a component explaining that they are not logged in.
3497
+ */
3498
+ "/admin/status": {
3499
+ GET: {
3500
+ req: {
3501
+ cookies: getSitemapTree._defineProperty({}, VAL_SESSION_COOKIE, zod.z.string().optional())
3502
+ },
3503
+ res: zod.z.object({
3504
+ status: zod.z.literal(200),
3505
+ json: zod.z.object({
3506
+ connected: zod.z["boolean"](),
3507
+ /**
3508
+ * `val-login` on a developer's own checkout, `studio` anywhere the
3509
+ * Studio's sign-in is the way in. Optional: an older server does
3510
+ * not send it.
3511
+ */
3512
+ signIn: zod.z["enum"](["val-login", "studio"]).optional()
3513
+ })
3514
+ })
3515
+ }
3516
+ },
3517
+ "/admin/proxy": {
3518
+ GET: adminProxyEndpoint(),
3519
+ POST: adminProxyEndpoint(),
3520
+ PUT: adminProxyEndpoint(),
3521
+ DELETE: adminProxyEndpoint()
3421
3522
  }
3422
3523
  };
3423
3524
 
@@ -7744,6 +7845,7 @@ exports.VAL_ENABLE_COOKIE_NAME = VAL_ENABLE_COOKIE_NAME;
7744
7845
  exports.VAL_GREEN_RAMP = VAL_GREEN_RAMP;
7745
7846
  exports.VAL_SESSION_COOKIE = VAL_SESSION_COOKIE;
7746
7847
  exports.VAL_STATE_COOKIE = VAL_STATE_COOKIE;
7848
+ exports.VAL_STUDIO_HEADER = VAL_STUDIO_HEADER;
7747
7849
  exports.ValCommit = ValCommit;
7748
7850
  exports.ValDeployment = ValDeployment;
7749
7851
  exports.accentRamp = accentRamp;
@@ -1504,6 +1504,35 @@ var GenericError = zod.z.object({
1504
1504
  message: zod.z.string()
1505
1505
  });
1506
1506
 
1507
+ /**
1508
+ * The header a request to `/admin/proxy` must carry. A cross-site form or
1509
+ * `<img>` cannot set a custom header, so without it the proxy cannot be driven
1510
+ * with the editor's cookie from another site.
1511
+ */
1512
+ var VAL_STUDIO_HEADER = "x-val-studio";
1513
+
1514
+ /**
1515
+ * What Val Build answered, mapped onto the statuses this server speaks: a
1516
+ * `code` in the JSON is what the web components act on, so it is passed
1517
+ * through untouched.
1518
+ */
1519
+ var AdminProxyResponse = zod.z.object({
1520
+ status: zod.z.union([zod.z.literal(200), zod.z.literal(400), zod.z.literal(401), zod.z.literal(403), zod.z.literal(404), zod.z.literal(500)]),
1521
+ json: zod.z.unknown()
1522
+ });
1523
+ function adminProxyEndpoint() {
1524
+ return {
1525
+ req: {
1526
+ path: zod.z.string(),
1527
+ rawQuery: zod.z.string(),
1528
+ headers: getSitemapTree._defineProperty({}, VAL_STUDIO_HEADER, zod.z.string().optional()),
1529
+ cookies: getSitemapTree._defineProperty({}, VAL_SESSION_COOKIE, zod.z.string().optional()),
1530
+ body: zod.z.unknown()
1531
+ },
1532
+ res: AdminProxyResponse
1533
+ };
1534
+ }
1535
+
1507
1536
  /**
1508
1537
  * What answered when one URL was opened.
1509
1538
  *
@@ -2028,6 +2057,14 @@ var Api = {
2028
2057
  * highest version. Optional, for the same reason `headPatchId` is.
2029
2058
  */
2030
2059
  headVersion: zod.z.number().optional(),
2060
+ /**
2061
+ * Every group on the branch and which listed patches it holds,
2062
+ * read with the list and `headVersion`. What a Studio's view of
2063
+ * the groups is taken from, so a stage or an unstage made in
2064
+ * another browser reaches it with the next stat. Absent where
2065
+ * the content service has no groups.
2066
+ */
2067
+ patchGroups: zod.z.array(PatchGroup).optional(),
2031
2068
  commits: zod.z.array(ValCommit),
2032
2069
  /**
2033
2070
  * The publishes the content service knows about.
@@ -2427,7 +2464,12 @@ var Api = {
2427
2464
  PUT: {
2428
2465
  req: {
2429
2466
  body: zod.z.object({
2430
- patchGroupId: zod.z.string(),
2467
+ /**
2468
+ * The group to stage into. Absent means the caller's open group on
2469
+ * the branch, created if there is none — which is what the Studio
2470
+ * sends, so a stage never has to wait for a group to exist.
2471
+ */
2472
+ patchGroupId: zod.z.string().optional(),
2431
2473
  /** What the user asked to stage. */
2432
2474
  patchIds: zod.z.array(PatchId),
2433
2475
  /*
@@ -2465,15 +2507,23 @@ var Api = {
2465
2507
  }), zod.z.object({
2466
2508
  status: zod.z.literal(200),
2467
2509
  json: zod.z.object({
2468
- patchGroupId: zod.z.string(),
2469
- patchIds: zod.z.array(PatchId)
2510
+ /** `null` for an unstage when the caller has no open group. */
2511
+ patchGroupId: zod.z.string().nullable(),
2512
+ patchIds: zod.z.array(PatchId),
2513
+ /**
2514
+ * The chain version the change committed at. The client keeps its
2515
+ * own view of the change until a stat at least this new shows it.
2516
+ * Absent from a content service that predates it.
2517
+ */
2518
+ headVersion: zod.z.number().optional()
2470
2519
  })
2471
2520
  })])
2472
2521
  },
2473
2522
  DELETE: {
2474
2523
  req: {
2475
2524
  body: zod.z.object({
2476
- patchGroupId: zod.z.string(),
2525
+ /** See the PUT. Absent with no open group is a no-op. */
2526
+ patchGroupId: zod.z.string().optional(),
2477
2527
  /** What the user asked to unstage. */
2478
2528
  patchIds: zod.z.array(PatchId),
2479
2529
  /** What has to go with it: everything built on top of it. */
@@ -2498,8 +2548,15 @@ var Api = {
2498
2548
  }), zod.z.object({
2499
2549
  status: zod.z.literal(200),
2500
2550
  json: zod.z.object({
2501
- patchGroupId: zod.z.string(),
2502
- patchIds: zod.z.array(PatchId)
2551
+ /** `null` for an unstage when the caller has no open group. */
2552
+ patchGroupId: zod.z.string().nullable(),
2553
+ patchIds: zod.z.array(PatchId),
2554
+ /**
2555
+ * The chain version the change committed at. The client keeps its
2556
+ * own view of the change until a stat at least this new shows it.
2557
+ * Absent from a content service that predates it.
2558
+ */
2559
+ headVersion: zod.z.number().optional()
2503
2560
  })
2504
2561
  })])
2505
2562
  }
@@ -3418,6 +3475,50 @@ var Api = {
3418
3475
  json: GenericError
3419
3476
  })])
3420
3477
  }
3478
+ },
3479
+ /*
3480
+ * Val Build, on the editor's behalf, for the web components the Studio
3481
+ * mounts from admin.val.build (`<val-project-switcher>` and the ones after
3482
+ * it). `/admin/proxy/projects/overview?current=…` is
3483
+ * `{valBuildUrl}/api/studio/v1/projects/overview?current=…`, with the
3484
+ * editor's token from the session cookie: the component cannot send that
3485
+ * token itself, because it is in an httpOnly cookie only this server reads.
3486
+ *
3487
+ * A pipe, deliberately: the path, the query and the JSON body go through as
3488
+ * they are, so a new component or endpoint on Val Build needs no Val
3489
+ * release. What it does NOT pass through is anything that would let it be
3490
+ * aimed elsewhere — see `adminProxy.ts`.
3491
+ */
3492
+ /*
3493
+ * Whether this Studio has a Val Build credential for the editor: a session,
3494
+ * or in local development a `val login`. The Studio asks before it loads a
3495
+ * web component, so a developer who never logged in sees the plain project
3496
+ * name rather than a component explaining that they are not logged in.
3497
+ */
3498
+ "/admin/status": {
3499
+ GET: {
3500
+ req: {
3501
+ cookies: getSitemapTree._defineProperty({}, VAL_SESSION_COOKIE, zod.z.string().optional())
3502
+ },
3503
+ res: zod.z.object({
3504
+ status: zod.z.literal(200),
3505
+ json: zod.z.object({
3506
+ connected: zod.z["boolean"](),
3507
+ /**
3508
+ * `val-login` on a developer's own checkout, `studio` anywhere the
3509
+ * Studio's sign-in is the way in. Optional: an older server does
3510
+ * not send it.
3511
+ */
3512
+ signIn: zod.z["enum"](["val-login", "studio"]).optional()
3513
+ })
3514
+ })
3515
+ }
3516
+ },
3517
+ "/admin/proxy": {
3518
+ GET: adminProxyEndpoint(),
3519
+ POST: adminProxyEndpoint(),
3520
+ PUT: adminProxyEndpoint(),
3521
+ DELETE: adminProxyEndpoint()
3421
3522
  }
3422
3523
  };
3423
3524
 
@@ -7744,6 +7845,7 @@ exports.VAL_ENABLE_COOKIE_NAME = VAL_ENABLE_COOKIE_NAME;
7744
7845
  exports.VAL_GREEN_RAMP = VAL_GREEN_RAMP;
7745
7846
  exports.VAL_SESSION_COOKIE = VAL_SESSION_COOKIE;
7746
7847
  exports.VAL_STATE_COOKIE = VAL_STATE_COOKIE;
7848
+ exports.VAL_STUDIO_HEADER = VAL_STUDIO_HEADER;
7747
7849
  exports.ValCommit = ValCommit;
7748
7850
  exports.ValDeployment = ValDeployment;
7749
7851
  exports.accentRamp = accentRamp;
@@ -1497,6 +1497,35 @@ var GenericError = z.object({
1497
1497
  message: z.string()
1498
1498
  });
1499
1499
 
1500
+ /**
1501
+ * The header a request to `/admin/proxy` must carry. A cross-site form or
1502
+ * `<img>` cannot set a custom header, so without it the proxy cannot be driven
1503
+ * with the editor's cookie from another site.
1504
+ */
1505
+ var VAL_STUDIO_HEADER = "x-val-studio";
1506
+
1507
+ /**
1508
+ * What Val Build answered, mapped onto the statuses this server speaks: a
1509
+ * `code` in the JSON is what the web components act on, so it is passed
1510
+ * through untouched.
1511
+ */
1512
+ var AdminProxyResponse = z.object({
1513
+ status: z.union([z.literal(200), z.literal(400), z.literal(401), z.literal(403), z.literal(404), z.literal(500)]),
1514
+ json: z.unknown()
1515
+ });
1516
+ function adminProxyEndpoint() {
1517
+ return {
1518
+ req: {
1519
+ path: z.string(),
1520
+ rawQuery: z.string(),
1521
+ headers: _defineProperty({}, VAL_STUDIO_HEADER, z.string().optional()),
1522
+ cookies: _defineProperty({}, VAL_SESSION_COOKIE, z.string().optional()),
1523
+ body: z.unknown()
1524
+ },
1525
+ res: AdminProxyResponse
1526
+ };
1527
+ }
1528
+
1500
1529
  /**
1501
1530
  * What answered when one URL was opened.
1502
1531
  *
@@ -2021,6 +2050,14 @@ var Api = {
2021
2050
  * highest version. Optional, for the same reason `headPatchId` is.
2022
2051
  */
2023
2052
  headVersion: z.number().optional(),
2053
+ /**
2054
+ * Every group on the branch and which listed patches it holds,
2055
+ * read with the list and `headVersion`. What a Studio's view of
2056
+ * the groups is taken from, so a stage or an unstage made in
2057
+ * another browser reaches it with the next stat. Absent where
2058
+ * the content service has no groups.
2059
+ */
2060
+ patchGroups: z.array(PatchGroup).optional(),
2024
2061
  commits: z.array(ValCommit),
2025
2062
  /**
2026
2063
  * The publishes the content service knows about.
@@ -2420,7 +2457,12 @@ var Api = {
2420
2457
  PUT: {
2421
2458
  req: {
2422
2459
  body: z.object({
2423
- patchGroupId: z.string(),
2460
+ /**
2461
+ * The group to stage into. Absent means the caller's open group on
2462
+ * the branch, created if there is none — which is what the Studio
2463
+ * sends, so a stage never has to wait for a group to exist.
2464
+ */
2465
+ patchGroupId: z.string().optional(),
2424
2466
  /** What the user asked to stage. */
2425
2467
  patchIds: z.array(PatchId),
2426
2468
  /*
@@ -2458,15 +2500,23 @@ var Api = {
2458
2500
  }), z.object({
2459
2501
  status: z.literal(200),
2460
2502
  json: z.object({
2461
- patchGroupId: z.string(),
2462
- patchIds: z.array(PatchId)
2503
+ /** `null` for an unstage when the caller has no open group. */
2504
+ patchGroupId: z.string().nullable(),
2505
+ patchIds: z.array(PatchId),
2506
+ /**
2507
+ * The chain version the change committed at. The client keeps its
2508
+ * own view of the change until a stat at least this new shows it.
2509
+ * Absent from a content service that predates it.
2510
+ */
2511
+ headVersion: z.number().optional()
2463
2512
  })
2464
2513
  })])
2465
2514
  },
2466
2515
  DELETE: {
2467
2516
  req: {
2468
2517
  body: z.object({
2469
- patchGroupId: z.string(),
2518
+ /** See the PUT. Absent with no open group is a no-op. */
2519
+ patchGroupId: z.string().optional(),
2470
2520
  /** What the user asked to unstage. */
2471
2521
  patchIds: z.array(PatchId),
2472
2522
  /** What has to go with it: everything built on top of it. */
@@ -2491,8 +2541,15 @@ var Api = {
2491
2541
  }), z.object({
2492
2542
  status: z.literal(200),
2493
2543
  json: z.object({
2494
- patchGroupId: z.string(),
2495
- patchIds: z.array(PatchId)
2544
+ /** `null` for an unstage when the caller has no open group. */
2545
+ patchGroupId: z.string().nullable(),
2546
+ patchIds: z.array(PatchId),
2547
+ /**
2548
+ * The chain version the change committed at. The client keeps its
2549
+ * own view of the change until a stat at least this new shows it.
2550
+ * Absent from a content service that predates it.
2551
+ */
2552
+ headVersion: z.number().optional()
2496
2553
  })
2497
2554
  })])
2498
2555
  }
@@ -3411,6 +3468,50 @@ var Api = {
3411
3468
  json: GenericError
3412
3469
  })])
3413
3470
  }
3471
+ },
3472
+ /*
3473
+ * Val Build, on the editor's behalf, for the web components the Studio
3474
+ * mounts from admin.val.build (`<val-project-switcher>` and the ones after
3475
+ * it). `/admin/proxy/projects/overview?current=…` is
3476
+ * `{valBuildUrl}/api/studio/v1/projects/overview?current=…`, with the
3477
+ * editor's token from the session cookie: the component cannot send that
3478
+ * token itself, because it is in an httpOnly cookie only this server reads.
3479
+ *
3480
+ * A pipe, deliberately: the path, the query and the JSON body go through as
3481
+ * they are, so a new component or endpoint on Val Build needs no Val
3482
+ * release. What it does NOT pass through is anything that would let it be
3483
+ * aimed elsewhere — see `adminProxy.ts`.
3484
+ */
3485
+ /*
3486
+ * Whether this Studio has a Val Build credential for the editor: a session,
3487
+ * or in local development a `val login`. The Studio asks before it loads a
3488
+ * web component, so a developer who never logged in sees the plain project
3489
+ * name rather than a component explaining that they are not logged in.
3490
+ */
3491
+ "/admin/status": {
3492
+ GET: {
3493
+ req: {
3494
+ cookies: _defineProperty({}, VAL_SESSION_COOKIE, z.string().optional())
3495
+ },
3496
+ res: z.object({
3497
+ status: z.literal(200),
3498
+ json: z.object({
3499
+ connected: z["boolean"](),
3500
+ /**
3501
+ * `val-login` on a developer's own checkout, `studio` anywhere the
3502
+ * Studio's sign-in is the way in. Optional: an older server does
3503
+ * not send it.
3504
+ */
3505
+ signIn: z["enum"](["val-login", "studio"]).optional()
3506
+ })
3507
+ })
3508
+ }
3509
+ },
3510
+ "/admin/proxy": {
3511
+ GET: adminProxyEndpoint(),
3512
+ POST: adminProxyEndpoint(),
3513
+ PUT: adminProxyEndpoint(),
3514
+ DELETE: adminProxyEndpoint()
3414
3515
  }
3415
3516
  };
3416
3517
 
@@ -7648,4 +7749,4 @@ function parse(schema, body, call) {
7648
7749
  return parsed.data;
7649
7750
  }
7650
7751
 
7651
- export { AA_LARGE, AA_TEXT, Api, BRAND_CONTRAST_PAIRS, BinaryFileRef, CodeOptions, ColorOptions, DEFAULT_ERROR_MESSAGE, DateOptions, ENCODE_DEFAULTS, ENCODE_MIME_TYPE_OF, FileOptions, HistoricalCommit, HistoricalModule, HistoricalPatchSet, HistoryError, ImageEncodeOption, ImageOptions, JSONValue, JSON_ENTRIES_BATCH_MAX, ModuleComparison, NEVER_ENCODED, ParentRef$1 as ParentRef, Patch, PatchBlock, PatchGroup, PatchId, PatchJSON, PublishProtocolError, RAMP_STEPS, RemirrorBr, RemirrorBulletList, RemirrorHeading, RemirrorImage, RemirrorJSON, RemirrorLinkMark, RemirrorListItem, RemirrorOrderedList, RemirrorParagraph, RemirrorText, RemirrorTextMark, RestoreVerdict, RichTextOptions, SCHEMA_SOURCE_FIXES, SerializedArraySchema, SerializedBooleanSchema, SerializedCodeSchema, SerializedColorSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedDiscriminatedUnionSchema, SerializedEnumSchema, SerializedFileSchema, SerializedImageSchema, SerializedKeyOfSchema, SerializedLiteralSchema, SerializedLocaleSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedRecordSchema, SerializedRichTextSchema, SerializedRouteSchema, SerializedSchema, SerializedSettingsSchema, SerializedStringSchema, SerializedValViewSchema, SharedValConfig, VAL_ENABLE_COOKIE_NAME, VAL_GREEN_RAMP, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, ValCommit, ValDeployment, accentRamp, buildDuplicatePatch, buildEmptyAtPathPatch, buildFileRefValue, buildImageGalleryPatch, buildRemoveImageGalleryEntryPatch, buildSearchIndex, chainHeadOf, checkCompatibility, chooseEncoded, concatModulePath, contrastRatio, createRegExpFromPattern, createSearchIndex, createValClient, declaredLocales, describeContainerAtPath, emptyOf, explainIncompatible, filterBlockingValidationErrors, filterRoutesByPatterns, findSimilar, fitWithin, flattenRichText, getErrorMessageFromUnknownJson, getFilenameFromRef, getInlineImgInfo, getKeyOfRecordAt, getRefParts, getRoutesOf, getRoutesWithModulePaths, getSourceAt, indexModule, isMimeTypeAccepted, isRemoteSchema, isSchemaSourceFixError, isSkippedSource, keyOfRecordPath, levenshtein, localeAt, memoizePerRequest, newestCommitSha, parseArtifacts, parseBuildTarget, parseCancel, parseDeclare, parseDiscard, parseJob, parseNewestCiRun, parsePress, parseProblems, parseProjectSource, parsePromote, parsePublishToken, parseRenew, parseRequestStatus, parseStatus, parseUpdateTarget, parseVerify, partitionValidationErrors, performSearch, relativeLuminance, remirrorToRichTextSource, removeModule, resolveEncodeSettings, resolvePairGround, resolveSchemaSourceFixForError, resolveSchemaSourceFixes, resolveSerializedSchemaAtPath, richTextToRemirror, safeParsePatch, sourcePathOfChild, themeCustomProperties, toolNames, traverseSchemaSource, urlOf, validateRoutePatterns, withExtension };
7752
+ export { AA_LARGE, AA_TEXT, Api, BRAND_CONTRAST_PAIRS, BinaryFileRef, CodeOptions, ColorOptions, DEFAULT_ERROR_MESSAGE, DateOptions, ENCODE_DEFAULTS, ENCODE_MIME_TYPE_OF, FileOptions, HistoricalCommit, HistoricalModule, HistoricalPatchSet, HistoryError, ImageEncodeOption, ImageOptions, JSONValue, JSON_ENTRIES_BATCH_MAX, ModuleComparison, NEVER_ENCODED, ParentRef$1 as ParentRef, Patch, PatchBlock, PatchGroup, PatchId, PatchJSON, PublishProtocolError, RAMP_STEPS, RemirrorBr, RemirrorBulletList, RemirrorHeading, RemirrorImage, RemirrorJSON, RemirrorLinkMark, RemirrorListItem, RemirrorOrderedList, RemirrorParagraph, RemirrorText, RemirrorTextMark, RestoreVerdict, RichTextOptions, SCHEMA_SOURCE_FIXES, SerializedArraySchema, SerializedBooleanSchema, SerializedCodeSchema, SerializedColorSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedDiscriminatedUnionSchema, SerializedEnumSchema, SerializedFileSchema, SerializedImageSchema, SerializedKeyOfSchema, SerializedLiteralSchema, SerializedLocaleSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedRecordSchema, SerializedRichTextSchema, SerializedRouteSchema, SerializedSchema, SerializedSettingsSchema, SerializedStringSchema, SerializedValViewSchema, SharedValConfig, VAL_ENABLE_COOKIE_NAME, VAL_GREEN_RAMP, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, VAL_STUDIO_HEADER, ValCommit, ValDeployment, accentRamp, buildDuplicatePatch, buildEmptyAtPathPatch, buildFileRefValue, buildImageGalleryPatch, buildRemoveImageGalleryEntryPatch, buildSearchIndex, chainHeadOf, checkCompatibility, chooseEncoded, concatModulePath, contrastRatio, createRegExpFromPattern, createSearchIndex, createValClient, declaredLocales, describeContainerAtPath, emptyOf, explainIncompatible, filterBlockingValidationErrors, filterRoutesByPatterns, findSimilar, fitWithin, flattenRichText, getErrorMessageFromUnknownJson, getFilenameFromRef, getInlineImgInfo, getKeyOfRecordAt, getRefParts, getRoutesOf, getRoutesWithModulePaths, getSourceAt, indexModule, isMimeTypeAccepted, isRemoteSchema, isSchemaSourceFixError, isSkippedSource, keyOfRecordPath, levenshtein, localeAt, memoizePerRequest, newestCommitSha, parseArtifacts, parseBuildTarget, parseCancel, parseDeclare, parseDiscard, parseJob, parseNewestCiRun, parsePress, parseProblems, parseProjectSource, parsePromote, parsePublishToken, parseRenew, parseRequestStatus, parseStatus, parseUpdateTarget, parseVerify, partitionValidationErrors, performSearch, relativeLuminance, remirrorToRichTextSource, removeModule, resolveEncodeSettings, resolvePairGround, resolveSchemaSourceFixForError, resolveSchemaSourceFixes, resolveSerializedSchemaAtPath, richTextToRemirror, safeParsePatch, sourcePathOfChild, themeCustomProperties, toolNames, traverseSchemaSource, urlOf, validateRoutePatterns, withExtension };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valbuild/shared",
3
- "version": "0.139.0",
3
+ "version": "0.140.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.139.0"
40
+ "@valbuild/core": "0.139.1"
41
41
  },
42
42
  "files": [
43
43
  "CHANGELOG.md",