@valbuild/cli 0.124.0 → 0.126.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,182 @@
1
1
  # @valbuild/cli
2
2
 
3
+ ## 0.126.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [#652](https://github.com/valbuild/val/pull/652) [`f2fe70d`](https://github.com/valbuild/val/commit/f2fe70dab2b65000dfaf289f09c70b4a8291467a) Thanks [@freekh](https://github.com/freekh)! - `s.union` is now `s.discriminatedUnion` and `s.enum`.
8
+
9
+ `s.union` did two unrelated jobs and worked out which one you meant from its
10
+ first argument: a string key meant a tagged union of objects, literal schemas
11
+ meant a set of allowed strings. Those are now two schemas with two names.
12
+
13
+ ```ts
14
+ // A fixed set of strings — presents as a dropdown
15
+ s.enum("primary", "secondary", "ghost"); // Schema<"primary" | "secondary" | "ghost">
16
+
17
+ // One of several object shapes, told apart by a tag field
18
+ s.discriminatedUnion(
19
+ "type",
20
+ s.object({ type: s.literal("hero"), heading: s.string() }),
21
+ s.object({ type: s.literal("quote"), text: s.string() }),
22
+ );
23
+ ```
24
+
25
+ `s.enum` takes the strings directly, so the `s.literal(...)` wrapper is gone.
26
+
27
+ **`s.union` still works** — it is deprecated, and it builds exactly the schema
28
+ above, so nothing has to change today:
29
+
30
+ ```ts
31
+ s.union(s.literal("one"), s.literal("two")); // → s.enum("one", "two")
32
+ s.union("type", pageA, pageB); // → s.discriminatedUnion("type", pageA, pageB)
33
+ ```
34
+
35
+ The two are different kinds of node, and that is the reason for the split. A
36
+ discriminated union is a container: the selected variant's fields are the fields
37
+ being edited, and everything that walks a schema descends through it. An enum is
38
+ a leaf — a string with a closed domain — so nothing recurses into it. Told apart
39
+ only by the shape of `key`, every consumer had to re-derive which one it was
40
+ holding; each now has its own serialized type (`"discriminated-union"` and
41
+ `"enum"`) and Val Studio has a field per kind rather than one field that
42
+ branches.
43
+
44
+ Two behaviour changes fall out of the split, both of them fixes:
45
+
46
+ - A value that is not a string at all now fails an enum's validation with a
47
+ type error. `s.union` of literals only ever checked the value against its
48
+ literals when the value WAS a string, so a number or an object where an enum
49
+ was declared validated clean.
50
+ - An enum field now shows its validation errors in Val Studio where the field
51
+ is opened on its own — the module editor and the canvas's fields column — and
52
+ gets the compact error layout inside an inline list row. It is a leaf now, so
53
+ it goes through the same error rendering as every other leaf field; the string
54
+ union bypassed it and showed nothing in those places.
55
+
56
+ Several latent crashes in the old `s.union` are fixed on the way past, all of
57
+ them cases where it threw a `TypeError` instead of reporting:
58
+
59
+ - A required discriminated union holding `null` now reports a type error rather
60
+ than throwing, and resolving a path underneath a nullable one that is `null`
61
+ gives the error the API promises instead of a crash.
62
+ - `s.literal("")` is a legal discriminator tag, and `s.enum("")` a legal value.
63
+ Both used to be treated as absent by a truthiness check — in path resolution,
64
+ in stega encoding, and in the message that lists a union's valid tags. The
65
+ editor's dropdowns handle them too: an empty value is reserved by the select
66
+ component and had to be mapped around.
67
+ - A variant that omits the discriminator entirely is now reported as the schema
68
+ error it is, instead of throwing while the check looked for it.
69
+ - An enum's value is now indexed for search, like every other string leaf. The
70
+ old string union was never indexed at all, so searching for one of its values
71
+ could not find the field.
72
+ - A nullable discriminated union set to `null` no longer renders a spinner that
73
+ never resolves.
74
+
75
+ `s.discriminatedUnion` also requires at least one variant, as `s.enum` requires
76
+ at least one value: a union with nothing to select is not a thing to write, and
77
+ everything downstream reads the first variant where it needs any.
78
+
79
+ If you read serialized schemas yourself, that is the breaking part: `type` is no
80
+ longer `"union"`, an enum carries `values: string[]` instead of a `key` plus
81
+ `items` of literal schemas, and `UnionSchema` is no longer a class.
82
+ `SerializedUnionSchema`, `SerializedStringUnionSchema`,
83
+ `SerializedObjectUnionSchema` and `UnionSchema` remain as deprecated type
84
+ aliases.
85
+
86
+ - Updated dependencies [[`5bfd630`](https://github.com/valbuild/val/commit/5bfd630b63dee2189e238f20fe72ecc5537160f7), [`ccbcda6`](https://github.com/valbuild/val/commit/ccbcda60b3e3c465071229ae1ba28ac735483e63), [`f2fe70d`](https://github.com/valbuild/val/commit/f2fe70dab2b65000dfaf289f09c70b4a8291467a), [`5c18c99`](https://github.com/valbuild/val/commit/5c18c99ecc84651f82123481fc042063db953833), [`171208a`](https://github.com/valbuild/val/commit/171208a20177e68ed5a8b1a6fdaabfe893a6aa5f)]:
87
+ - @valbuild/shared@0.126.0
88
+ - @valbuild/server@0.126.0
89
+ - @valbuild/core@0.126.0
90
+ - @valbuild/language-server@0.126.0
91
+
92
+ ## 0.125.0
93
+
94
+ ### Patch Changes
95
+
96
+ - [#638](https://github.com/valbuild/val/pull/638) [`c390397`](https://github.com/valbuild/val/commit/c390397cb5e203eb1bedae3a6fab15726e850b90) Thanks [@freekh](https://github.com/freekh)! - Val now runs on TanStack Start.
97
+
98
+ `@valbuild/tanstack` is a new package with everything `@valbuild/next` has: Val
99
+ Studio at `/val`, the on-page overlay and canvas, draft mode, the client hooks,
100
+ server-side content reads, images, and the MCP tools.
101
+
102
+ ```sh
103
+ npm install @valbuild/tanstack
104
+ ```
105
+
106
+ ```ts
107
+ // val.config.ts
108
+ import { initVal } from "@valbuild/tanstack";
109
+ const { s, c, config, tanstackRouter } = initVal({ project: "org/project" });
110
+ ```
111
+
112
+ **Routes are first class.** A Val module for a route is named after the route
113
+ file it sits beside — `src/routes/posts.$postId.tsx` is served content by
114
+ `src/routes/posts.$postId.val.ts` — and its keys are the URLs that route serves:
115
+
116
+ ```ts
117
+ export default c.define(
118
+ "/src/routes/posts.$postId.val.ts",
119
+ s.router(tanstackRouter, s.object({ title: s.string() })),
120
+ { "/posts/hello-world": { title: "Hello world" } },
121
+ );
122
+ ```
123
+
124
+ `.` and `/` both separate segments, `$param` is a parameter, `$` is a splat, and
125
+ `index`, `route`, `(groups)` and `_pathless` layouts add no URL segment — the
126
+ same rules TanStack Router uses for the route file itself. Val validates every
127
+ key against that pattern, and Val Studio shows these modules as a sitemap under
128
+ **Pages**, where an editor can add a page.
129
+
130
+ Point the route generator away from your content files, in `vite.config.ts` and
131
+ `tsr.config.json`:
132
+
133
+ ```ts
134
+ tanstackStart({ router: { routeFileIgnorePattern: "\\.val\\.[tj]sx?$" } });
135
+ ```
136
+
137
+ See the [README](https://github.com/valbuild/val/blob/main/packages/tanstack/README.md)
138
+ for the full wiring, and `examples/tanstack` for a working app.
139
+
140
+ **Also fixed, for everyone:** `Internal.VERSION.core` was `null` in any ESM
141
+ bundle — it was read with `require("../package.json")` inside a `try`, so the
142
+ failure was silent. That version goes into every remote file ref and proxy mode
143
+ refuses to start without it. Every package now reads its version through a
144
+ static JSON import, which is inlined at build time.
145
+
146
+ Two smaller fixes that came out of running the whole toolchain against a
147
+ TanStack project:
148
+
149
+ - `val versions` reports `@valbuild/tanstack`, and `val debug` writes a snapshot
150
+ that names whichever framework package the captured project actually has.
151
+ - `@valbuild/eslint-plugin` reads a `tsconfig.json` that has comments in it. A
152
+ tsconfig is JSONC, and `JSON.parse` is not — so on any project whose tsconfig
153
+ carries a comment (the TanStack starter's does) the
154
+ `module-in-val-modules` rule threw `Expected double-quoted property name in
155
+ JSON` on the first file and took the whole lint run with it.
156
+
157
+ Three fixes found by driving the Studio against a real TanStack app:
158
+
159
+ - **A draft image now loads on the page.** The source the Studio pushes to the
160
+ host page carries `patch_id` for any file whose bytes are still in a patch, so
161
+ the page asks `/api/val/files/...?patch_id=` rather than a `/public` path that
162
+ nothing has written yet. This was silent — the image just did not appear — and
163
+ it affects any page that reads media through the hooks rather than on the
164
+ server, `@valbuild/next` included.
165
+ - **A splat route no longer logs an error on every render.** TanStack returns
166
+ both `_splat` and `*` for the same parameter; Val reported the second as a
167
+ parameter it could not place in the path.
168
+ - The TanStack example and starter render a 404 page instead of throwing
169
+ `notFound()` from a component, which escaped to the error boundary and logged
170
+ `Error in renderToReadableStream` (and, with no not-found component
171
+ configured, aborted the response) on every miss.
172
+
173
+ - Updated dependencies [[`22f78b4`](https://github.com/valbuild/val/commit/22f78b471fd18e542f518f72b75bd472d7c3dc52), [`c390397`](https://github.com/valbuild/val/commit/c390397cb5e203eb1bedae3a6fab15726e850b90)]:
174
+ - @valbuild/language-server@0.125.0
175
+ - @valbuild/core@0.125.0
176
+ - @valbuild/shared@0.125.0
177
+ - @valbuild/eslint-plugin@0.125.0
178
+ - @valbuild/server@0.125.0
179
+
3
180
  ## 0.124.0
4
181
 
5
182
  ### Patch Changes
@@ -975,30 +975,33 @@ function isFileRef(value) {
975
975
  return !!value && typeof value === "object" && "path" in value && typeof value.path === "string";
976
976
  }
977
977
 
978
+ /**
979
+ * The versions of the Val packages this project has installed.
980
+ *
981
+ * Each is resolved from the project rather than declared, because the CLI is a
982
+ * dependency of the project and not the other way round — and a project has
983
+ * exactly one framework package, so the one that is absent is absent rather
984
+ * than broken. `undefined` is the honest answer for it.
985
+ */
978
986
  const getVersions = () => {
979
- const coreVersion = (() => {
980
- try {
981
- var _require;
982
- // eslint-disable-next-line @typescript-eslint/no-require-imports
983
- return (_require = require("@valbuild/core")) === null || _require === void 0 || (_require = _require.Internal) === null || _require === void 0 || (_require = _require.VERSION) === null || _require === void 0 ? void 0 : _require.core;
984
- } catch {
985
- return null;
986
- }
987
- })();
988
- const nextVersion = (() => {
989
- try {
990
- var _require2;
991
- // eslint-disable-next-line @typescript-eslint/no-require-imports
992
- return (_require2 = require("@valbuild/next")) === null || _require2 === void 0 || (_require2 = _require2.Internal) === null || _require2 === void 0 || (_require2 = _require2.VERSION) === null || _require2 === void 0 ? void 0 : _require2.next;
993
- } catch {
994
- return null;
995
- }
996
- })();
987
+ const coreVersion = requireVersion("@valbuild/core", "core");
988
+ const nextVersion = requireVersion("@valbuild/next", "next");
989
+ const tanstackVersion = requireVersion("@valbuild/tanstack", "tanstack");
997
990
  return {
998
991
  coreVersion: coreVersion || undefined,
999
- nextVersion: nextVersion || undefined
992
+ nextVersion: nextVersion || undefined,
993
+ tanstackVersion: tanstackVersion || undefined
1000
994
  };
1001
995
  };
996
+ function requireVersion(packageName, key) {
997
+ try {
998
+ var _require;
999
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
1000
+ return ((_require = require(packageName)) === null || _require === void 0 || (_require = _require.Internal) === null || _require === void 0 || (_require = _require.VERSION) === null || _require === void 0 ? void 0 : _require[key]) ?? null;
1001
+ } catch {
1002
+ return null;
1003
+ }
1004
+ }
1002
1005
 
1003
1006
  const host = process.env.VAL_BUILD_URL || "https://admin.val.build";
1004
1007
  async function connect(options) {
@@ -1365,10 +1368,7 @@ function collectSchemaReferences(schema) {
1365
1368
  visit(item, false);
1366
1369
  }
1367
1370
  break;
1368
- case "union":
1369
- if (typeof node.key !== "string") {
1370
- visit(node.key, false);
1371
- }
1371
+ case "discriminated-union":
1372
1372
  for (const item of node.items) {
1373
1373
  visit(item, false);
1374
1374
  }
@@ -1597,6 +1597,7 @@ async function buildSnapshot(ctx, options = {}) {
1597
1597
  versions: {
1598
1598
  core: getVersions().coreVersion,
1599
1599
  next: getVersions().nextVersion,
1600
+ tanstack: getVersions().tanstackVersion,
1600
1601
  project: readProjectValVersions(ctx.projectRoot),
1601
1602
  node: process.version,
1602
1603
  platform: `${process.platform}-${process.arch}`
@@ -1692,9 +1693,18 @@ function generateValModules(moduleFilePaths) {
1692
1693
  const withoutExt = moduleFilePath.replace(/\.(ts|js|tsx|jsx)$/, "");
1693
1694
  return ` { def: () => import(".${withoutExt}") },`;
1694
1695
  }).join("\n");
1696
+ /*
1697
+ * The framework package the captured project actually has.
1698
+ *
1699
+ * A snapshot is replayed by loading this file, so naming the wrong one makes
1700
+ * it fail to resolve on a machine that has the other. `getVersions` answers
1701
+ * from what is installed; the fallback matters only for a project with
1702
+ * neither, which could not have produced a snapshot anyway.
1703
+ */
1704
+ const frameworkPackage = getVersions().tanstackVersion ? "@valbuild/tanstack" : "@valbuild/next";
1695
1705
  return `// GENERATED by \`val debug\`: trimmed to the modules this snapshot carries.
1696
1706
  // The project's original is kept as val.modules.original.ts.
1697
- import { modules } from "@valbuild/next";
1707
+ import { modules } from "${frameworkPackage}";
1698
1708
  import { config } from "./val.config";
1699
1709
 
1700
1710
  export default modules(config, [
@@ -1709,7 +1719,7 @@ Captured ${manifest.generatedAt} from project \`${manifest.project ?? "(fs mode)
1709
1719
  branch \`${manifest.branch ?? "?"}\`, commit \`${manifest.commit ?? "?"}\`.
1710
1720
 
1711
1721
  - @valbuild/core: \`${manifest.versions.core ?? "?"}\`
1712
- - @valbuild/next: \`${manifest.versions.next ?? "?"}\`
1722
+ - ${manifest.versions.tanstack ? `@valbuild/tanstack: \`${manifest.versions.tanstack}\`` : `@valbuild/next: \`${manifest.versions.next ?? "?"}\``}
1713
1723
  - ${manifest.patchCount} pending patches, ${manifest.unappliablePatchCount} of which could not be applied.
1714
1724
 
1715
1725
  ## Replaying it
@@ -2234,5 +2244,15 @@ void main().catch(err => {
2234
2244
  async function versions() {
2235
2245
  const foundVersions = getVersions();
2236
2246
  console.log(`${chalk__default["default"].cyan("@valbuild/core")}: ${foundVersions.coreVersion}`);
2237
- console.log(`${chalk__default["default"].cyan("@valbuild/next")}: ${foundVersions.nextVersion}`);
2247
+ // Only the framework package this project actually has. Printing the other
2248
+ // as `undefined` reads as something missing rather than something absent.
2249
+ if (foundVersions.nextVersion) {
2250
+ console.log(`${chalk__default["default"].cyan("@valbuild/next")}: ${foundVersions.nextVersion}`);
2251
+ }
2252
+ if (foundVersions.tanstackVersion) {
2253
+ console.log(`${chalk__default["default"].cyan("@valbuild/tanstack")}: ${foundVersions.tanstackVersion}`);
2254
+ }
2255
+ if (!foundVersions.nextVersion && !foundVersions.tanstackVersion) {
2256
+ console.log(`${chalk__default["default"].yellow("No framework package found")}: install @valbuild/next or @valbuild/tanstack`);
2257
+ }
2238
2258
  }
@@ -975,30 +975,33 @@ function isFileRef(value) {
975
975
  return !!value && typeof value === "object" && "path" in value && typeof value.path === "string";
976
976
  }
977
977
 
978
+ /**
979
+ * The versions of the Val packages this project has installed.
980
+ *
981
+ * Each is resolved from the project rather than declared, because the CLI is a
982
+ * dependency of the project and not the other way round — and a project has
983
+ * exactly one framework package, so the one that is absent is absent rather
984
+ * than broken. `undefined` is the honest answer for it.
985
+ */
978
986
  const getVersions = () => {
979
- const coreVersion = (() => {
980
- try {
981
- var _require;
982
- // eslint-disable-next-line @typescript-eslint/no-require-imports
983
- return (_require = require("@valbuild/core")) === null || _require === void 0 || (_require = _require.Internal) === null || _require === void 0 || (_require = _require.VERSION) === null || _require === void 0 ? void 0 : _require.core;
984
- } catch {
985
- return null;
986
- }
987
- })();
988
- const nextVersion = (() => {
989
- try {
990
- var _require2;
991
- // eslint-disable-next-line @typescript-eslint/no-require-imports
992
- return (_require2 = require("@valbuild/next")) === null || _require2 === void 0 || (_require2 = _require2.Internal) === null || _require2 === void 0 || (_require2 = _require2.VERSION) === null || _require2 === void 0 ? void 0 : _require2.next;
993
- } catch {
994
- return null;
995
- }
996
- })();
987
+ const coreVersion = requireVersion("@valbuild/core", "core");
988
+ const nextVersion = requireVersion("@valbuild/next", "next");
989
+ const tanstackVersion = requireVersion("@valbuild/tanstack", "tanstack");
997
990
  return {
998
991
  coreVersion: coreVersion || undefined,
999
- nextVersion: nextVersion || undefined
992
+ nextVersion: nextVersion || undefined,
993
+ tanstackVersion: tanstackVersion || undefined
1000
994
  };
1001
995
  };
996
+ function requireVersion(packageName, key) {
997
+ try {
998
+ var _require;
999
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
1000
+ return ((_require = require(packageName)) === null || _require === void 0 || (_require = _require.Internal) === null || _require === void 0 || (_require = _require.VERSION) === null || _require === void 0 ? void 0 : _require[key]) ?? null;
1001
+ } catch {
1002
+ return null;
1003
+ }
1004
+ }
1002
1005
 
1003
1006
  const host = process.env.VAL_BUILD_URL || "https://admin.val.build";
1004
1007
  async function connect(options) {
@@ -1365,10 +1368,7 @@ function collectSchemaReferences(schema) {
1365
1368
  visit(item, false);
1366
1369
  }
1367
1370
  break;
1368
- case "union":
1369
- if (typeof node.key !== "string") {
1370
- visit(node.key, false);
1371
- }
1371
+ case "discriminated-union":
1372
1372
  for (const item of node.items) {
1373
1373
  visit(item, false);
1374
1374
  }
@@ -1597,6 +1597,7 @@ async function buildSnapshot(ctx, options = {}) {
1597
1597
  versions: {
1598
1598
  core: getVersions().coreVersion,
1599
1599
  next: getVersions().nextVersion,
1600
+ tanstack: getVersions().tanstackVersion,
1600
1601
  project: readProjectValVersions(ctx.projectRoot),
1601
1602
  node: process.version,
1602
1603
  platform: `${process.platform}-${process.arch}`
@@ -1692,9 +1693,18 @@ function generateValModules(moduleFilePaths) {
1692
1693
  const withoutExt = moduleFilePath.replace(/\.(ts|js|tsx|jsx)$/, "");
1693
1694
  return ` { def: () => import(".${withoutExt}") },`;
1694
1695
  }).join("\n");
1696
+ /*
1697
+ * The framework package the captured project actually has.
1698
+ *
1699
+ * A snapshot is replayed by loading this file, so naming the wrong one makes
1700
+ * it fail to resolve on a machine that has the other. `getVersions` answers
1701
+ * from what is installed; the fallback matters only for a project with
1702
+ * neither, which could not have produced a snapshot anyway.
1703
+ */
1704
+ const frameworkPackage = getVersions().tanstackVersion ? "@valbuild/tanstack" : "@valbuild/next";
1695
1705
  return `// GENERATED by \`val debug\`: trimmed to the modules this snapshot carries.
1696
1706
  // The project's original is kept as val.modules.original.ts.
1697
- import { modules } from "@valbuild/next";
1707
+ import { modules } from "${frameworkPackage}";
1698
1708
  import { config } from "./val.config";
1699
1709
 
1700
1710
  export default modules(config, [
@@ -1709,7 +1719,7 @@ Captured ${manifest.generatedAt} from project \`${manifest.project ?? "(fs mode)
1709
1719
  branch \`${manifest.branch ?? "?"}\`, commit \`${manifest.commit ?? "?"}\`.
1710
1720
 
1711
1721
  - @valbuild/core: \`${manifest.versions.core ?? "?"}\`
1712
- - @valbuild/next: \`${manifest.versions.next ?? "?"}\`
1722
+ - ${manifest.versions.tanstack ? `@valbuild/tanstack: \`${manifest.versions.tanstack}\`` : `@valbuild/next: \`${manifest.versions.next ?? "?"}\``}
1713
1723
  - ${manifest.patchCount} pending patches, ${manifest.unappliablePatchCount} of which could not be applied.
1714
1724
 
1715
1725
  ## Replaying it
@@ -2234,5 +2244,15 @@ void main().catch(err => {
2234
2244
  async function versions() {
2235
2245
  const foundVersions = getVersions();
2236
2246
  console.log(`${chalk__default["default"].cyan("@valbuild/core")}: ${foundVersions.coreVersion}`);
2237
- console.log(`${chalk__default["default"].cyan("@valbuild/next")}: ${foundVersions.nextVersion}`);
2247
+ // Only the framework package this project actually has. Printing the other
2248
+ // as `undefined` reads as something missing rather than something absent.
2249
+ if (foundVersions.nextVersion) {
2250
+ console.log(`${chalk__default["default"].cyan("@valbuild/next")}: ${foundVersions.nextVersion}`);
2251
+ }
2252
+ if (foundVersions.tanstackVersion) {
2253
+ console.log(`${chalk__default["default"].cyan("@valbuild/tanstack")}: ${foundVersions.tanstackVersion}`);
2254
+ }
2255
+ if (!foundVersions.nextVersion && !foundVersions.tanstackVersion) {
2256
+ console.log(`${chalk__default["default"].yellow("No framework package found")}: install @valbuild/next or @valbuild/tanstack`);
2257
+ }
2238
2258
  }
@@ -943,30 +943,33 @@ function isFileRef(value) {
943
943
  return !!value && typeof value === "object" && "path" in value && typeof value.path === "string";
944
944
  }
945
945
 
946
+ /**
947
+ * The versions of the Val packages this project has installed.
948
+ *
949
+ * Each is resolved from the project rather than declared, because the CLI is a
950
+ * dependency of the project and not the other way round — and a project has
951
+ * exactly one framework package, so the one that is absent is absent rather
952
+ * than broken. `undefined` is the honest answer for it.
953
+ */
946
954
  const getVersions = () => {
947
- const coreVersion = (() => {
948
- try {
949
- var _require;
950
- // eslint-disable-next-line @typescript-eslint/no-require-imports
951
- return (_require = require("@valbuild/core")) === null || _require === void 0 || (_require = _require.Internal) === null || _require === void 0 || (_require = _require.VERSION) === null || _require === void 0 ? void 0 : _require.core;
952
- } catch {
953
- return null;
954
- }
955
- })();
956
- const nextVersion = (() => {
957
- try {
958
- var _require2;
959
- // eslint-disable-next-line @typescript-eslint/no-require-imports
960
- return (_require2 = require("@valbuild/next")) === null || _require2 === void 0 || (_require2 = _require2.Internal) === null || _require2 === void 0 || (_require2 = _require2.VERSION) === null || _require2 === void 0 ? void 0 : _require2.next;
961
- } catch {
962
- return null;
963
- }
964
- })();
955
+ const coreVersion = requireVersion("@valbuild/core", "core");
956
+ const nextVersion = requireVersion("@valbuild/next", "next");
957
+ const tanstackVersion = requireVersion("@valbuild/tanstack", "tanstack");
965
958
  return {
966
959
  coreVersion: coreVersion || undefined,
967
- nextVersion: nextVersion || undefined
960
+ nextVersion: nextVersion || undefined,
961
+ tanstackVersion: tanstackVersion || undefined
968
962
  };
969
963
  };
964
+ function requireVersion(packageName, key) {
965
+ try {
966
+ var _require;
967
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
968
+ return ((_require = require(packageName)) === null || _require === void 0 || (_require = _require.Internal) === null || _require === void 0 || (_require = _require.VERSION) === null || _require === void 0 ? void 0 : _require[key]) ?? null;
969
+ } catch {
970
+ return null;
971
+ }
972
+ }
970
973
 
971
974
  const host = process.env.VAL_BUILD_URL || "https://admin.val.build";
972
975
  async function connect(options) {
@@ -1333,10 +1336,7 @@ function collectSchemaReferences(schema) {
1333
1336
  visit(item, false);
1334
1337
  }
1335
1338
  break;
1336
- case "union":
1337
- if (typeof node.key !== "string") {
1338
- visit(node.key, false);
1339
- }
1339
+ case "discriminated-union":
1340
1340
  for (const item of node.items) {
1341
1341
  visit(item, false);
1342
1342
  }
@@ -1565,6 +1565,7 @@ async function buildSnapshot(ctx, options = {}) {
1565
1565
  versions: {
1566
1566
  core: getVersions().coreVersion,
1567
1567
  next: getVersions().nextVersion,
1568
+ tanstack: getVersions().tanstackVersion,
1568
1569
  project: readProjectValVersions(ctx.projectRoot),
1569
1570
  node: process.version,
1570
1571
  platform: `${process.platform}-${process.arch}`
@@ -1660,9 +1661,18 @@ function generateValModules(moduleFilePaths) {
1660
1661
  const withoutExt = moduleFilePath.replace(/\.(ts|js|tsx|jsx)$/, "");
1661
1662
  return ` { def: () => import(".${withoutExt}") },`;
1662
1663
  }).join("\n");
1664
+ /*
1665
+ * The framework package the captured project actually has.
1666
+ *
1667
+ * A snapshot is replayed by loading this file, so naming the wrong one makes
1668
+ * it fail to resolve on a machine that has the other. `getVersions` answers
1669
+ * from what is installed; the fallback matters only for a project with
1670
+ * neither, which could not have produced a snapshot anyway.
1671
+ */
1672
+ const frameworkPackage = getVersions().tanstackVersion ? "@valbuild/tanstack" : "@valbuild/next";
1663
1673
  return `// GENERATED by \`val debug\`: trimmed to the modules this snapshot carries.
1664
1674
  // The project's original is kept as val.modules.original.ts.
1665
- import { modules } from "@valbuild/next";
1675
+ import { modules } from "${frameworkPackage}";
1666
1676
  import { config } from "./val.config";
1667
1677
 
1668
1678
  export default modules(config, [
@@ -1677,7 +1687,7 @@ Captured ${manifest.generatedAt} from project \`${manifest.project ?? "(fs mode)
1677
1687
  branch \`${manifest.branch ?? "?"}\`, commit \`${manifest.commit ?? "?"}\`.
1678
1688
 
1679
1689
  - @valbuild/core: \`${manifest.versions.core ?? "?"}\`
1680
- - @valbuild/next: \`${manifest.versions.next ?? "?"}\`
1690
+ - ${manifest.versions.tanstack ? `@valbuild/tanstack: \`${manifest.versions.tanstack}\`` : `@valbuild/next: \`${manifest.versions.next ?? "?"}\``}
1681
1691
  - ${manifest.patchCount} pending patches, ${manifest.unappliablePatchCount} of which could not be applied.
1682
1692
 
1683
1693
  ## Replaying it
@@ -2202,5 +2212,15 @@ void main().catch(err => {
2202
2212
  async function versions() {
2203
2213
  const foundVersions = getVersions();
2204
2214
  console.log(`${chalk.cyan("@valbuild/core")}: ${foundVersions.coreVersion}`);
2205
- console.log(`${chalk.cyan("@valbuild/next")}: ${foundVersions.nextVersion}`);
2215
+ // Only the framework package this project actually has. Printing the other
2216
+ // as `undefined` reads as something missing rather than something absent.
2217
+ if (foundVersions.nextVersion) {
2218
+ console.log(`${chalk.cyan("@valbuild/next")}: ${foundVersions.nextVersion}`);
2219
+ }
2220
+ if (foundVersions.tanstackVersion) {
2221
+ console.log(`${chalk.cyan("@valbuild/tanstack")}: ${foundVersions.tanstackVersion}`);
2222
+ }
2223
+ if (!foundVersions.nextVersion && !foundVersions.tanstackVersion) {
2224
+ console.log(`${chalk.yellow("No framework package found")}: install @valbuild/next or @valbuild/tanstack`);
2225
+ }
2206
2226
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@valbuild/cli",
3
3
  "private": false,
4
- "version": "0.124.0",
4
+ "version": "0.126.0",
5
5
  "description": "Val CLI tools",
6
6
  "repository": {
7
7
  "type": "git",
@@ -24,11 +24,11 @@
24
24
  "jszip": "^3.10.1",
25
25
  "meow": "^9.0.0",
26
26
  "picocolors": "^1.1.1",
27
- "@valbuild/core": "0.124.0",
28
- "@valbuild/eslint-plugin": "0.108.0",
29
- "@valbuild/language-server": "0.124.0",
30
- "@valbuild/server": "0.124.0",
31
- "@valbuild/shared": "0.124.0"
27
+ "@valbuild/core": "0.126.0",
28
+ "@valbuild/eslint-plugin": "0.125.0",
29
+ "@valbuild/language-server": "0.126.0",
30
+ "@valbuild/server": "0.126.0",
31
+ "@valbuild/shared": "0.126.0"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "prettier": "*",
package/src/cli.ts CHANGED
@@ -228,5 +228,21 @@ void main().catch((err) => {
228
228
  async function versions() {
229
229
  const foundVersions = getVersions();
230
230
  console.log(`${chalk.cyan("@valbuild/core")}: ${foundVersions.coreVersion}`);
231
- console.log(`${chalk.cyan("@valbuild/next")}: ${foundVersions.nextVersion}`);
231
+ // Only the framework package this project actually has. Printing the other
232
+ // as `undefined` reads as something missing rather than something absent.
233
+ if (foundVersions.nextVersion) {
234
+ console.log(
235
+ `${chalk.cyan("@valbuild/next")}: ${foundVersions.nextVersion}`,
236
+ );
237
+ }
238
+ if (foundVersions.tanstackVersion) {
239
+ console.log(
240
+ `${chalk.cyan("@valbuild/tanstack")}: ${foundVersions.tanstackVersion}`,
241
+ );
242
+ }
243
+ if (!foundVersions.nextVersion && !foundVersions.tanstackVersion) {
244
+ console.log(
245
+ `${chalk.yellow("No framework package found")}: install @valbuild/next or @valbuild/tanstack`,
246
+ );
247
+ }
232
248
  }
@@ -150,10 +150,7 @@ function collectSchemaReferences(schema: SerializedSchema): SchemaReferences {
150
150
  visit(item, false);
151
151
  }
152
152
  break;
153
- case "union":
154
- if (typeof node.key !== "string") {
155
- visit(node.key, false);
156
- }
153
+ case "discriminated-union":
157
154
  for (const item of node.items) {
158
155
  visit(item, false);
159
156
  }
@@ -39,6 +39,7 @@ export type SnapshotManifest = {
39
39
  /** Resolved at runtime by the cli that captured this. */
40
40
  core?: string;
41
41
  next?: string;
42
+ tanstack?: string;
42
43
  /**
43
44
  * The @valbuild/* versions the project declares. This is what to check out
44
45
  * in the val repo in order to replay on the code the customer was running.
@@ -253,6 +254,7 @@ export async function buildSnapshot(
253
254
  versions: {
254
255
  core: getVersions().coreVersion,
255
256
  next: getVersions().nextVersion,
257
+ tanstack: getVersions().tanstackVersion,
256
258
  project: readProjectValVersions(ctx.projectRoot),
257
259
  node: process.version,
258
260
  platform: `${process.platform}-${process.arch}`,
@@ -380,9 +382,20 @@ function generateValModules(moduleFilePaths: string[]): string {
380
382
  return ` { def: () => import(".${withoutExt}") },`;
381
383
  })
382
384
  .join("\n");
385
+ /*
386
+ * The framework package the captured project actually has.
387
+ *
388
+ * A snapshot is replayed by loading this file, so naming the wrong one makes
389
+ * it fail to resolve on a machine that has the other. `getVersions` answers
390
+ * from what is installed; the fallback matters only for a project with
391
+ * neither, which could not have produced a snapshot anyway.
392
+ */
393
+ const frameworkPackage = getVersions().tanstackVersion
394
+ ? "@valbuild/tanstack"
395
+ : "@valbuild/next";
383
396
  return `// GENERATED by \`val debug\`: trimmed to the modules this snapshot carries.
384
397
  // The project's original is kept as val.modules.original.ts.
385
- import { modules } from "@valbuild/next";
398
+ import { modules } from "${frameworkPackage}";
386
399
  import { config } from "./val.config";
387
400
 
388
401
  export default modules(config, [
@@ -398,7 +411,11 @@ Captured ${manifest.generatedAt} from project \`${manifest.project ?? "(fs mode)
398
411
  branch \`${manifest.branch ?? "?"}\`, commit \`${manifest.commit ?? "?"}\`.
399
412
 
400
413
  - @valbuild/core: \`${manifest.versions.core ?? "?"}\`
401
- - @valbuild/next: \`${manifest.versions.next ?? "?"}\`
414
+ - ${
415
+ manifest.versions.tanstack
416
+ ? `@valbuild/tanstack: \`${manifest.versions.tanstack}\``
417
+ : `@valbuild/next: \`${manifest.versions.next ?? "?"}\``
418
+ }
402
419
  - ${manifest.patchCount} pending patches, ${manifest.unappliablePatchCount} of which could not be applied.
403
420
 
404
421
  ## Replaying it
@@ -1,25 +1,31 @@
1
+ /**
2
+ * The versions of the Val packages this project has installed.
3
+ *
4
+ * Each is resolved from the project rather than declared, because the CLI is a
5
+ * dependency of the project and not the other way round — and a project has
6
+ * exactly one framework package, so the one that is absent is absent rather
7
+ * than broken. `undefined` is the honest answer for it.
8
+ */
1
9
  export const getVersions = (): {
2
10
  coreVersion?: string;
3
11
  nextVersion?: string;
12
+ tanstackVersion?: string;
4
13
  } => {
5
- const coreVersion = (() => {
6
- try {
7
- // eslint-disable-next-line @typescript-eslint/no-require-imports
8
- return require("@valbuild/core")?.Internal?.VERSION?.core;
9
- } catch {
10
- return null;
11
- }
12
- })();
13
- const nextVersion = (() => {
14
- try {
15
- // eslint-disable-next-line @typescript-eslint/no-require-imports
16
- return require("@valbuild/next")?.Internal?.VERSION?.next;
17
- } catch {
18
- return null;
19
- }
20
- })();
14
+ const coreVersion = requireVersion("@valbuild/core", "core");
15
+ const nextVersion = requireVersion("@valbuild/next", "next");
16
+ const tanstackVersion = requireVersion("@valbuild/tanstack", "tanstack");
21
17
  return {
22
18
  coreVersion: coreVersion || undefined,
23
19
  nextVersion: nextVersion || undefined,
20
+ tanstackVersion: tanstackVersion || undefined,
24
21
  };
25
22
  };
23
+
24
+ function requireVersion(packageName: string, key: string): string | null {
25
+ try {
26
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
27
+ return require(packageName)?.Internal?.VERSION?.[key] ?? null;
28
+ } catch {
29
+ return null;
30
+ }
31
+ }