@valbuild/shared 0.118.0 → 0.121.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.
@@ -1119,25 +1119,24 @@ var SerializedImageSchema = z.object({
1119
1119
  });
1120
1120
  var RichTextOptions = z.lazy(function () {
1121
1121
  return z.object({
1122
- style: z.object({
1123
- bold: z["boolean"]().optional(),
1124
- italic: z["boolean"]().optional(),
1125
- lineThrough: z["boolean"]().optional()
1126
- }).optional(),
1127
- block: z.object({
1128
- h1: z["boolean"]().optional(),
1129
- h2: z["boolean"]().optional(),
1130
- h3: z["boolean"]().optional(),
1131
- h4: z["boolean"]().optional(),
1132
- h5: z["boolean"]().optional(),
1133
- h6: z["boolean"]().optional(),
1134
- ul: z["boolean"]().optional(),
1135
- ol: z["boolean"]().optional()
1136
- }).optional(),
1137
- inline: z.object({
1138
- a: z.union([z["boolean"](), SerializedRouteSchema, SerializedStringSchema]).optional(),
1139
- img: z.union([z["boolean"](), SerializedImageSchema]).optional()
1140
- }).optional()
1122
+ // Set by `.maxLength()` / `.minLength()`, not by the options argument.
1123
+ // These z.objects strip unknown keys, so leaving them out drops the
1124
+ // length constraints in transit.
1125
+ maxLength: z.number().optional(),
1126
+ minLength: z.number().optional(),
1127
+ bold: z["boolean"]().optional(),
1128
+ italic: z["boolean"]().optional(),
1129
+ lineThrough: z["boolean"]().optional(),
1130
+ h1: z["boolean"]().optional(),
1131
+ h2: z["boolean"]().optional(),
1132
+ h3: z["boolean"]().optional(),
1133
+ h4: z["boolean"]().optional(),
1134
+ h5: z["boolean"]().optional(),
1135
+ h6: z["boolean"]().optional(),
1136
+ ul: z["boolean"]().optional(),
1137
+ ol: z["boolean"]().optional(),
1138
+ a: z.union([z["boolean"](), SerializedRouteSchema, SerializedStringSchema]).optional(),
1139
+ img: z.union([z["boolean"](), SerializedImageSchema]).optional()
1141
1140
  });
1142
1141
  });
