@valbuild/tanstack 0.135.0 → 0.136.1

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,58 @@
1
1
  # @valbuild/tanstack
2
2
 
3
+ ## 0.136.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#697](https://github.com/valbuild/val/pull/697) [`5c82928`](https://github.com/valbuild/val/commit/5c82928992d29f133f81cf0704a273c0449b18f1) Thanks [@freekh](https://github.com/freekh)! - Read draft content once per request instead of once per `fetchVal`
8
+
9
+ In draft mode, `fetchVal` resolves its selector by asking the Val server for the
10
+ whole module tree. It did that on every call, so a page with three reads made
11
+ three requests for three identical answers — and `fetchValRouteUrl` added a
12
+ fourth by calling `fetchVal` again on top of the caller's own. The answer cannot
13
+ differ between reads in one request, so it is now read once and shared. On a
14
+ 60-module project a three-read draft render goes from ~187ms to ~70ms.
15
+
16
+ The memo is scoped to the request and nothing wider, because the response it
17
+ holds contains the caller's own unpublished patches: React's `cache()` in a
18
+ Next RSC, a `WeakMap` keyed on the `Request` in TanStack Start, and no caching
19
+ at all where neither is available.
20
+
21
+ What this does **not** change:
22
+
23
+ - **Production is untouched.** With Val disabled the reader never calls the
24
+ server; it resolves against the statically imported module, as before.
25
+ - **What a draft shows is unchanged.** Same query, same patch scoping — a draft
26
+ still shows the caller's own staged work and nobody else's.
27
+ - **The client readers are untouched.** `useVal` already subscribed to exactly
28
+ the modules its selector names.
29
+ - **The server still evaluates every module per request.** Narrowing the
30
+ request's path was measured and does not help: `/sources/~` evaluates,
31
+ previews and validates everything and only then filters the response, so a
32
+ narrow path returns less for the same milliseconds. That remains open.
33
+
34
+ - Updated dependencies [[`cf89e74`](https://github.com/valbuild/val/commit/cf89e7429a79c4304ecbedd4f8b571a0de0f145f), [`c219574`](https://github.com/valbuild/val/commit/c21957498f3c7f4f47cef197c5dc0d591aa744ca), [`e673b43`](https://github.com/valbuild/val/commit/e673b43feaf48b7f30881d6786c858a0cb6a44a2), [`5c82928`](https://github.com/valbuild/val/commit/5c82928992d29f133f81cf0704a273c0449b18f1), [`4450be5`](https://github.com/valbuild/val/commit/4450be570ec3a66d7d98ba273c333ca2d2f163d9), [`d2f385a`](https://github.com/valbuild/val/commit/d2f385a04978992a5036379235e447ba7775faef)]:
35
+ - @valbuild/ui@0.136.1
36
+ - @valbuild/shared@0.136.1
37
+ - @valbuild/server@0.136.1
38
+ - @valbuild/core@0.136.1
39
+ - @valbuild/react@0.136.1
40
+ - @valbuild/language-server@0.136.1
41
+ - @valbuild/mcp@0.136.1
42
+
43
+ ## 0.136.0
44
+
45
+ ### Patch Changes
46
+
47
+ - Updated dependencies [[`f3a4bb7`](https://github.com/valbuild/val/commit/f3a4bb7aea604943b92545c122243798c759715c), [`1d72d00`](https://github.com/valbuild/val/commit/1d72d00a1b036959ae0f1540121701cbb2694dcb)]:
48
+ - @valbuild/ui@0.136.0
49
+ - @valbuild/core@0.136.0
50
+ - @valbuild/server@0.136.0
51
+ - @valbuild/shared@0.136.0
52
+ - @valbuild/language-server@0.136.0
53
+ - @valbuild/react@0.136.0
54
+ - @valbuild/mcp@0.136.0
55
+
3
56
  ## 0.135.0
4
57
 
5
58
  ### Patch Changes
@@ -1,24 +1,71 @@
1
1
  import { type JsonEntryContentOf, type Resolvable, type ResolvedVal, type RouteValueOf } from "@valbuild/react/stega";
2
2
  import { ValConfig, ValModules, type ResolvableModule } from "@valbuild/core";
3
+ import { type RequestScopedMemo } from "@valbuild/shared/internal";
3
4
  import { ValServer, type ValPatchStore } from "@valbuild/server";
4
5
  import { type ValDraftMode } from "./valDraftMode.js";
5
6
  import type { ValHttpMode } from "./initValServer.js";
6
- declare const initFetchValStega: (config: ValConfig, valApiEndpoints: string, valServerPromise: Promise<ValServer>, isEnabled: () => Promise<boolean>, getHeaders: () => Promise<{
7
+ /**
8
+ * The `modules` map every `fetchVal` in one request shares.
9
+ *
10
+ * Derived from the route's own response type rather than restated, so it cannot
11
+ * drift from what `/sources/~` actually returns.
12
+ */
13
+ export type DraftSources = Extract<Awaited<ReturnType<ValServer["/sources/~"]["PUT"]>>, {
14
+ status: 200;
15
+ }>["json"]["modules"];
16
+ /**
17
+ * The slice of `ValServer` the draft-sources reader uses.
18
+ *
19
+ * Narrower than `ValServer` for the same reason `JsonEntryValServer` below is:
20
+ * it says what the dependency IS, and it lets a test drive the reader with a
21
+ * one-route fake instead of casting a partial object to the whole server type.
22
+ */
23
+ export type DraftSourcesValServer = Pick<ValServer, "/sources/~">;
24
+ /** What the route readers need: the tree, plus the single-entry route. */
25
+ export type RouteReaderValServer = Pick<ValServer, "/sources/~" | "/json">;
26
+ /**
27
+ * Where the reader gets its per-request memo box.
28
+ *
29
+ * Injected rather than reached for, so that "this reader needs a request to
30
+ * scope its cache to" is part of its contract and a test can supply a scope it
31
+ * controls — there is no TanStack request in jest.
32
+ */
33
+ export type GetDraftSourcesScope = () => Promise<RequestScopedMemo<DraftSources | null> | null>;
34
+ /**
35
+ * A per-request memo box, keyed on the `Request` itself.
36
+ *
37
+ * That is what makes this safe: TanStack resolves one `Request` object per
38
+ * in-flight request out of async local storage, so two visitors cannot collide,
39
+ * and a `WeakMap` lets the entry go when the request does. This is the TanStack
40
+ * half of the Next package's `cache()` — there is no RSC here, so React's
41
+ * request memoisation does not exist (see the note at the top of this file).
42
+ *
43
+ * Outside a request there is nothing to scope to and `getRequest` throws;
44
+ * `null` then means "compute every time", which is what this did before the
45
+ * memo existed. See `memoizePerRequest`.
46
+ *
47
+ * Built PER `initValContent` rather than once for the module, because the box
48
+ * is only as specific as the map it came from: two Val servers in one process
49
+ * sharing one would answer each other's reads within a request, and they hold
50
+ * different content.
51
+ */
52
+ export declare function createTanStackRequestScope(): GetDraftSourcesScope;
53
+ export declare const initFetchValStega: (config: ValConfig, valApiEndpoints: string, valServerPromise: Promise<DraftSourcesValServer>, isEnabled: () => Promise<boolean>, getHeaders: () => Promise<{
7
54
  get(name: string): string | null;
8
55
  }>, getCookies: () => Promise<{
9
56
  get(name: string): {
10
57
  name: string;
11
58
  value: string;
12
59
  } | undefined;
13
- }>) => <T extends Resolvable>(selector: T) => Promise<ResolvedVal<T>>;
14
- declare const initFetchValRouteStega: (config: ValConfig, valApiEndpoints: string, valServerPromise: Promise<ValServer>, isEnabled: () => Promise<boolean>, getHeaders: () => Promise<{
60
+ }>, getDraftSourcesScope: GetDraftSourcesScope) => <T extends Resolvable>(selector: T) => Promise<ResolvedVal<T>>;
61
+ declare const initFetchValRouteStega: (config: ValConfig, valApiEndpoints: string, valServerPromise: Promise<RouteReaderValServer>, isEnabled: () => Promise<boolean>, getHeaders: () => Promise<{
15
62
  get(name: string): string | null;
16
63
  }>, getCookies: () => Promise<{
17
64
  get(name: string): {
18
65
  name: string;
19
66
  value: string;
20
67
  } | undefined;
21
- }>) => <T extends ResolvableModule>(selector: T, params: Promise<Record<string, string | string[]>> | Record<string, string | string[]> | unknown) => Promise<RouteValueOf<T>>;
68
+ }>, getDraftSourcesScope: GetDraftSourcesScope) => <T extends ResolvableModule>(selector: T, params: Promise<Record<string, string | string[]>> | Record<string, string | string[]> | unknown) => Promise<RouteValueOf<T>>;
22
69
  /**
23
70
  * Loads a single `.jsonValues()` entry's DRAFT content via the in-process
24
71
  * `/json` endpoint (which replays pending patches). Returns `undefined` when the
@@ -76,14 +123,14 @@ export declare const initFetchValKeyStega: (valServerPromise: Promise<JsonEntryV
76
123
  value: string;
77
124
  } | undefined;
78
125
  }>) => <T extends ResolvableModule>(selector: T, key: string) => Promise<JsonEntryContentOf<T> | undefined>;
79
- declare const initFetchValRouteUrl: (config: ValConfig, valApiEndpoints: string, valServerPromise: Promise<ValServer>, isEnabled: () => Promise<boolean>, getHeaders: () => Promise<{
126
+ declare const initFetchValRouteUrl: (config: ValConfig, valApiEndpoints: string, valServerPromise: Promise<RouteReaderValServer>, isEnabled: () => Promise<boolean>, getHeaders: () => Promise<{
80
127
  get(name: string): string | null;
81
128
  }>, getCookies: () => Promise<{
82
129
  get(name: string): {
83
130
  name: string;
84
131
  value: string;
85
132
  } | undefined;
86
- }>) => <T extends ResolvableModule>(selector: T, params?: Promise<Record<string, string | string[]>> | Record<string, string | string[]> | unknown) => Promise<string | null>;
133
+ }>, getDraftSourcesScope: GetDraftSourcesScope) => <T extends ResolvableModule>(selector: T, params?: Promise<Record<string, string | string[]>> | Record<string, string | string[]> | unknown) => Promise<string | null>;
87
134
  /**
88
135
  * Val's content readers for the server side of a TanStack Start app.
89
136
  *
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = require('./version-d7ff1ff7.cjs.dev.js');
5
+ var version = require('./version-e63e1b48.cjs.dev.js');
6
6
  var createForOfIteratorHelper = require('./createForOfIteratorHelper-e75681d7.cjs.dev.js');
7
7
  var core = require('@valbuild/core');
8
8
  var stega = require('@valbuild/react/stega');
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = require('./version-a940a26b.cjs.prod.js');
5
+ var version = require('./version-abf2eb56.cjs.prod.js');
6
6
  var createForOfIteratorHelper = require('./createForOfIteratorHelper-0324e063.cjs.prod.js');
7
7
  var core = require('@valbuild/core');
8
8
  var stega = require('@valbuild/react/stega');
@@ -1,4 +1,4 @@
1
- import { _ as _asyncToGenerator, a as _regenerator, r as readValEnableCookie, V as VERSION$1 } from './version-78c09a89.esm.js';
1
+ import { _ as _asyncToGenerator, a as _regenerator, r as readValEnableCookie, V as VERSION$1 } from './version-eb1cf21e.esm.js';
2
2
  import { _ as _objectSpread2, a as _slicedToArray, b as _createForOfIteratorHelper } from './createForOfIteratorHelper-485c2ce1.esm.js';
3
3
  import { Internal as Internal$1, initVal as initVal$1, DEFAULT_CONTENT_HOST } from '@valbuild/core';
4
4
  import * as core from '@valbuild/core';
@@ -212,7 +212,7 @@ var packageJson = {
212
212
  "tanstack-router",
213
213
  "react"
214
214
  ],
215
- version: "0.135.0",
215
+ version: "0.136.1",
216
216
  scripts: {
217
217
  typecheck: "tsc --noEmit",
218
218
  test: "jest"
@@ -212,7 +212,7 @@ var packageJson = {
212
212
  "tanstack-router",
213
213
  "react"
214
214
  ],
215
- version: "0.135.0",
215
+ version: "0.136.1",
216
216
  scripts: {
217
217
  typecheck: "tsc --noEmit",
218
218
  test: "jest"
@@ -210,7 +210,7 @@ var packageJson = {
210
210
  "tanstack-router",
211
211
  "react"
212
212
  ],
213
- version: "0.135.0",
213
+ version: "0.136.1",
214
214
  scripts: {
215
215
  typecheck: "tsc --noEmit",
216
216
  test: "jest"
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "tanstack-router",
15
15
  "react"
16
16
  ],
17
- "version": "0.135.0",
17
+ "version": "0.136.1",
18
18
  "main": "dist/valbuild-tanstack.cjs.js",
19
19
  "module": "dist/valbuild-tanstack.esm.js",
20
20
  "exports": {
@@ -42,13 +42,13 @@
42
42
  "exports": true
43
43
  },
44
44
  "dependencies": {
45
- "@valbuild/core": "0.134.0",
46
- "@valbuild/language-server": "0.135.0",
47
- "@valbuild/mcp": "0.135.0",
48
- "@valbuild/react": "0.134.1",
49
- "@valbuild/server": "0.135.0",
50
- "@valbuild/ui": "0.134.0",
51
- "@valbuild/shared": "0.134.1"
45
+ "@valbuild/core": "0.136.1",
46
+ "@valbuild/language-server": "0.136.1",
47
+ "@valbuild/mcp": "0.136.1",
48
+ "@valbuild/react": "0.136.1",
49
+ "@valbuild/server": "0.136.1",
50
+ "@valbuild/shared": "0.136.1",
51
+ "@valbuild/ui": "0.136.1"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@tanstack/react-router": "^1.170.33",