@valbuild/next 0.120.4 → 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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,107 @@
1
1
  # @valbuild/next
2
2
 
3
+ ## 0.121.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#605](https://github.com/valbuild/val/pull/605) [`6794d29`](https://github.com/valbuild/val/commit/6794d2980bc81284ab7f2cc667f01cc21c9e3a79) Thanks [@freekh](https://github.com/freekh)! - `s.settings()`: the project's settings, as content.
8
+
9
+ A settings module is one per project, at the root of the content tree:
10
+
11
+ ```typescript
12
+ // settings.val.ts
13
+ export default c.define("/settings.val.ts", s.settings(), {});
14
+ ```
15
+
16
+ Register it in `val.modules.ts` like any other module, and it shows up in the
17
+ Studio under the cog at the foot of the left rail. Everything in it is content:
18
+ it is edited as a draft, it appears in the publish diff, and it is the same for
19
+ everyone working on the project.
20
+
21
+ Every key is optional, at every level, so `{}` is a complete settings module —
22
+ and stays one as sections are added. What it holds today is the assistant:
23
+
24
+ ```typescript
25
+ export default c.define("/settings.val.ts", s.settings(), {
26
+ assistant: {
27
+ enabled: true,
28
+ context: "A CMS for developers, run by a team of four in Oslo.",
29
+ tone: "Plain and direct. British English, sentence case in headings.",
30
+ },
31
+ });
32
+ ```
33
+
34
+ `context` is background the assistant would otherwise guess at; `tone` is how it
35
+ should write when it writes content. Both are sent with every message it makes.
36
+
37
+ `enabled` decides whether editors have an assistant, and it has **three** states
38
+ rather than two:
39
+
40
+ - `true` — they do.
41
+ - `false` — they do not, and every trace of it goes: no button in the top bar,
42
+ no row in the quick actions, no panel, nothing sent.
43
+ - unset — nobody has decided. The assistant is still **shown**, and asks to be
44
+ turned on before it is used. Hiding an assistant nobody has decided about
45
+ means nobody discovers it; quietly enabling one means a project starts sending
46
+ its content to a model because it did not know to say no.
47
+
48
+ A project with no settings module at all has an assistant, as before: there is
49
+ nowhere to record a decision, and nowhere for the prompt to write the answer.
50
+
51
+ **Breaking: `ai.chat` is gone from `val.config.ts`.** Whether the assistant is
52
+ available is a decision about the project's content, made by the people who edit
53
+ it, so it moved to settings — turning the chat on used to take a developer, a
54
+ deploy and a code review of a boolean. Remove the whole block:
55
+
56
+ ```diff
57
+ const { s, c, val, config } = initVal({
58
+ - ai: {
59
+ - chat: {
60
+ - experimental: { enable: true },
61
+ - suggestions: ["Summarize", "Fix typos at this page"],
62
+ - title: "Ask me anything",
63
+ - description: "Val can answer questions about the content.",
64
+ - },
65
+ - },
66
+ });
67
+ ```
68
+
69
+ `experimental.enable` becomes `assistant.enabled` in the settings module.
70
+ `suggestions`, `title` and `description` are removed with nothing replacing
71
+ them: the assistant now opens with its own copy. A project that had the chat
72
+ enabled and wants it to stay on for everyone should write
73
+ `assistant: { enabled: true }` — otherwise editors are offered it and asked.
74
+
75
+ `ai.commitMessages` stays in `val.config.ts`, and is unaffected.
76
+
77
+ Two settings modules, or one in a subdirectory, is a module error: the dev
78
+ server refuses to serve sources, `npx val validate` reports it against the file,
79
+ and the Studio says so rather than picking one.
80
+
81
+ ### Patch Changes
82
+
83
+ - [#607](https://github.com/valbuild/val/pull/607) [`2bcbee1`](https://github.com/valbuild/val/commit/2bcbee1be682c2bbd5b7bc7d152ddd4204162fd2) Thanks [@freekh](https://github.com/freekh)! - `.readonly()` and `.hidden()` now take the flag as an argument, so a schema can
84
+ decide these from a variable instead of only from whether the call was written at
85
+ all:
86
+
87
+ ```ts
88
+ s.string().readonly(!canEdit);
89
+ s.image().hidden(hideMedia);
90
+ ```
91
+
92
+ The argument defaults to `true`, so `.readonly()` and `.readonly(true)` are the
93
+ same thing and nothing about existing schemas changes. Passing `false` leaves the
94
+ field editable or visible, which is also what a schema is without the call - it
95
+ is there so the flag can come from a variable.
96
+
97
+ - Updated dependencies [[`105479b`](https://github.com/valbuild/val/commit/105479b84a08846f1fe5971916f6a54275198d12), [`55ec736`](https://github.com/valbuild/val/commit/55ec73651394908b6f440e360d181b95a91c0a93), [`2bcc6fd`](https://github.com/valbuild/val/commit/2bcc6fdff8d668123e07e3c5e81ac6fa1436e47b), [`2bcbee1`](https://github.com/valbuild/val/commit/2bcbee1be682c2bbd5b7bc7d152ddd4204162fd2), [`6794d29`](https://github.com/valbuild/val/commit/6794d2980bc81284ab7f2cc667f01cc21c9e3a79), [`2db27d5`](https://github.com/valbuild/val/commit/2db27d555441bee2dd31817acc8c92b7b718ee55)]:
98
+ - @valbuild/ui@0.121.0
99
+ - @valbuild/shared@0.121.0
100
+ - @valbuild/server@0.121.0
101
+ - @valbuild/core@0.121.0
102
+ - @valbuild/react@0.121.0
103
+ - @valbuild/language-server@0.121.0
104
+
3
105
  ## 0.120.4
4
106
 
5
107
  ### Patch Changes
package/README.md CHANGED
@@ -48,6 +48,7 @@
48
48
  - [Number](#number)
49
49
  - [Boolean](#boolean)
50
50
  - [Nullable](#nullable)
51
+ - [Read-only and hidden fields](#read-only-and-hidden-fields)
51
52
  - [Array](#array)
52
53
  - [Record](#record)
53
54
  - [Router](#router)
@@ -384,6 +385,24 @@ import { s } from "./val.config";
384
385
  s.string().nullable(); // <- Schema<string | null>
385
386
  ```
386
387
 
388
+ ## Read-only and hidden fields
389
+
390
+ `.readonly()` renders a field disabled in the Val editor, and `.hidden()` leaves
391
+ it out of the editor entirely. Both are UI-only: the value is still stored,
392
+ validated and serialized as normal.
393
+
394
+ Both take an optional flag which defaults to `true`, so `.readonly()` and
395
+ `.readonly(true)` are the same thing. Pass it when the decision comes from a
396
+ variable rather than being written out:
397
+
398
+ ```ts
399
+ import { s } from "./val.config";
400
+
401
+ s.string().readonly(); // same as .readonly(true)
402
+ s.string().readonly(!canEdit);
403
+ s.image().hidden(hideMedia);
404
+ ```
405
+
387
406
  ## Description
388
407
 
389
408
  All schema types can be given a human-readable description with `.describe(text)`. Descriptions are shown in the Val editor UI as muted helper text under the field label, helping editors understand what a field is for without leaving the page.
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "next",
13
13
  "react"
14
14
  ],
15
- "version": "0.120.4",
15
+ "version": "0.121.0",
16
16
  "main": "dist/valbuild-next.cjs.js",
17
17
  "module": "dist/valbuild-next.esm.js",
18
18
  "exports": {
@@ -47,12 +47,12 @@
47
47
  "dependencies": {
48
48
  "client-only": "^0.0.1",
49
49
  "server-only": "^0.0.1",
50
- "@valbuild/react": "0.120.4",
51
- "@valbuild/server": "0.120.4",
52
- "@valbuild/shared": "0.120.0",
53
- "@valbuild/core": "0.120.0",
54
- "@valbuild/language-server": "0.120.4",
55
- "@valbuild/ui": "0.120.4"
50
+ "@valbuild/react": "0.121.0",
51
+ "@valbuild/shared": "0.121.0",
52
+ "@valbuild/server": "0.121.0",
53
+ "@valbuild/ui": "0.121.0",
54
+ "@valbuild/core": "0.121.0",
55
+ "@valbuild/language-server": "0.121.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@testing-library/react": "^16.3.3",
@@ -92,7 +92,22 @@ var initFetchValStega = function initFetchValStega(config, valApiEndpoints, valS
92
92
  validate_binary_files: false,
93
93
  exclude_patches: false,
94
94
  // RSC pre-render uses the legacy "server applies patches" path.
95
- apply_patches: undefined
95
+ apply_patches: undefined,
96
+ /*
97
+ * The caller's own staged work, and nobody else's.
98
+ *
99
+ * A draft render cannot name its group ids — it has no client
100
+ * state — so it asks for "mine" and the server resolves them from
101
+ * the session. Without this a preview shows base + every pending
102
+ * patch on the branch, so one person's half-finished edit appears
103
+ * in another person's draft.
104
+ *
105
+ * `patch_id` stays `undefined`: naming an explicit list is for a
106
+ * caller that already knows what it wants, and it would override
107
+ * the resolution rather than intersect with it.
108
+ */
109
+ patch_id: undefined,
110
+ own_patch_groups_only: true
96
111
  },
97
112
  cookies: defineProperty._defineProperty({}, internal.VAL_SESSION_COOKIE, (_cookies = cookies) === null || _cookies === void 0 || (_cookies = _cookies.get(internal.VAL_SESSION_COOKIE)) === null || _cookies === void 0 ? void 0 : _cookies.value)
98
113
  });
@@ -408,7 +423,16 @@ function _loadDraftJsonEntry() {
408
423
  // single-entry shape
409
424
  offset: undefined,
410
425
  limit: undefined,
411
- apply_patches: true
426
+ apply_patches: true,
427
+ /*
428
+ * Scoped the same way the module content beside it is.
429
+ *
430
+ * A draft page renders both, and this call was unscoped — so one page
431
+ * showed base + the caller's group for its modules and base + EVERY
432
+ * pending patch on the branch for any `jsonValues` entry, including other
433
+ * authors' half-finished edits. See the same flag on `/sources/~` above.
434
+ */
435
+ own_patch_groups_only: true
412
436
  },
413
437
  cookies: defineProperty._defineProperty({}, internal.VAL_SESSION_COOKIE, (_cookies3 = cookies) === null || _cookies3 === void 0 || (_cookies3 = _cookies3.get(internal.VAL_SESSION_COOKIE)) === null || _cookies3 === void 0 ? void 0 : _cookies3.value)
414
438
  });
@@ -92,7 +92,22 @@ var initFetchValStega = function initFetchValStega(config, valApiEndpoints, valS
92
92
  validate_binary_files: false,
93
93
  exclude_patches: false,
94
94
  // RSC pre-render uses the legacy "server applies patches" path.
95
- apply_patches: undefined
95
+ apply_patches: undefined,
96
+ /*
97
+ * The caller's own staged work, and nobody else's.
98
+ *
99
+ * A draft render cannot name its group ids — it has no client
100
+ * state — so it asks for "mine" and the server resolves them from
101
+ * the session. Without this a preview shows base + every pending
102
+ * patch on the branch, so one person's half-finished edit appears
103
+ * in another person's draft.
104
+ *
105
+ * `patch_id` stays `undefined`: naming an explicit list is for a
106
+ * caller that already knows what it wants, and it would override
107
+ * the resolution rather than intersect with it.
108
+ */
109
+ patch_id: undefined,
110
+ own_patch_groups_only: true
96
111
  },
97
112
  cookies: defineProperty._defineProperty({}, internal.VAL_SESSION_COOKIE, (_cookies = cookies) === null || _cookies === void 0 || (_cookies = _cookies.get(internal.VAL_SESSION_COOKIE)) === null || _cookies === void 0 ? void 0 : _cookies.value)
98
113
  });
@@ -408,7 +423,16 @@ function _loadDraftJsonEntry() {
408
423
  // single-entry shape
409
424
  offset: undefined,
410
425
  limit: undefined,
411
- apply_patches: true
426
+ apply_patches: true,
427
+ /*
428
+ * Scoped the same way the module content beside it is.
429
+ *
430
+ * A draft page renders both, and this call was unscoped — so one page
431
+ * showed base + the caller's group for its modules and base + EVERY
432
+ * pending patch on the branch for any `jsonValues` entry, including other
433
+ * authors' half-finished edits. See the same flag on `/sources/~` above.
434
+ */
435
+ own_patch_groups_only: true
412
436
  },
413
437
  cookies: defineProperty._defineProperty({}, internal.VAL_SESSION_COOKIE, (_cookies3 = cookies) === null || _cookies3 === void 0 || (_cookies3 = _cookies3.get(internal.VAL_SESSION_COOKIE)) === null || _cookies3 === void 0 ? void 0 : _cookies3.value)
414
438
  });
@@ -88,7 +88,22 @@ var initFetchValStega = function initFetchValStega(config, valApiEndpoints, valS
88
88
  validate_binary_files: false,
89
89
  exclude_patches: false,
90
90
  // RSC pre-render uses the legacy "server applies patches" path.
91
- apply_patches: undefined
91
+ apply_patches: undefined,
92
+ /*
93
+ * The caller's own staged work, and nobody else's.
94
+ *
95
+ * A draft render cannot name its group ids — it has no client
96
+ * state — so it asks for "mine" and the server resolves them from
97
+ * the session. Without this a preview shows base + every pending
98
+ * patch on the branch, so one person's half-finished edit appears
99
+ * in another person's draft.
100
+ *
101
+ * `patch_id` stays `undefined`: naming an explicit list is for a
102
+ * caller that already knows what it wants, and it would override
103
+ * the resolution rather than intersect with it.
104
+ */
105
+ patch_id: undefined,
106
+ own_patch_groups_only: true
92
107
  },
93
108
  cookies: _defineProperty({}, VAL_SESSION_COOKIE, (_cookies = cookies) === null || _cookies === void 0 || (_cookies = _cookies.get(VAL_SESSION_COOKIE)) === null || _cookies === void 0 ? void 0 : _cookies.value)
94
109
  });
@@ -404,7 +419,16 @@ function _loadDraftJsonEntry() {
404
419
  // single-entry shape
405
420
  offset: undefined,
406
421
  limit: undefined,
407
- apply_patches: true
422
+ apply_patches: true,
423
+ /*
424
+ * Scoped the same way the module content beside it is.
425
+ *
426
+ * A draft page renders both, and this call was unscoped — so one page
427
+ * showed base + the caller's group for its modules and base + EVERY
428
+ * pending patch on the branch for any `jsonValues` entry, including other
429
+ * authors' half-finished edits. See the same flag on `/sources/~` above.
430
+ */
431
+ own_patch_groups_only: true
408
432
  },
409
433
  cookies: _defineProperty({}, VAL_SESSION_COOKIE, (_cookies3 = cookies) === null || _cookies3 === void 0 || (_cookies3 = _cookies3.get(VAL_SESSION_COOKIE)) === null || _cookies3 === void 0 ? void 0 : _cookies3.value)
410
434
  });