1143
1142
  var SerializedRichTextSchema = z.object({
@@ -1330,6 +1329,21 @@ var notFoundResponse = z.object({
1330
1329
  var GenericError = z.object({
1331
1330
  message: z.string()
1332
1331
  });
1332
+
1333
+ /**
1334
+ * A patch group: the set of patches one user has chosen to publish.
1335
+ *
1336
+ * Not a patch *set* — a patch set is computed from the schema and says which
1337
+ * patches must move together; a patch group is curated and says which ones this
1338
+ * user wants live. See `docs/independent-publish/PLAN.md`.
1339
+ */
1340
+ var PatchGroup = z.object({
1341
+ patchGroupId: z.string(),
1342
+ authorId: z.string().nullable(),
1343
+ createdAt: z.string(),
1344
+ publishedAt: z.string().nullable(),
1345
+ patchIds: z.array(PatchId)
1346
+ });
1333
1347
  var GenericPatchError = z.union([z.object({
1334
1348
  patchId: PatchId,
1335
1349
  message: z.string()
@@ -1711,6 +1725,30 @@ var Api = {
1711
1725
  schemaSha: z.string(),
1712
1726
  sourcesSha: z.string(),
1713
1727
  patches: z.array(PatchId),
1728
+ /**
1729
+ * Of `patches`, the ones that have already SHIPPED.
1730
+ *
1731
+ * A published patch stays in the chain with `appliedAt` set until
1732
+ * the next deployment moves the base, so the id list alone cannot
1733
+ * say which is which — and a client never re-fetches a record it
1734
+ * already holds, so it never finds out on its own. Another
1735
+ * author's publish then left that patch pending in your scope,
1736
+ * your prefix gate read a hole in front of it, and Publish
1737
+ * refused for a reason that had stopped being true.
1738
+ *
1739
+ * Optional: `fs` mode forgets published patches outright, and a
1740
+ * client that ignores this behaves exactly as it did before.
1741
+ */
1742
+ appliedPatches: z.array(PatchId).optional(),
1743
+ /**
1744
+ * The newest commit, which is the PUBLISH head.
1745
+ *
1746
+ * Not `commitSha`: that is the commit this deployment serves and
1747
+ * moves only when a new build lands. This moves the instant
1748
+ * somebody publishes, which is what makes it the thing a client
1749
+ * carries back to `/save` to say which world it decided against.
1750
+ */
1751
+ headCommitSha: z.string().optional(),
1714
1752
  /**
1715
1753
  * Unpublished changes the store threw away because it could not
1716
1754
  * read them.
@@ -1739,6 +1777,30 @@ var Api = {
1739
1777
  sourcesSha: z.string(),
1740
1778
  commitSha: z.string(),
1741
1779
  patches: z.array(PatchId),
1780
+ /**
1781
+ * Of `patches`, the ones that have already SHIPPED.
1782
+ *
1783
+ * A published patch stays in the chain with `appliedAt` set until
1784
+ * the next deployment moves the base, so the id list alone cannot
1785
+ * say which is which — and a client never re-fetches a record it
1786
+ * already holds, so it never finds out on its own. Another
1787
+ * author's publish then left that patch pending in your scope,
1788
+ * your prefix gate read a hole in front of it, and Publish
1789
+ * refused for a reason that had stopped being true.
1790
+ *
1791
+ * Optional: `fs` mode forgets published patches outright, and a
1792
+ * client that ignores this behaves exactly as it did before.
1793
+ */
1794
+ appliedPatches: z.array(PatchId).optional(),
1795
+ /**
1796
+ * The newest commit, which is the PUBLISH head.
1797
+ *
1798
+ * Not `commitSha`: that is the commit this deployment serves and
1799
+ * moves only when a new build lands. This moves the instant
1800
+ * somebody publishes, which is what makes it the thing a client
1801
+ * carries back to `/save` to say which world it decided against.
1802
+ */
1803
+ headCommitSha: z.string().optional(),
1742
1804
  commits: z.array(ValCommit),
1743
1805
  config: ValConfig,
1744
1806
  profileId: z.string().nullable(),
@@ -1808,6 +1870,26 @@ var Api = {
1808
1870
  query: {
1809
1871
  id: z.array(PatchId).min(1, "At least one patch id is required")
1810
1872
  },
1873
+ body: z.object({
1874
+ /*
1875
+ * Patches that are NOT being deleted but must lose their patch
1876
+ * group membership because these are.
1877
+ *
1878
+ * Deleting a patch out of the middle of a patch set leaves every
1879
+ * group holding the rest with a non-prefix intersection, and a
1880
+ * prefix is the one invariant a group has. Which patches those are
1881
+ * needs the content schema, so the client computes the forward
1882
+ * closure and sends it; the content API drops the memberships
1883
+ * without touching the patches.
1884
+ *
1885
+ * In the BODY while the ids to delete are in the query, because
1886
+ * this list is unbounded in the same way and the query string is
1887
+ * already chunked to fit. Optional throughout: `fs` mode has no
1888
+ * groups, and a client that predates this is deleting correctly,
1889
+ * just not repairing.
1890
+ */
1891
+ unstagePatchIds: z.array(PatchId).optional()
1892
+ }).optional(),
1811
1893
  cookies: {
1812
1894
  val_session: z.string().optional()
1813
1895
  }
@@ -1832,7 +1914,16 @@ var Api = {
1832
1914
  path: ModuleFilePath,
1833
1915
  patchId: PatchId,
1834
1916
  patch: z.any() // TODO: this should be Patch instead - we got a weird validation error: although input looks good, it still does not accept objects as values... Which it should do via the z.record(JSONValue) type
1835
- }))
1917
+ })),
1918
+ // Patch group membership. Sent with the patch itself, in one request, so
1919
+ // there is no window in which a patch exists but belongs to no group.
1920
+ // Absent means "the caller does not know about groups" - the server then
1921
+ // behaves exactly as before.
1922
+ patchGroupId: z.string().nullish(),
1923
+ // What has to come with the patch: other patch ids that must join the
1924
+ // same group for it to stay applicable. Computed on the client, which
1925
+ // is the only side that has the schema needed to derive patch sets.
1926
+ withPatchIds: z.array(PatchId).optional()
1836
1927
  }),
1837
1928
  cookies: {
1838
1929
  val_session: z.string().optional()
@@ -1858,7 +1949,8 @@ var Api = {
1858
1949
  status: z.literal(200),
1859
1950
  json: z.object({
1860
1951
  newPatchIds: z.array(PatchId),
1861
- parentRef: ParentRef
1952
+ parentRef: ParentRef,
1953
+ patchGroupId: z.string().optional()
1862
1954
  })
1863
1955
  })])
1864
1956
  },
