@tanstack/redact 0.0.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/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +7 -0
- package/dist/core/internal.d.ts +76 -0
- package/dist/core/internal.js +59 -0
- package/dist/core/internal.js.map +7 -0
- package/dist/core/types.d.ts +21 -0
- package/dist/core/types.js +10 -0
- package/dist/core/types.js.map +7 -0
- package/dist/dom/_all.d.ts +17 -0
- package/dist/dom/_all.js +51 -0
- package/dist/dom/_all.js.map +7 -0
- package/dist/dom/client.d.ts +3 -0
- package/dist/dom/client.js +8 -0
- package/dist/dom/client.js.map +7 -0
- package/dist/dom/dispatcher.d.ts +20 -0
- package/dist/dom/dispatcher.js +267 -0
- package/dist/dom/dispatcher.js.map +7 -0
- package/dist/dom/dom.d.ts +10 -0
- package/dist/dom/dom.js +262 -0
- package/dist/dom/dom.js.map +7 -0
- package/dist/dom/event-replay.d.ts +13 -0
- package/dist/dom/event-replay.js +46 -0
- package/dist/dom/event-replay.js.map +7 -0
- package/dist/dom/features/class/full.d.ts +1 -0
- package/dist/dom/features/class/full.js +91 -0
- package/dist/dom/features/class/full.js.map +7 -0
- package/dist/dom/features/class/index.d.ts +1 -0
- package/dist/dom/features/class/index.js +3 -0
- package/dist/dom/features/class/index.js.map +7 -0
- package/dist/dom/features/class/stub.d.ts +1 -0
- package/dist/dom/features/class/stub.js +50 -0
- package/dist/dom/features/class/stub.js.map +7 -0
- package/dist/dom/features/context/full.d.ts +1 -0
- package/dist/dom/features/context/full.js +49 -0
- package/dist/dom/features/context/full.js.map +7 -0
- package/dist/dom/features/context/index.d.ts +1 -0
- package/dist/dom/features/context/index.js +3 -0
- package/dist/dom/features/context/index.js.map +7 -0
- package/dist/dom/features/context/stub.d.ts +1 -0
- package/dist/dom/features/context/stub.js +22 -0
- package/dist/dom/features/context/stub.js.map +7 -0
- package/dist/dom/features/forward-ref/full.d.ts +1 -0
- package/dist/dom/features/forward-ref/full.js +51 -0
- package/dist/dom/features/forward-ref/full.js.map +7 -0
- package/dist/dom/features/forward-ref/index.d.ts +1 -0
- package/dist/dom/features/forward-ref/index.js +3 -0
- package/dist/dom/features/forward-ref/index.js.map +7 -0
- package/dist/dom/features/forward-ref/stub.d.ts +1 -0
- package/dist/dom/features/forward-ref/stub.js +22 -0
- package/dist/dom/features/forward-ref/stub.js.map +7 -0
- package/dist/dom/features/hydration/full.d.ts +61 -0
- package/dist/dom/features/hydration/full.js +264 -0
- package/dist/dom/features/hydration/full.js.map +7 -0
- package/dist/dom/features/hydration/index.d.ts +1 -0
- package/dist/dom/features/hydration/index.js +3 -0
- package/dist/dom/features/hydration/index.js.map +7 -0
- package/dist/dom/features/hydration/stub.d.ts +28 -0
- package/dist/dom/features/hydration/stub.js +66 -0
- package/dist/dom/features/hydration/stub.js.map +7 -0
- package/dist/dom/features/index.d.ts +7 -0
- package/dist/dom/features/index.js +9 -0
- package/dist/dom/features/index.js.map +7 -0
- package/dist/dom/features/lazy/full.d.ts +1 -0
- package/dist/dom/features/lazy/full.js +78 -0
- package/dist/dom/features/lazy/full.js.map +7 -0
- package/dist/dom/features/lazy/index.d.ts +1 -0
- package/dist/dom/features/lazy/index.js +3 -0
- package/dist/dom/features/lazy/index.js.map +7 -0
- package/dist/dom/features/lazy/stub.d.ts +1 -0
- package/dist/dom/features/lazy/stub.js +36 -0
- package/dist/dom/features/lazy/stub.js.map +7 -0
- package/dist/dom/features/memo/full.d.ts +1 -0
- package/dist/dom/features/memo/full.js +59 -0
- package/dist/dom/features/memo/full.js.map +7 -0
- package/dist/dom/features/memo/index.d.ts +1 -0
- package/dist/dom/features/memo/index.js +3 -0
- package/dist/dom/features/memo/index.js.map +7 -0
- package/dist/dom/features/memo/stub.d.ts +1 -0
- package/dist/dom/features/memo/stub.js +36 -0
- package/dist/dom/features/memo/stub.js.map +7 -0
- package/dist/dom/features/portal/full.d.ts +1 -0
- package/dist/dom/features/portal/full.js +19 -0
- package/dist/dom/features/portal/full.js.map +7 -0
- package/dist/dom/features/portal/index.d.ts +1 -0
- package/dist/dom/features/portal/index.js +3 -0
- package/dist/dom/features/portal/index.js.map +7 -0
- package/dist/dom/features/portal/stub.d.ts +1 -0
- package/dist/dom/features/portal/stub.js +7 -0
- package/dist/dom/features/portal/stub.js.map +7 -0
- package/dist/dom/features/suspense/full.d.ts +1 -0
- package/dist/dom/features/suspense/full.js +146 -0
- package/dist/dom/features/suspense/full.js.map +7 -0
- package/dist/dom/features/suspense/index.d.ts +1 -0
- package/dist/dom/features/suspense/index.js +3 -0
- package/dist/dom/features/suspense/index.js.map +7 -0
- package/dist/dom/features/suspense/stub.d.ts +1 -0
- package/dist/dom/features/suspense/stub.js +6 -0
- package/dist/dom/features/suspense/stub.js.map +7 -0
- package/dist/dom/index.d.ts +25 -0
- package/dist/dom/index.js +45 -0
- package/dist/dom/index.js.map +7 -0
- package/dist/dom/portal.d.ts +2 -0
- package/dist/dom/portal.js +15 -0
- package/dist/dom/portal.js.map +7 -0
- package/dist/dom/reconcile.d.ts +40 -0
- package/dist/dom/reconcile.js +795 -0
- package/dist/dom/reconcile.js.map +7 -0
- package/dist/dom/root.d.ts +15 -0
- package/dist/dom/root.js +85 -0
- package/dist/dom/root.js.map +7 -0
- package/dist/dom/test-utils.d.ts +1 -0
- package/dist/dom/test-utils.js +10 -0
- package/dist/dom/test-utils.js.map +7 -0
- package/dist/react/children.d.ts +8 -0
- package/dist/react/children.js +75 -0
- package/dist/react/children.js.map +7 -0
- package/dist/react/class.d.ts +31 -0
- package/dist/react/class.js +40 -0
- package/dist/react/class.js.map +7 -0
- package/dist/react/context.d.ts +27 -0
- package/dist/react/context.js +31 -0
- package/dist/react/context.js.map +7 -0
- package/dist/react/element.d.ts +10 -0
- package/dist/react/element.js +64 -0
- package/dist/react/element.js.map +7 -0
- package/dist/react/hooks.d.ts +37 -0
- package/dist/react/hooks.js +146 -0
- package/dist/react/hooks.js.map +7 -0
- package/dist/react/index.d.ts +76 -0
- package/dist/react/index.js +187 -0
- package/dist/react/index.js.map +7 -0
- package/dist/react/jsx-runtime.d.ts +5 -0
- package/dist/react/jsx-runtime.js +21 -0
- package/dist/react/jsx-runtime.js.map +7 -0
- package/dist/react/memo.d.ts +29 -0
- package/dist/react/memo.js +47 -0
- package/dist/react/memo.js.map +7 -0
- package/dist/react/portal.d.ts +1 -0
- package/dist/react/portal.js +6 -0
- package/dist/react/portal.js.map +7 -0
- package/dist/react/shared-internals.d.ts +33 -0
- package/dist/react/shared-internals.js +29 -0
- package/dist/react/shared-internals.js.map +7 -0
- package/dist/react/suspense.d.ts +15 -0
- package/dist/react/suspense.js +16 -0
- package/dist/react/suspense.js.map +7 -0
- package/dist/scheduler/index.d.ts +44 -0
- package/dist/scheduler/index.js +109 -0
- package/dist/scheduler/index.js.map +7 -0
- package/dist/server/bootstrap-script.d.ts +22 -0
- package/dist/server/bootstrap-script.js +16 -0
- package/dist/server/bootstrap-script.js.map +7 -0
- package/dist/server/dispatcher.d.ts +37 -0
- package/dist/server/dispatcher.js +140 -0
- package/dist/server/dispatcher.js.map +7 -0
- package/dist/server/escape.d.ts +7 -0
- package/dist/server/escape.js +159 -0
- package/dist/server/escape.js.map +7 -0
- package/dist/server/index.d.ts +16 -0
- package/dist/server/index.js +26 -0
- package/dist/server/index.js.map +7 -0
- package/dist/server/renderToString.d.ts +7 -0
- package/dist/server/renderToString.js +29 -0
- package/dist/server/renderToString.js.map +7 -0
- package/dist/server/stream.d.ts +40 -0
- package/dist/server/stream.js +200 -0
- package/dist/server/stream.js.map +7 -0
- package/dist/server/walk.d.ts +33 -0
- package/dist/server/walk.js +298 -0
- package/dist/server/walk.js.map +7 -0
- package/dist/vite/index.d.ts +96 -0
- package/dist/vite/index.js +217 -0
- package/dist/vite/index.js.map +7 -0
- package/package.json +83 -0
- package/src/core/index.ts +2 -0
- package/src/core/internal.ts +107 -0
- package/src/core/types.ts +36 -0
- package/src/dom/_all.ts +54 -0
- package/src/dom/client.ts +4 -0
- package/src/dom/dispatcher.ts +318 -0
- package/src/dom/dom.ts +316 -0
- package/src/dom/event-replay.ts +55 -0
- package/src/dom/features/class/full.ts +104 -0
- package/src/dom/features/class/index.ts +1 -0
- package/src/dom/features/class/stub.ts +65 -0
- package/src/dom/features/context/full.ts +57 -0
- package/src/dom/features/context/index.ts +1 -0
- package/src/dom/features/context/stub.ts +32 -0
- package/src/dom/features/forward-ref/full.ts +54 -0
- package/src/dom/features/forward-ref/index.ts +1 -0
- package/src/dom/features/forward-ref/stub.ts +28 -0
- package/src/dom/features/hydration/full.ts +345 -0
- package/src/dom/features/hydration/index.ts +1 -0
- package/src/dom/features/hydration/stub.ts +72 -0
- package/src/dom/features/index.ts +11 -0
- package/src/dom/features/lazy/full.ts +98 -0
- package/src/dom/features/lazy/index.ts +1 -0
- package/src/dom/features/lazy/stub.ts +45 -0
- package/src/dom/features/memo/full.ts +74 -0
- package/src/dom/features/memo/index.ts +1 -0
- package/src/dom/features/memo/stub.ts +42 -0
- package/src/dom/features/portal/full.ts +22 -0
- package/src/dom/features/portal/index.ts +1 -0
- package/src/dom/features/portal/stub.ts +11 -0
- package/src/dom/features/suspense/full.ts +191 -0
- package/src/dom/features/suspense/index.ts +1 -0
- package/src/dom/features/suspense/stub.ts +12 -0
- package/src/dom/index.ts +33 -0
- package/src/dom/portal.ts +16 -0
- package/src/dom/reconcile.ts +1169 -0
- package/src/dom/root.ts +107 -0
- package/src/dom/test-utils.ts +6 -0
- package/src/react/children.ts +85 -0
- package/src/react/class.ts +56 -0
- package/src/react/context.ts +50 -0
- package/src/react/element.ts +80 -0
- package/src/react/hooks.ts +190 -0
- package/src/react/index.ts +132 -0
- package/src/react/jsx-runtime.ts +16 -0
- package/src/react/memo.ts +45 -0
- package/src/react/portal.ts +1 -0
- package/src/react/shared-internals.ts +79 -0
- package/src/react/suspense.ts +18 -0
- package/src/scheduler/index.ts +124 -0
- package/src/server/bootstrap-script.ts +52 -0
- package/src/server/dispatcher.ts +158 -0
- package/src/server/escape.ts +187 -0
- package/src/server/index.ts +26 -0
- package/src/server/renderToString.ts +33 -0
- package/src/server/stream.ts +302 -0
- package/src/server/walk.ts +448 -0
- package/src/vite/index.ts +401 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs'
|
|
2
|
+
import { dirname, resolve as resolvePath } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
|
|
5
|
+
export type RedactPreset = 'nano' | 'full'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Opt-in feature set. Each flag toggles whether the feature's real
|
|
9
|
+
* implementation ships (`true`) or is swapped with a stub module that
|
|
10
|
+
* degrades gracefully (`false`). Missing keys fall back to the preset's
|
|
11
|
+
* default. Adding a feature to this interface propagates to consumer
|
|
12
|
+
* configs as autocompleted options.
|
|
13
|
+
*/
|
|
14
|
+
export interface RedactFeatures {
|
|
15
|
+
/**
|
|
16
|
+
* `createPortal`. When `false`, portal elements render in place as a
|
|
17
|
+
* Fragment (the `container` prop is ignored). `renderPortal` and its
|
|
18
|
+
* deps are stripped from the bundle.
|
|
19
|
+
*/
|
|
20
|
+
portal?: boolean
|
|
21
|
+
/**
|
|
22
|
+
* `createContext` / `useContext` / `<Provider>` / `<Consumer>`. When
|
|
23
|
+
* `false`, Providers render as Fragments (value never propagates),
|
|
24
|
+
* Consumers invoke their function-children with the context's default
|
|
25
|
+
* value, and `useContext` returns the default. Provider-walk logic and
|
|
26
|
+
* `renderProvider` are stripped.
|
|
27
|
+
*/
|
|
28
|
+
context?: boolean
|
|
29
|
+
/**
|
|
30
|
+
* `<Suspense>` boundaries + streaming hydration. When `false`, Suspense
|
|
31
|
+
* elements render as Fragments (children mount inline, `fallback` is
|
|
32
|
+
* ignored). Thrown thenables still schedule a re-render on settle, so
|
|
33
|
+
* eventual consistency works — just no fallback UI during the pending
|
|
34
|
+
* window. Boundary-handler stack and hydration integration are stripped.
|
|
35
|
+
*/
|
|
36
|
+
suspense?: boolean
|
|
37
|
+
/**
|
|
38
|
+
* `React.memo`. When `false`, memoized components still render but without
|
|
39
|
+
* the prop-equality gate — every parent rerender passes through.
|
|
40
|
+
* `shallowEqual` and the force-rerender bypass are stripped.
|
|
41
|
+
*/
|
|
42
|
+
memo?: boolean
|
|
43
|
+
/**
|
|
44
|
+
* `React.forwardRef`. When `false`, forwardRef components still render but
|
|
45
|
+
* the ref prop isn't forwarded to the inner function. React 19+ treats
|
|
46
|
+
* refs as normal props on function components anyway, so most apps can
|
|
47
|
+
* drop this. The dispatcher save/restore machinery is stripped.
|
|
48
|
+
*/
|
|
49
|
+
forwardRef?: boolean
|
|
50
|
+
/**
|
|
51
|
+
* `React.lazy`. When `false`, lazy elements still resolve if their payload
|
|
52
|
+
* is already available synchronously (e.g. pre-awaited RSC Flight); async
|
|
53
|
+
* resolution throws a clear error. The hydration-deferred-reveal path and
|
|
54
|
+
* Suspense coordination are stripped.
|
|
55
|
+
*/
|
|
56
|
+
lazy?: boolean
|
|
57
|
+
/**
|
|
58
|
+
* Class components (`extends Component`). When `false`, class components
|
|
59
|
+
* still render but only honor the core contract: constructor + `render()`
|
|
60
|
+
* + `setState`. Dropped: `contextType`, `getDerivedStateFromProps`,
|
|
61
|
+
* `shouldComponentUpdate`, `componentDidMount`/`Update`/`WillUnmount`,
|
|
62
|
+
* `getDerivedStateFromError`/`componentDidCatch` (error boundaries).
|
|
63
|
+
*/
|
|
64
|
+
classComponents?: boolean
|
|
65
|
+
/**
|
|
66
|
+
* SSR hydration (`hydrateRoot`). When `false`, `hydrateRoot` throws
|
|
67
|
+
* (use `createRoot` for SPAs). The HydrationCursor / DOM adoption /
|
|
68
|
+
* streaming-boundary coordination / event-replay / scroll-guard
|
|
69
|
+
* machinery is stripped — the biggest single chunk of reducible code.
|
|
70
|
+
*/
|
|
71
|
+
hydration?: boolean
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface ResolvedFeatures {
|
|
75
|
+
portal: boolean
|
|
76
|
+
context: boolean
|
|
77
|
+
suspense: boolean
|
|
78
|
+
memo: boolean
|
|
79
|
+
forwardRef: boolean
|
|
80
|
+
lazy: boolean
|
|
81
|
+
classComponents: boolean
|
|
82
|
+
hydration: boolean
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const PRESET_DEFAULTS: Record<RedactPreset, ResolvedFeatures> = {
|
|
86
|
+
// Opt-in: everything off. Turn individual features on via `features`.
|
|
87
|
+
nano: {
|
|
88
|
+
portal: false, context: false, suspense: false, memo: false,
|
|
89
|
+
forwardRef: false, lazy: false, classComponents: false, hydration: false,
|
|
90
|
+
},
|
|
91
|
+
// Opt-out: everything on (drop-in React parity). Turn features off via `features`.
|
|
92
|
+
full: {
|
|
93
|
+
portal: true, context: true, suspense: true, memo: true,
|
|
94
|
+
forwardRef: true, lazy: true, classComponents: true, hydration: true,
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function resolveFeatures(
|
|
99
|
+
preset: RedactPreset,
|
|
100
|
+
overrides: RedactFeatures,
|
|
101
|
+
): ResolvedFeatures {
|
|
102
|
+
const p = PRESET_DEFAULTS[preset]
|
|
103
|
+
return {
|
|
104
|
+
portal: overrides.portal ?? p.portal,
|
|
105
|
+
context: overrides.context ?? p.context,
|
|
106
|
+
suspense: overrides.suspense ?? p.suspense,
|
|
107
|
+
memo: overrides.memo ?? p.memo,
|
|
108
|
+
forwardRef: overrides.forwardRef ?? p.forwardRef,
|
|
109
|
+
lazy: overrides.lazy ?? p.lazy,
|
|
110
|
+
classComponents: overrides.classComponents ?? p.classComponents,
|
|
111
|
+
hydration: overrides.hydration ?? p.hydration,
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface RedactOptions {
|
|
116
|
+
/** Skip aliasing specific specifiers, e.g. if a consumer wants real React somewhere. */
|
|
117
|
+
skip?: ReadonlyArray<string>
|
|
118
|
+
/**
|
|
119
|
+
* Override package resolution root. Defaults to the Vite config root. Useful
|
|
120
|
+
* for monorepos where the plugin lives in a different workspace than the
|
|
121
|
+
* consumer app.
|
|
122
|
+
*/
|
|
123
|
+
resolveFrom?: string
|
|
124
|
+
/**
|
|
125
|
+
* Explicit package roots, bypassing node_modules lookup. Keys are package
|
|
126
|
+
* names (e.g. `@tanstack/redact`), values are absolute paths to the package
|
|
127
|
+
* directory. Handy for cross-workspace testing / bring-your-own-build setups.
|
|
128
|
+
*/
|
|
129
|
+
packageRoots?: Record<string, string>
|
|
130
|
+
/**
|
|
131
|
+
* Starting point for feature selection. `'full'` (default) turns every
|
|
132
|
+
* feature on — drop-in React parity, opt-out individual features via
|
|
133
|
+
* `features`. `'nano'` turns everything off — opt in to what you need.
|
|
134
|
+
*/
|
|
135
|
+
preset?: RedactPreset
|
|
136
|
+
/**
|
|
137
|
+
* Per-feature overrides merged on top of the preset's defaults. Enables
|
|
138
|
+
* fine-grained "preset minus X" or "preset plus Y" configurations.
|
|
139
|
+
*/
|
|
140
|
+
features?: RedactFeatures
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Alias map. ORDER MATTERS — Vite's alias matcher uses first-match against
|
|
144
|
+
// prefix, so more-specific specifiers MUST come before less-specific ones.
|
|
145
|
+
// Without this, `react-dom/server` would prefix-match `react-dom` first and
|
|
146
|
+
// resolve to `@tanstack/redact/dom/server` (wrong) instead of
|
|
147
|
+
// `@tanstack/redact/server`.
|
|
148
|
+
//
|
|
149
|
+
// `use-sync-external-store` aliases are here because its CJS-only React 17
|
|
150
|
+
// compat shim does `var React = require('react')`. That survives Vite's
|
|
151
|
+
// pre-bundling intact and explodes in Cloudflare Workers (no `require`).
|
|
152
|
+
// Modern React has `useSyncExternalStore` built-in, and `@tanstack/redact`
|
|
153
|
+
// additionally exports `useSyncExternalStoreWithSelector` so this alias
|
|
154
|
+
// is safe everywhere.
|
|
155
|
+
const ALIASES: Record<string, string> = {
|
|
156
|
+
// ---- most-specific first ----
|
|
157
|
+
'use-sync-external-store/shim/with-selector': '@tanstack/redact',
|
|
158
|
+
'use-sync-external-store/shim/with-selector.js': '@tanstack/redact',
|
|
159
|
+
'use-sync-external-store/with-selector': '@tanstack/redact',
|
|
160
|
+
'use-sync-external-store/with-selector.js': '@tanstack/redact',
|
|
161
|
+
'use-sync-external-store/shim': '@tanstack/redact',
|
|
162
|
+
'use-sync-external-store': '@tanstack/redact',
|
|
163
|
+
|
|
164
|
+
// React drop-in shim targets. Subpaths first.
|
|
165
|
+
'react/jsx-runtime': '@tanstack/redact/jsx-runtime',
|
|
166
|
+
'react/jsx-dev-runtime': '@tanstack/redact/jsx-dev-runtime',
|
|
167
|
+
'react-dom/client': '@tanstack/redact/dom-client',
|
|
168
|
+
'react-dom/server': '@tanstack/redact/server',
|
|
169
|
+
'react-dom/test-utils': '@tanstack/redact/dom-test-utils',
|
|
170
|
+
'react-dom': '@tanstack/redact/dom',
|
|
171
|
+
react: '@tanstack/redact',
|
|
172
|
+
scheduler: '@tanstack/redact/scheduler',
|
|
173
|
+
|
|
174
|
+
// Self-aliases so Vite resolves `@tanstack/redact/*` imports to the same
|
|
175
|
+
// canonical file path no matter where they originate (worker bundle vs
|
|
176
|
+
// deps_ssr pre-bundle vs source). Without these, Cloudflare's
|
|
177
|
+
// `noExternal: true` worker config inlines one copy while Vite's
|
|
178
|
+
// optimizeDeps pre-bundles another, ending up with two separate
|
|
179
|
+
// ReactSharedInternals instances and a null dispatcher in user hooks.
|
|
180
|
+
// Subpaths first here too.
|
|
181
|
+
'@tanstack/redact/jsx-runtime': '@tanstack/redact/jsx-runtime',
|
|
182
|
+
'@tanstack/redact/jsx-dev-runtime': '@tanstack/redact/jsx-dev-runtime',
|
|
183
|
+
'@tanstack/redact/dom-client': '@tanstack/redact/dom-client',
|
|
184
|
+
'@tanstack/redact/dom-test-utils': '@tanstack/redact/dom-test-utils',
|
|
185
|
+
'@tanstack/redact/server': '@tanstack/redact/server',
|
|
186
|
+
'@tanstack/redact/scheduler': '@tanstack/redact/scheduler',
|
|
187
|
+
'@tanstack/redact/dom': '@tanstack/redact/dom',
|
|
188
|
+
'@tanstack/redact': '@tanstack/redact',
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function splitSpecifier(specifier: string): { pkg: string; sub: string } {
|
|
192
|
+
if (specifier.startsWith('@')) {
|
|
193
|
+
const slash1 = specifier.indexOf('/')
|
|
194
|
+
const slash2 = specifier.indexOf('/', slash1 + 1)
|
|
195
|
+
if (slash2 < 0) return { pkg: specifier, sub: '' }
|
|
196
|
+
return { pkg: specifier.slice(0, slash2), sub: specifier.slice(slash2 + 1) }
|
|
197
|
+
}
|
|
198
|
+
const slash = specifier.indexOf('/')
|
|
199
|
+
if (slash < 0) return { pkg: specifier, sub: '' }
|
|
200
|
+
return { pkg: specifier.slice(0, slash), sub: specifier.slice(slash + 1) }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function findPackageDir(pkg: string, fromDir: string): string | null {
|
|
204
|
+
let dir = fromDir
|
|
205
|
+
while (true) {
|
|
206
|
+
const candidate = resolvePath(dir, 'node_modules', pkg)
|
|
207
|
+
if (existsSync(resolvePath(candidate, 'package.json'))) return candidate
|
|
208
|
+
const parent = dirname(dir)
|
|
209
|
+
if (parent === dir) return null
|
|
210
|
+
dir = parent
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function resolveExport(packageDir: string, sub: string): string | null {
|
|
215
|
+
const pkgJsonPath = resolvePath(packageDir, 'package.json')
|
|
216
|
+
let pkg: any
|
|
217
|
+
try {
|
|
218
|
+
pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))
|
|
219
|
+
} catch {
|
|
220
|
+
return null
|
|
221
|
+
}
|
|
222
|
+
const key = sub ? './' + sub : '.'
|
|
223
|
+
const exp = pkg.exports?.[key]
|
|
224
|
+
// Prefer published `import` (dist/.js) over `source` — dist is a single
|
|
225
|
+
// transformed bundle so Vite's dep optimizer doesn't thrash on dozens of
|
|
226
|
+
// individual source files. The package keeps cross-subpath imports
|
|
227
|
+
// external, so there's still only one runtime instance.
|
|
228
|
+
const pick = (v: any): string | null => {
|
|
229
|
+
if (typeof v === 'string') return v
|
|
230
|
+
if (v && typeof v === 'object') {
|
|
231
|
+
return pick(v.import ?? v.module ?? v.source ?? v.default ?? null)
|
|
232
|
+
}
|
|
233
|
+
return null
|
|
234
|
+
}
|
|
235
|
+
const target = pick(exp)
|
|
236
|
+
if (target) return resolvePath(packageDir, target)
|
|
237
|
+
if (!sub) {
|
|
238
|
+
const main = pkg.module ?? pkg.main
|
|
239
|
+
if (typeof main === 'string') return resolvePath(packageDir, main)
|
|
240
|
+
}
|
|
241
|
+
return null
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// When installed from npm, `@tanstack/redact` is declared as a `dependency`
|
|
245
|
+
// of consumer apps. Under pnpm's strict mode it ends up nested under the
|
|
246
|
+
// plugin's own `.pnpm/@tanstack+redact@.../node_modules/` rather than
|
|
247
|
+
// hoisted to the consumer's root, so a `findPackageDir` walk starting at
|
|
248
|
+
// the Vite project root won't always find it. Search from the plugin's own
|
|
249
|
+
// directory first (which walks into its nested node_modules), then fall
|
|
250
|
+
// back to the consumer root for hoisted installs.
|
|
251
|
+
const pluginDir = dirname(fileURLToPath(import.meta.url))
|
|
252
|
+
|
|
253
|
+
function resolveSpecifier(
|
|
254
|
+
specifier: string,
|
|
255
|
+
fromDir: string,
|
|
256
|
+
packageRoots: Record<string, string>,
|
|
257
|
+
): string | null {
|
|
258
|
+
const { pkg, sub } = splitSpecifier(specifier)
|
|
259
|
+
const packageDir =
|
|
260
|
+
packageRoots[pkg] ??
|
|
261
|
+
findPackageDir(pkg, pluginDir) ??
|
|
262
|
+
findPackageDir(pkg, fromDir)
|
|
263
|
+
if (!packageDir) return null
|
|
264
|
+
const target = resolveExport(packageDir, sub)
|
|
265
|
+
if (!target) return null
|
|
266
|
+
// Canonicalize through pnpm symlinks. Under strict pnpm, the package may
|
|
267
|
+
// live nested under `.pnpm/@tanstack+redact@.../node_modules/*`, but each
|
|
268
|
+
// of those is itself a symlink to the flat `.pnpm/@tanstack+redact@.../`
|
|
269
|
+
// entry. Vite's `fetchModule` (used by TanStack Start's server-fn
|
|
270
|
+
// compiler) follows the realpath, so the id seen by the capture-transform
|
|
271
|
+
// differs from the nested id we'd return. That leaves the compiler's
|
|
272
|
+
// moduleCache keyed on the realpath while `getModuleInfo` looks up the
|
|
273
|
+
// nested path → miss → "could not load module info". Returning the
|
|
274
|
+
// canonical realpath here keeps the two sides in agreement.
|
|
275
|
+
try {
|
|
276
|
+
return realpathSync(target)
|
|
277
|
+
} catch {
|
|
278
|
+
return target
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function redact(options: RedactOptions = {}): any {
|
|
283
|
+
const skip = new Set(options.skip ?? [])
|
|
284
|
+
const entries = Object.entries(ALIASES).filter(([k]) => !skip.has(k))
|
|
285
|
+
const features = resolveFeatures(options.preset ?? 'full', options.features ?? {})
|
|
286
|
+
|
|
287
|
+
const resolvedMap: Record<string, string> = {}
|
|
288
|
+
let done = false
|
|
289
|
+
|
|
290
|
+
function resolveAll(root: string): void {
|
|
291
|
+
if (done) return
|
|
292
|
+
const fromDir = options.resolveFrom ?? root
|
|
293
|
+
const packageRoots = options.packageRoots ?? {}
|
|
294
|
+
for (const [from, to] of entries) {
|
|
295
|
+
const resolved = resolveSpecifier(to, fromDir, packageRoots)
|
|
296
|
+
if (resolved) resolvedMap[from] = resolved
|
|
297
|
+
}
|
|
298
|
+
done = true
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
name: 'redact',
|
|
303
|
+
enforce: 'pre',
|
|
304
|
+
|
|
305
|
+
config() {
|
|
306
|
+
const excludeList = entries.map(([k]) => k)
|
|
307
|
+
// Single package — only one name to dedupe / no-external.
|
|
308
|
+
const noExt = ['@tanstack/redact']
|
|
309
|
+
// Top-level resolve.alias so `react` → `@tanstack/redact` happens
|
|
310
|
+
// BEFORE any plugin-based resolveId hook fires. The Cloudflare
|
|
311
|
+
// vite-plugin's rolldown worker-runner pre-scans the worker entry's
|
|
312
|
+
// exports and resolves bare specifiers via Vite's alias map directly
|
|
313
|
+
// (not via plugin hooks), so without this it would resolve `react` to
|
|
314
|
+
// the real npm package and try to `require()` it in a Worker (no CJS
|
|
315
|
+
// support). Object form is required — array form is silently ignored
|
|
316
|
+
// by rolldown's worker-runner.
|
|
317
|
+
const aliasMap = Object.fromEntries(entries.filter(([from, to]) => from !== to))
|
|
318
|
+
// Scope optimizeDeps to client + ssr environments ONLY. Do NOT set a
|
|
319
|
+
// top-level optimizeDeps — in Vite 6+ that's effectively the client
|
|
320
|
+
// env's default but also seeps into the rsc env's `'use client'`
|
|
321
|
+
// analysis, causing flood warnings like "inconsistently optimized".
|
|
322
|
+
// Dedupe `@tanstack/redact` so Vite resolves it to a single instance
|
|
323
|
+
// even when multiple packages (e.g. @tanstack/react-router and user
|
|
324
|
+
// code) drag it into different parts of the module graph.
|
|
325
|
+
const dedupe = noExt
|
|
326
|
+
return {
|
|
327
|
+
resolve: {
|
|
328
|
+
alias: aliasMap,
|
|
329
|
+
dedupe,
|
|
330
|
+
},
|
|
331
|
+
environments: {
|
|
332
|
+
client: {
|
|
333
|
+
optimizeDeps: { exclude: excludeList },
|
|
334
|
+
},
|
|
335
|
+
ssr: {
|
|
336
|
+
optimizeDeps: { exclude: excludeList },
|
|
337
|
+
resolve: { noExternal: noExt },
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
ssr: { noExternal: noExt },
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
configResolved(config: any) {
|
|
345
|
+
resolveAll(config.root)
|
|
346
|
+
// With `packageRoots`, package sources live outside the consumer's Vite
|
|
347
|
+
// project root, so the default server.fs.allow list blocks them. Append
|
|
348
|
+
// to the resolved allow list rather than replacing via `config()`, so we
|
|
349
|
+
// keep Vite's defaults (root + node_modules + client runtime).
|
|
350
|
+
const fsAllow = Object.values(options.packageRoots ?? {})
|
|
351
|
+
if (fsAllow.length && config.server?.fs?.allow) {
|
|
352
|
+
for (const p of fsAllow) {
|
|
353
|
+
if (!config.server.fs.allow.includes(p)) {
|
|
354
|
+
config.server.fs.allow.push(p)
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
async resolveId(this: any, id: string, importer?: string, opts?: any) {
|
|
361
|
+
// Skip the RSC environment — it relies on real React internals via
|
|
362
|
+
// @vitejs/plugin-rsc's vendored react-server-dom. Substituting our
|
|
363
|
+
// shim there breaks Flight serialization. Client + SSR envs still swap.
|
|
364
|
+
const envName = this?.environment?.name
|
|
365
|
+
if (envName === 'rsc') return null
|
|
366
|
+
|
|
367
|
+
// Feature-flag swap: when the reconciler's `features/index` module
|
|
368
|
+
// imports a feature by relative path, redirect to that feature's stub
|
|
369
|
+
// if the flag is off. The stub registers a graceful-degradation
|
|
370
|
+
// matcher (e.g. Portal → Fragment) so user code keeps working.
|
|
371
|
+
if (importer && /[\\/]features[\\/]index\.[jt]sx?$/.test(importer)) {
|
|
372
|
+
const m = id.match(/^\.\/([a-z-]+)$/)
|
|
373
|
+
if (m) {
|
|
374
|
+
const name = m[1] as keyof ResolvedFeatures
|
|
375
|
+
if (name in features && !features[name]) {
|
|
376
|
+
const r = await this.resolve(`./${name}/stub`, importer, {
|
|
377
|
+
...opts,
|
|
378
|
+
skipSelf: true,
|
|
379
|
+
})
|
|
380
|
+
if (r) return r.id
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Hydration swap: hydration isn't self-registering, so it's imported
|
|
386
|
+
// from reconcile.ts, root.ts, and the Suspense/Lazy feature modules.
|
|
387
|
+
// Any specifier ending in `/hydration` that resolves to our feature
|
|
388
|
+
// module gets redirected to the stub when the flag is off.
|
|
389
|
+
if (!features.hydration && importer && /[\\/]hydration$/.test(id)) {
|
|
390
|
+
const r = await this.resolve(id, importer, { ...opts, skipSelf: true })
|
|
391
|
+
if (r && /features[\\/]hydration[\\/]index\.(ts|js)$/.test(r.id)) {
|
|
392
|
+
return r.id.replace(/index\.(ts|js)$/, 'stub.$1')
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return resolvedMap[id] ?? null
|
|
397
|
+
},
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export default redact
|