@pracht/vite-plugin 0.11.0 → 0.11.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/package.json +8 -4
- package/virtual.d.ts +255 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pracht/vite-plugin",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Vite plugin for Pracht apps with virtual modules, dev SSR, prerendering, route inspection, and multi-adapter builds.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pracht",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"directory": "packages/vite-plugin"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
|
-
"dist"
|
|
28
|
+
"dist",
|
|
29
|
+
"virtual.d.ts"
|
|
29
30
|
],
|
|
30
31
|
"type": "module",
|
|
31
32
|
"exports": {
|
|
@@ -36,6 +37,9 @@
|
|
|
36
37
|
"./pages-router": {
|
|
37
38
|
"types": "./dist/pages-router.d.mts",
|
|
38
39
|
"default": "./dist/pages-router.mjs"
|
|
40
|
+
},
|
|
41
|
+
"./virtual": {
|
|
42
|
+
"types": "./virtual.d.ts"
|
|
39
43
|
}
|
|
40
44
|
},
|
|
41
45
|
"publishConfig": {
|
|
@@ -48,8 +52,8 @@
|
|
|
48
52
|
"es-module-lexer": "^1.7.0",
|
|
49
53
|
"@pracht/adapter-node": "0.4.2",
|
|
50
54
|
"@pracht/capabilities": "0.3.0",
|
|
51
|
-
"@pracht/
|
|
52
|
-
"@pracht/
|
|
55
|
+
"@pracht/core": "0.16.0",
|
|
56
|
+
"@pracht/preact-ssr-precompile": "0.1.3"
|
|
53
57
|
},
|
|
54
58
|
"peerDependencies": {
|
|
55
59
|
"vite": "^8.0.0"
|
package/virtual.d.ts
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
declare module "virtual:pracht/server" {
|
|
2
|
+
const mod: { fetch: (request: Request, env: any, ctx: any) => Promise<Response> };
|
|
3
|
+
export default mod;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
declare module "virtual:pracht/client" {}
|
|
7
|
+
|
|
8
|
+
declare module "virtual:pracht/capabilities" {
|
|
9
|
+
import type {
|
|
10
|
+
CapabilityBrowserCallOptions,
|
|
11
|
+
CapabilityCallOptionsFor,
|
|
12
|
+
CapabilityInputArgs,
|
|
13
|
+
CapabilityInputFor,
|
|
14
|
+
CapabilityOutputFor,
|
|
15
|
+
HasRegisteredCapabilities,
|
|
16
|
+
HttpCapabilityName,
|
|
17
|
+
NonDestructiveCapabilityName,
|
|
18
|
+
Register,
|
|
19
|
+
} from "@pracht/core";
|
|
20
|
+
import type {
|
|
21
|
+
CapabilityEffect,
|
|
22
|
+
CapabilityEnvelope,
|
|
23
|
+
CapabilityErrorPayload,
|
|
24
|
+
CapabilityIssue,
|
|
25
|
+
} from "@pracht/capabilities";
|
|
26
|
+
|
|
27
|
+
// The envelope types are the protocol package's — re-exported so existing
|
|
28
|
+
// `import type { ... } from "virtual:pracht/capabilities"` keeps working.
|
|
29
|
+
export type { CapabilityEnvelope, CapabilityErrorPayload, CapabilityIssue };
|
|
30
|
+
|
|
31
|
+
export interface CallCapabilityOptions extends CapabilityBrowserCallOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Confirmation token for committing a destructive capability, taken from
|
|
34
|
+
* the prior call's `confirmation_required` error envelope. Sets the
|
|
35
|
+
* confirmation header for you. A destructive call must either prepare with
|
|
36
|
+
* `{ prepare: true }` or commit with this token once `pracht typegen` has
|
|
37
|
+
* registered its effect class.
|
|
38
|
+
*/
|
|
39
|
+
confirm?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Start the prepare half of a destructive call. The server returns a
|
|
42
|
+
* `confirmation_required` envelope containing the token; repeat the call
|
|
43
|
+
* with `confirm` to commit. Typed destructive calls require exactly one of
|
|
44
|
+
* `prepare: true` or `confirm`.
|
|
45
|
+
*/
|
|
46
|
+
prepare?: true;
|
|
47
|
+
/**
|
|
48
|
+
* Successful non-`read` calls revalidate the active route's data
|
|
49
|
+
* automatically; pass `false` to skip it for this call.
|
|
50
|
+
*/
|
|
51
|
+
revalidate?: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Destructive calls require exactly one of `{ prepare: true }` or
|
|
56
|
+
* `{ confirm }`. `prepare` is not sent over the wire; the dispatcher uses it
|
|
57
|
+
* only to remove any confirmation token inherited through caller-supplied
|
|
58
|
+
* headers. The server is what refuses to run the unconfirmed call.
|
|
59
|
+
*/
|
|
60
|
+
type OptionsFor<TName extends string> = CapabilityCallOptionsFor<TName, CallCapabilityOptions>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* HTTP endpoints of http-exposed capabilities, keyed by capability name.
|
|
64
|
+
*
|
|
65
|
+
* Has a **null prototype**, so a capability named `toString` cannot shadow an
|
|
66
|
+
* inherited member during lookup. Index it and enumerate it as usual, but
|
|
67
|
+
* reach for `Object.hasOwn(capabilityEndpoints, name)` rather than
|
|
68
|
+
* `capabilityEndpoints.hasOwnProperty(name)` — there is no `Object.prototype`
|
|
69
|
+
* to inherit that from. TypeScript cannot express the missing prototype, so
|
|
70
|
+
* the `Record` type below overstates what is available.
|
|
71
|
+
*/
|
|
72
|
+
export const capabilityEndpoints: Record<
|
|
73
|
+
string,
|
|
74
|
+
{ method: string; path: string; effect: CapabilityEffect | null }
|
|
75
|
+
>;
|
|
76
|
+
|
|
77
|
+
interface TypedCallCapability {
|
|
78
|
+
/**
|
|
79
|
+
* Names that cannot be `destructive`. Listed first and with an optional
|
|
80
|
+
* options argument, so it is always arity-compatible with a one- or
|
|
81
|
+
* two-argument call — which makes it the signature that reports what is
|
|
82
|
+
* wrong with an unresolvable name, instead of an argument count.
|
|
83
|
+
*/
|
|
84
|
+
<TName extends NonDestructiveCapabilityName>(
|
|
85
|
+
name: TName,
|
|
86
|
+
...args: CapabilityInputArgs<TName, CallCapabilityOptions>
|
|
87
|
+
): Promise<CapabilityEnvelope<CapabilityOutputFor<TName>>>;
|
|
88
|
+
/** Possibly `destructive`: the prepare marker or the token is required. */
|
|
89
|
+
<TName extends HttpCapabilityName>(
|
|
90
|
+
name: TName,
|
|
91
|
+
input: CapabilityInputFor<TName>,
|
|
92
|
+
options: OptionsFor<TName>,
|
|
93
|
+
): Promise<CapabilityEnvelope<CapabilityOutputFor<TName>>>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface UntypedCallCapability {
|
|
97
|
+
<T = unknown>(
|
|
98
|
+
name: string,
|
|
99
|
+
input?: unknown,
|
|
100
|
+
opts?: CallCapabilityOptions,
|
|
101
|
+
): Promise<CapabilityEnvelope<T>>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Invoke an http-exposed capability from the browser via its HTTP projection.
|
|
106
|
+
* Once `pracht typegen` has registered the capability graph on
|
|
107
|
+
* `Register["capabilities"]`, the name, input, output, and confirmation
|
|
108
|
+
* requirement all come from the registration: a private capability, an
|
|
109
|
+
* unknown name, a mismatched input, or a `destructive` call without an
|
|
110
|
+
* explicit prepare/commit choice are compile errors rather than runtime
|
|
111
|
+
* envelopes.
|
|
112
|
+
*
|
|
113
|
+
* Declared as a conditionally-typed value rather than as an overload pair
|
|
114
|
+
* whose fallback `name` resolves to `never`. That fallback survived overload
|
|
115
|
+
* resolution and absorbed anything arity filtering rejected, so every
|
|
116
|
+
* mistake — including a `destructive` call that merely forgot its options —
|
|
117
|
+
* came back as `'"notes.purge"' is not assignable to 'never'`: blaming the
|
|
118
|
+
* name, never naming the cause. Here the untyped form is simply absent for a
|
|
119
|
+
* registered app, and the two typed signatures split by effect class so that
|
|
120
|
+
* an unresolvable name is always arity-compatible with the first one and gets
|
|
121
|
+
* reported as a name.
|
|
122
|
+
*
|
|
123
|
+
* A dynamic name is no longer accepted once typegen has run; assert it with
|
|
124
|
+
* `name as HttpCapabilityName` when the name genuinely comes from data, and
|
|
125
|
+
* keep in mind the runtime still answers an unknown one with
|
|
126
|
+
* `unknown_capability`.
|
|
127
|
+
*/
|
|
128
|
+
export const callCapability: HasRegisteredCapabilities extends true
|
|
129
|
+
? TypedCallCapability
|
|
130
|
+
: UntypedCallCapability;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The same calls as `callCapability`, reached as a nested object built from
|
|
134
|
+
* the dotted capability names — `capabilities.notes.search({ query })`.
|
|
135
|
+
* Private capabilities are simply absent from it. Because the members are
|
|
136
|
+
* real property accesses, a typo here reports as "Property 'serach' does not
|
|
137
|
+
* exist … Did you mean 'search'?" — which `callCapability("notes.serach")`
|
|
138
|
+
* cannot do, since a string literal argument has no such suggestion.
|
|
139
|
+
*
|
|
140
|
+
* Current typegen output declares the nested client explicitly, so each leaf
|
|
141
|
+
* carries the capability's title and description as JSDoc. The mapped type
|
|
142
|
+
* below remains the compatibility fallback for older generated files.
|
|
143
|
+
*
|
|
144
|
+
* Identical runtime path to `callCapability` (same endpoint table, same
|
|
145
|
+
* settled event, same revalidation), so nothing forks between the two.
|
|
146
|
+
*/
|
|
147
|
+
export const capabilities: PrachtCapabilityClient;
|
|
148
|
+
|
|
149
|
+
type GeneratedCapabilityClient = Register extends { capabilityClient: infer TClient }
|
|
150
|
+
? TClient
|
|
151
|
+
: never;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Dotted names expanded into nested namespaces, http-exposed only. Current
|
|
155
|
+
* typegen output supplies the explicit client (including JSDoc); older
|
|
156
|
+
* generated files use the mapped fallback. Before typegen has run, every
|
|
157
|
+
* segment stays callable with unknown input/output.
|
|
158
|
+
*/
|
|
159
|
+
export type PrachtCapabilityClient = HasRegisteredCapabilities extends true
|
|
160
|
+
? [GeneratedCapabilityClient] extends [never]
|
|
161
|
+
? CapabilityClientNode<HttpCapabilityName>
|
|
162
|
+
: GeneratedCapabilityClient
|
|
163
|
+
: Record<string, UntypedCapabilityClientNode>;
|
|
164
|
+
|
|
165
|
+
interface UntypedCapabilityClientNode {
|
|
166
|
+
<T = unknown>(input?: unknown, opts?: CallCapabilityOptions): Promise<CapabilityEnvelope<T>>;
|
|
167
|
+
[segment: string]: UntypedCapabilityClientNode;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
type CapabilityMethod<TName extends string> = (
|
|
171
|
+
...args: CapabilityInputArgs<TName, OptionsFor<TName>>
|
|
172
|
+
) => Promise<CapabilityEnvelope<CapabilityOutputFor<TName>>>;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* `Prefix` carries the already-consumed path so a leaf can look its own full
|
|
176
|
+
* dotted name back up in the flat registration map.
|
|
177
|
+
*/
|
|
178
|
+
type CapabilitySegment<
|
|
179
|
+
TAll extends string,
|
|
180
|
+
TPrefix extends string,
|
|
181
|
+
> = TAll extends `${TPrefix}${infer TRest}`
|
|
182
|
+
? TRest extends `${infer THead}.${string}`
|
|
183
|
+
? THead
|
|
184
|
+
: TRest
|
|
185
|
+
: never;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* A name that is also a prefix of another (`notes` alongside `notes.search`)
|
|
189
|
+
* cannot be both a function and a namespace. The runtime builder resolves
|
|
190
|
+
* that by letting the namespace win, so the type must too — otherwise
|
|
191
|
+
* `capabilities.notes(...)` would typecheck and throw at runtime. The
|
|
192
|
+
* shadowed name stays callable through `callCapability()`, and
|
|
193
|
+
* `pracht verify` warns about it.
|
|
194
|
+
*/
|
|
195
|
+
type CapabilityClientNode<TAll extends string, TPrefix extends string = ""> = {
|
|
196
|
+
[TSeg in CapabilitySegment<TAll, TPrefix>]: [
|
|
197
|
+
Extract<TAll, `${TPrefix}${TSeg}.${string}`>,
|
|
198
|
+
] extends [never]
|
|
199
|
+
? CapabilityMethod<`${TPrefix}${TSeg}`>
|
|
200
|
+
: CapabilityClientNode<TAll, `${TPrefix}${TSeg}.`>;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Call state for a user-triggered capability call — a button, a search box, a
|
|
205
|
+
* picker. `call()` takes the same arguments as `callCapability` minus the
|
|
206
|
+
* name, and resolves to the same envelope.
|
|
207
|
+
*
|
|
208
|
+
* This is a mutation-shaped hook, not a fetch-on-render one: it dispatches
|
|
209
|
+
* when you call it, never during render. For data a page needs on load, run
|
|
210
|
+
* the capability in a `loader` with `invokeCapability()` — that result is
|
|
211
|
+
* server-rendered into the HTML and revalidates automatically after
|
|
212
|
+
* non-`read` calls, which a render-time fetch cannot do.
|
|
213
|
+
*
|
|
214
|
+
* ```tsx
|
|
215
|
+
* const search = useCapability("notes.search");
|
|
216
|
+
* await search.call({ query });
|
|
217
|
+
* // search.data / search.error / search.pending / search.reset()
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* Concurrent calls are last-one-wins: an earlier response that arrives after
|
|
221
|
+
* a later one is discarded, so typing into a search box cannot show a stale
|
|
222
|
+
* result. `data` stays visible while a follow-up call is `pending`.
|
|
223
|
+
* It also remains the most recent successful result when that follow-up fails;
|
|
224
|
+
* only `reset()` or changing the capability name clears it.
|
|
225
|
+
*/
|
|
226
|
+
export function useCapability<TName extends HttpCapabilityName>(
|
|
227
|
+
name: TName,
|
|
228
|
+
): PrachtCapabilityHook<TName>;
|
|
229
|
+
|
|
230
|
+
export interface PrachtCapabilityHook<TName extends HttpCapabilityName> {
|
|
231
|
+
call: (
|
|
232
|
+
...args: CapabilityInputArgs<TName, OptionsFor<TName>>
|
|
233
|
+
) => Promise<CapabilityEnvelope<CapabilityOutputFor<TName>>>;
|
|
234
|
+
/** Data from the most recent successful call, until `reset()`. */
|
|
235
|
+
data: CapabilityOutputFor<TName> | undefined;
|
|
236
|
+
/** Error payload from the most recent failed call, until `reset()`. */
|
|
237
|
+
error: CapabilityErrorPayload | undefined;
|
|
238
|
+
/** Whether a call is in flight. */
|
|
239
|
+
pending: boolean;
|
|
240
|
+
/** Clear `data`/`error`/`pending` and abandon any in-flight result. */
|
|
241
|
+
reset: () => void;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
declare module "virtual:pracht/webmcp" {
|
|
246
|
+
/** Registers WebMCP page tools; returns false when the API is unavailable. */
|
|
247
|
+
export function registerPrachtWebmcpTools(): boolean;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Preserve the ambient declaration shipped with Pracht's compatibility-level
|
|
251
|
+
// `.tsrx` discovery. Other custom formats provide their own declaration.
|
|
252
|
+
declare module "*.tsrx" {
|
|
253
|
+
const mod: Record<string, unknown>;
|
|
254
|
+
export = mod;
|
|
255
|
+
}
|