@@ -1866,7 +1958,16 @@ var Api = {
1866
1958
  req: {
1867
1959
  query: {
1868
1960
  patch_id: z.array(PatchId).optional(),
1869
- exclude_patch_ops: onlyOneBooleanQueryParam.optional()
1961
+ exclude_patch_ops: onlyOneBooleanQueryParam.optional(),
1962
+ /**
1963
+ * Include the patch group annotation in the answer.
1964
+ *
1965
+ * Off by default because the client CHUNKS this request — a long
1966
+ * chain is several round trips — and the groups are a property of the
1967
+ * branch, identical in every chunk. Asking on each one is N identical
1968
+ * lookups against the content API to learn the same thing.
1969
+ */
1970
+ include_patch_groups: onlyOneBooleanQueryParam.optional()
1870
1971
  },
1871
1972
  cookies: {
1872
1973
  val_session: z.string().optional()
@@ -1895,8 +1996,12 @@ var Api = {
1895
1996
  authorId: z.string().nullable(),
1896
1997
  appliedAt: z.object({
1897
1998
  commitSha: z.string()
1898
- }).nullable()
1999
+ }).nullable(),
2000
+ // Which patch groups hold this patch. Optional so that FS mode, and
2001
+ // any server that predates patch groups, can leave it out.
2002
+ patchGroupIds: z.array(z.string()).optional()
1899
2003
  })),
2004
+ patchGroups: z.array(PatchGroup).optional(),
1900
2005
  baseSha: z.string(),
1901
2006
  error: GenericError.optional(),
1902
2007
  errors: z.record(PatchId, GenericError).optional()
@@ -1904,6 +2009,91 @@ var Api = {
1904
2009
  })])
1905
2010
  }
1906
2011
  },
2012
+ // Patch group membership. Both are idempotent set operations, and both take an
2013
+ // already-closed set: the client computes the prefix closure (staging) or the
2014
+ // forward closure (unstaging) because only the client has the schema needed to
2015
+ // derive patch sets. See `docs/independent-publish/PLAN.md`.
2016
+ "/patch-groups/~/patches": {
2017
+ PUT: {
2018
+ req: {
2019
+ body: z.object({
2020
+ patchGroupId: z.string(),
2021
+ /** What the user asked to stage. */
2022
+ patchIds: z.array(PatchId),
2023
+ /*
2024
+ * What has to come with it, because the staged patches are written on
2025
+ * top of it.
2026
+ *
2027
+ * The content API records membership as `explicit` or `dependency`
2028
+ * and reads what it is not told about as a dependency — so folding
2029
+ * the two halves into `patchIds` files the patch someone clicked as
2030
+ * something the closure dragged in.
2031
+ */
2032
+ withPatchIds: z.array(PatchId).optional()
2033
+ }).refine(function (body) {
2034
+ var _body$withPatchIds$le, _body$withPatchIds;
2035
+ return body.patchIds.length > 0 || ((_body$withPatchIds$le = (_body$withPatchIds = body.withPatchIds) === null || _body$withPatchIds === void 0 ? void 0 : _body$withPatchIds.length) !== null && _body$withPatchIds$le !== void 0 ? _body$withPatchIds$le : 0) > 0;
2036
+ },
2037
+ // Either half alone is a real request: a stage of only what came with
2038
+ // it happens when the deferred queue's scope filter drops everything
2039
+ // the user originally clicked.
2040
+ "At least one patch id is required"),
2041
+ cookies: {
2042
+ val_session: z.string().optional()
2043
+ }
2044
+ },
2045
+ res: z.union([unauthorizedResponse, z.object({
2046
+ status: z.literal(403),
2047
+ json: GenericError
2048
+ }), z.object({
2049
+ // The group has already been published, so its membership is frozen.
2050
+ status: z.literal(409),
2051
+ json: GenericError
2052
+ }), z.object({
2053
+ status: z.literal(500),
2054
+ json: GenericError
2055
+ }), z.object({
2056
+ status: z.literal(200),
2057
+ json: z.object({
2058
+ patchGroupId: z.string(),
2059
+ patchIds: z.array(PatchId)
2060
+ })
2061
+ })])
2062
+ },
2063
+ DELETE: {
2064
+ req: {
2065
+ body: z.object({
2066
+ patchGroupId: z.string(),
2067
+ /** What the user asked to unstage. */
2068
+ patchIds: z.array(PatchId),
2069
+ /** What has to go with it: everything built on top of it. */
2070
+ withPatchIds: z.array(PatchId).optional()
2071
+ }).refine(function (body) {
2072
+ var _body$withPatchIds$le2, _body$withPatchIds2;
2073
+ return body.patchIds.length > 0 || ((_body$withPatchIds$le2 = (_body$withPatchIds2 = body.withPatchIds) === null || _body$withPatchIds2 === void 0 ? void 0 : _body$withPatchIds2.length) !== null && _body$withPatchIds$le2 !== void 0 ? _body$withPatchIds$le2 : 0) > 0;
2074
+ }, "At least one patch id is required"),
2075
+ cookies: {
2076
+ val_session: z.string().optional()
2077
+ }
2078
+ },
2079
+ res: z.union([unauthorizedResponse, z.object({
2080
+ status: z.literal(403),
2081
+ json: GenericError
2082
+ }), z.object({
2083
+ status: z.literal(409),
2084
+ json: GenericError
2085
+ }), z.object({
2086
+ status: z.literal(500),
2087
+ json: GenericError
2088
+ }), z.object({
2089
+ status: z.literal(200),
2090
+ json: z.object({
2091
+ patchGroupId: z.string(),
2092
+ patchIds: z.array(PatchId)
2093
+ })
2094
+ })])
2095
+ }
2096
+ },
1907
2097
  "/schema": {
1908
2098
  GET: {
1909
2099
  req: {
@@ -1940,7 +2130,34 @@ var Api = {
1940
2130
  validate_sources: onlyOneBooleanQueryParam.optional(),
1941
2131
  validate_binary_files: onlyOneBooleanQueryParam.optional(),
1942
2132
  exclude_patches: onlyOneBooleanQueryParam.optional(),
1943
- apply_patches: onlyOneBooleanQueryParam.optional()
2133
+ apply_patches: onlyOneBooleanQueryParam.optional(),
2134
+ /**
2135
+ * Apply ONLY these patches, rather than everything pending.
2136
+ *
2137
+ * This is what makes a draft-mode render match the caller's staged
2138
+ * view. Without it `/sources/~` replays every pending patch on the
2139
+ * branch, so a server-rendered preview shows other people's
2140
+ * unpublished work — the one thing independent publish is for.
2141
+ *
2142
+ * Omitted means everything pending, which is the behaviour every
2143
+ * existing caller has and must keep. An EMPTY array is a different
2144
+ * answer and is honoured as one: a group holding nothing renders
2145
+ * base.
2146
+ */
2147
+ patch_id: z.array(PatchId).optional(),
2148
+ /**
2149
+ * Apply only the patches in the CALLER'S OWN patch groups.
2150
+ *
2151
+ * The server resolves them from the session, so a draft render does
2152
+ * not have to know its own group ids — which it cannot, since it has
2153
+ * no client state. This is what makes `fetchVal` in draft mode show
2154
+ * the person their own staged work rather than everybody's.
2155
+ *
2156
+ * Ignored when `patch_id` is given: an explicit list is a caller that
2157
+ * already knows what it wants, and silently intersecting the two
2158
+ * would make the narrower one invisible.
2159
+ */
2160
+ own_patch_groups_only: onlyOneBooleanQueryParam.optional()
1944
2161
  },
1945
2162
  cookies: {
1946
2163
  val_session: z.string().optional()
@@ -2019,7 +2236,35 @@ var Api = {
2019
2236
  req: {
2020
2237
  body: z.object({
2021
2238
  message: z.string().optional(),
2022
- patchIds: z.array(PatchId)
2239
+ patchIds: z.array(PatchId),
2240
+ /*
2241
+ * The patch group this commit EMPTIES, if it empties one.
2242
+ *
2243
+ * Forwarded to the content API, which closes the group it names —
2244
+ * and closes it unconditionally, without checking that the commit
2245
+ * shipped all of it. So the client sends it only when the publish
2246
+ * accounts for every patch the group still holds; a partial publish
2247
+ * omits it and the group stays open with the rest in it.
2248
+ *
2249
+ * Optional, and absent in `fs` mode, which has no groups.
2250
+ */
2251
+ patchGroupId: z.string().optional(),
2252
+ /*
2253
+ * The newest commit this client knew about when it decided.
2254
+ *
2255
+ * Answered with 409 when the server sees a newer one, because then
2256
+ * somebody else published between the review screen being read and
2257
+ * Save being clicked, and what is about to ship was decided against a
2258
+ * world that no longer exists.
2259
+ *
2260
+ * Git's own not-fast-forward guard does not cover this: `ValServer`
2261
+ * fetches the chain and commits fresh at publish time, so the parent
2262
+ * commit it sends is always the server's current one.
2263
+ *
2264
+ * Optional, so a client that does not track it publishes exactly as
2265
+ * it did before.
2266
+ */
2267
+ expectedHeadCommitSha: z.string().optional()
2023
2268
  }),
2024
2269
  cookies: {
2025
2270
  val_session: z.string().optional()
@@ -2028,6 +2273,24 @@ var Api = {
2028
2273
  res: z.union([unauthorizedResponse, z.object({
2029
2274
  status: z.literal(200),
2030
2275
  json: z.object({
2276
+ /**
2277
+ * The commit this publish just made, which becomes the new publish
2278
+ * head.
2279
+ *
2280
+ * Sent back because nothing else tells this client about its own
2281
+ * commit in time. `headCommitSha` moves on a `/stat` response, and
2282
+ * until the next poll lands the client still believes the
2283
+ * PRE-publish head — so a second publish inside that window carried
2284
+ * a stale `expectedHeadCommitSha`, the server compared it against
2285
+ * the commit this same client had just made, and answered 409
2286
+ * "someone else published". With auto-publish, which publishes on
2287
+ * every pause in typing, that window is hit routinely and the
2288
+ * message blames a colleague for the user's own commit.
2289
+ *
2290
+ * Optional: `fs` mode has no publish head, and neither does a
2291
+ * server that predates this.
2292
+ */
2293
+ commitSha: z.string().optional(),
2031
2294
  /**
2032
2295
  * Unpublished changes the save threw away because they could not be
2033
2296
  * applied.
@@ -2044,12 +2307,61 @@ var Api = {
2044
2307
  message: z.string()
2045
2308
  })).optional()
2046
2309
  })
2310
+ }),
2311
+ /*
2312
+ * The named patch group is not this caller's, or the lookup that would
2313
+ * say so failed.
2314
+ *
2315
+ * Publishing may CLOSE a group, and closing somebody else's leaves
2316
+ * their pending work in a closed group and in no open one. So `/save`
2317
+ * runs the same ownership check stage and unstage do, and refuses the
2318
+ * same way — see `refuseUnlessOwn`.
2319
+ */
2320
+ z.object({
2321
+ status: z.literal(403),
2322
+ json: GenericError
2323
+ }), z.object({
2324
+ status: z.literal(500),
2325
+ json: GenericError
2047
2326
  }), z.object({
2048
2327
  status: z.literal(409),
2049
- json: z.object({
2328
+ json: z.union([/** A group that has already shipped. See the 403 above. */
2329
+ z.object({
2330
+ message: z.string()
2331
+ }), z.object({
2050
2332
  message: z.string(),
2051
2333
  isNotFastForward: z.literal(true)
2052
- })
2334
+ }),
2335
+ /*
2336
+ * Somebody else published between this being decided and Save.
2337
+ *
2338
+ * Its own shape rather than another `isNotFastForward`, because
2339
+ * they happen at different moments and mean different things to the
2340
+ * user: that one is git refusing a commit, this one is refused
2341
+ * BEFORE a commit is attempted, on a head the client named. Nothing
2342
+ * was written either way, but only this one is answered by looking
2343
+ * at the review screen again.
2344
+ */
2345
+ z.object({
2346
+ message: z.string(),
2347
+ headMoved: z.literal(true)
2348
+ }),
2349
+ /**
2350
+ * The group this commit named has already been published.
2351
+ *
2352
+ * A third thing sharing 409, and flagged for the same reason
2353
+ * `headMoved` is: read as a plain not-fast-forward it looks
2354
+ * retryable, and it is the opposite — the id will never be writable
2355
+ * again, so retrying reproduces it forever.
2356
+ *
2357
+ * It means this author published from somewhere else. The client
2358
+ * forgets the id and falls back to the annotation, which is the
2359
+ * same recovery a 409 on stage or unstage triggers.
2360
+ */
2361
+ z.object({
2362
+ message: z.string(),
2363
+ patchGroupPublished: z.literal(true)
2364
+ })])
2053
2365
  }), z.object({
2054
2366
  status: z.literal(400),
2055
2367
  json: z.union([z.object({
@@ -2130,7 +2442,16 @@ var Api = {
2130
2442
  limit: onlyOneIntQueryParam.refine(function (arg) {
2131
2443
  return arg > 0 && arg <= JSON_ENTRIES_BATCH_MAX;
2132
2444
  }, "limit must be between 1 and ".concat(JSON_ENTRIES_BATCH_MAX)).optional(),
2133
- apply_patches: onlyOneBooleanQueryParam.optional()
2445
+ apply_patches: onlyOneBooleanQueryParam.optional(),
2446
+ /**
2447
+ * The caller's own staged work, and nobody else's.
2448
+ *
2449
+ * The same flag `/sources/~` takes, and for the same reason — a draft
2450
+ * page renders both, so a scoped module beside an unscoped
2451
+ * `jsonValues` entry showed one person's view and everybody's pending
2452
+ * work on the same screen.
2453
+ */
2454
+ own_patch_groups_only: onlyOneBooleanQueryParam.optional()
2134
2455
  },
2135
2456
  cookies: _defineProperty({}, VAL_SESSION_COOKIE, z.string().optional())
2136
2457
  },
@@ -2704,6 +3025,44 @@ var urlOf = function urlOf() {
2704
3025
  return "".concat(route);
2705
3026
  };
2706
3027
 
3028
+ /**
3029
+ * The newest commit the client has been told about, or `null` if none.
3030
+ *
3031
+ * This is the **publish head**: unlike `baseSha`, which only moves once a
3032
+ * deployment lands, it moves the instant somebody publishes. That makes it the
3033
+ * one thing a client can carry to `/save` to say "this is the world I decided
3034
+ * against" — and the only way the server can tell that somebody else has
3035
+ * published since the review screen was read.
3036
+ *
3037
+ * In `shared` because both sides need the SAME answer: the client names a head
3038
+ * and the server compares against one, so two implementations of "newest" is two
3039
+ * ways to disagree about whether a publish is stale.
3040
+ *
3041
+ * By `createdAt` rather than by position, because the list's order is the
3042
+ * content API's business and nothing here should depend on it. Ties keep the
3043
+ * first seen, which is arbitrary and does not matter: two commits sharing a
3044
+ * timestamp are equally "since", and either answer refuses the same publishes.
3045
+ */
3046
+ function newestCommitSha(commits) {
3047
+ var _newest$commitSha, _newest;
3048
+ var newest = null;
3049
+ var _iterator = _createForOfIteratorHelper(commits !== null && commits !== void 0 ? commits : []),
3050
+ _step;
3051
+ try {
3052
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
3053
+ var commit = _step.value;
3054
+ if (newest === null || commit.createdAt > newest.createdAt) {
3055
+ newest = commit;
3056
+ }
3057
+ }
3058
+ } catch (err) {
3059
+ _iterator.e(err);
3060
+ } finally {
3061
+ _iterator.f();
3062
+ }
3063
+ return (_newest$commitSha = (_newest = newest) === null || _newest === void 0 ? void 0 : _newest.commitSha) !== null && _newest$commitSha !== void 0 ? _newest$commitSha : null;
3064
+ }
3065
+
2707
3066
  var VAL_CONFIG_SESSION_STORAGE_KEY = "val-config";
2708
3067
  var VAL_THEME_SESSION_STORAGE_KEY = "val-theme";
2709
3068
  var VAL_AI_SESSION_STORAGE_KEY = "val-ai-session";
@@ -2719,14 +3078,6 @@ var SharedValConfig = z.object({
2719
3078
  ai: z.object({
2720
3079
  commitMessages: z.object({
2721
3080
  disabled: z["boolean"]().optional()
2722
- }).optional(),
2723
- chat: z.object({
2724
- experimental: z.object({
2725
- enable: z["boolean"]().optional()
2726
- }).optional(),
2727
- suggestions: z.array(z.string()).optional(),
2728
- title: z.string().optional(),
2729
- description: z.string().optional()
2730
3081
  }).optional()
2731
3082
  }).optional()
2732
3083
  });
@@ -3511,6 +3862,11 @@ function emptyOf(schema) {
3511
3862
  return [];
3512
3863
  } else if (schema.type === "record") {
3513
3864
  return {};
3865
+ } else if (schema.type === "settings") {
3866
+ // Not an object of empty sections: every settings key is optional, and
3867
+ // absent IS the empty value. Filling the sections in would write a shape
3868
+ // the project never asked for.
3869
+ return {};
3514
3870
  } else if (schema.opt) {
3515
3871
  return null;
3516
3872
  } else if (schema.type === "richtext") {
@@ -3663,7 +4019,7 @@ function getInlineImgInfo(richtextSchema) {
3663
4019
  if (richtextSchema.type !== "richtext") return {
3664
4020
  kind: "not-allowed"
3665
4021
  };
3666
- var img = (_richtextSchema$optio = richtextSchema.options) === null || _richtextSchema$optio === void 0 || (_richtextSchema$optio = _richtextSchema$optio.inline) === null || _richtextSchema$optio === void 0 ? void 0 : _richtextSchema$optio.img;
4022
+ var img = (_richtextSchema$optio = richtextSchema.options) === null || _richtextSchema$optio === void 0 ? void 0 : _richtextSchema$optio.img;
3667
4023
  if (!img) return {
3668
4024
  kind: "not-allowed"
3669
4025
  };
@@ -4213,4 +4569,4 @@ function filterBlockingValidationErrors(validationErrors, schemas, sources) {
4213
4569
  return partitionValidationErrors(resolved).surfaced;
4214
4570
  }
4215
4571
 
4216
- export { Api, CodeOptions, ColorOptions, DEFAULT_ERROR_MESSAGE, DateOptions, FileOptions, ImageEncodeOption, ImageOptions, JSON_ENTRIES_BATCH_MAX, ParentRef$1 as ParentRef, Patch, PatchBlock, PatchId, PatchJSON, RemirrorBr, RemirrorBulletList, RemirrorHeading, RemirrorImage, RemirrorJSON, RemirrorLinkMark, RemirrorListItem, RemirrorOrderedList, RemirrorParagraph, RemirrorText, RemirrorTextMark, RichTextOptions, SerializedArraySchema, SerializedBooleanSchema, SerializedCodeSchema, SerializedColorSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedFileSchema, SerializedImageSchema, SerializedKeyOfSchema, SerializedLiteralSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedRecordSchema, SerializedRichTextSchema, SerializedRouteSchema, SerializedSchema, SerializedStringSchema, SerializedUnionSchema, SharedValConfig, VAL_AI_SESSION_STORAGE_KEY, VAL_CANVAS_MESSAGE, VAL_CANVAS_PARAM, VAL_CONFIG_SESSION_STORAGE_KEY, VAL_ENABLE_COOKIE_NAME, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, VAL_THEME_SESSION_STORAGE_KEY, ValCommit, ValDeployment, buildDuplicatePatch, buildEmptyAtPathPatch, buildFileRefValue, buildImageGalleryPatch, buildRemoveImageGalleryEntryPatch, createRegExpFromPattern, createValClient, describeContainerAtPath, emptyOf, filterBlockingValidationErrors, filterRoutesByPatterns, findSimilar, getErrorMessageFromUnknownJson, getInlineImgInfo, getNextAppRouterSitemapTree, getNextAppRouterSourceFolder, getPatternFromModuleFilePath, getRoutesOf, getRoutesWithModulePaths, getSourceAt, isRemoteSchema, isValCanvasFrame, isValCanvasPageMessage, isValCanvasStudioMessage, levenshtein, parseRoutePattern, partitionValidationErrors, remirrorToRichTextSource, resolveSchemaSourceFixForError, resolveSchemaSourceFixes, resolveSerializedSchemaAtPath, richTextToRemirror, safeParsePatch, toolNames, urlOf, validateRoutePatterns, withValCanvasParam };
4572
+ export { Api, CodeOptions, ColorOptions, DEFAULT_ERROR_MESSAGE, DateOptions, FileOptions, ImageEncodeOption, ImageOptions, JSON_ENTRIES_BATCH_MAX, ParentRef$1 as ParentRef, Patch, PatchBlock, PatchGroup, PatchId, PatchJSON, RemirrorBr, RemirrorBulletList, RemirrorHeading, RemirrorImage, RemirrorJSON, RemirrorLinkMark, RemirrorListItem, RemirrorOrderedList, RemirrorParagraph, RemirrorText, RemirrorTextMark, RichTextOptions, SerializedArraySchema, SerializedBooleanSchema, SerializedCodeSchema, SerializedColorSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedFileSchema, SerializedImageSchema, SerializedKeyOfSchema, SerializedLiteralSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedRecordSchema, SerializedRichTextSchema, SerializedRouteSchema, SerializedSchema, SerializedStringSchema, SerializedUnionSchema, SharedValConfig, VAL_AI_SESSION_STORAGE_KEY, VAL_CANVAS_MESSAGE, VAL_CANVAS_PARAM, VAL_CONFIG_SESSION_STORAGE_KEY, VAL_ENABLE_COOKIE_NAME, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, VAL_THEME_SESSION_STORAGE_KEY, ValCommit, ValDeployment, buildDuplicatePatch, buildEmptyAtPathPatch, buildFileRefValue, buildImageGalleryPatch, buildRemoveImageGalleryEntryPatch, createRegExpFromPattern, createValClient, describeContainerAtPath, emptyOf, filterBlockingValidationErrors, filterRoutesByPatterns, findSimilar, getErrorMessageFromUnknownJson, getInlineImgInfo, getNextAppRouterSitemapTree, getNextAppRouterSourceFolder, getPatternFromModuleFilePath, getRoutesOf, getRoutesWithModulePaths, getSourceAt, isRemoteSchema, isValCanvasFrame, isValCanvasPageMessage, isValCanvasStudioMessage, levenshtein, newestCommitSha, parseRoutePattern, partitionValidationErrors, remirrorToRichTextSource, resolveSchemaSourceFixForError, resolveSchemaSourceFixes, resolveSerializedSchemaAtPath, richTextToRemirror, safeParsePatch, toolNames, urlOf, validateRoutePatterns, withValCanvasParam };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valbuild/shared",
3
- "version": "0.118.0",
3
+ "version": "0.121.0",
4
4
  "private": false,
5
5
  "description": "Val shared types and utilities",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  "dependencies": {
32
32
  "zod": "^4.4.3",
33
33
  "zod-validation-error": "^5.0.0",
34
- "@valbuild/core": "0.117.0"
34
+ "@valbuild/core": "0.121.0"
35
35
  },
36
36
  "files": [
37
37
  "CHANGELOG.md",