@solidjs/web 2.0.0-beta.20 → 2.0.0-beta.22

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.
@@ -23,6 +23,32 @@ export class ResponseEnvelope<T = unknown> {
23
23
  */
24
24
  export function isResponseEnvelope(value: unknown): value is ResponseEnvelope;
25
25
 
26
+ /**
27
+ * Registered-symbol brand (`Symbol.for("solid.Href")`) marking URL-bearing
28
+ * values. Declared `unique symbol` type-side; the runtime value is the
29
+ * registered symbol, so separately bundled copies agree on identity.
30
+ */
31
+ export declare const HREF: unique symbol;
32
+
33
+ /**
34
+ * A URL-bearing value: coerces to its URL via `toString()` and carries the
35
+ * `HREF` registered-symbol brand. Integrations mint these (e.g. a router's
36
+ * typed path objects answer the brand from their proxy) and URL-accepting
37
+ * APIs like `redirect()` accept them alongside plain strings. The brand is
38
+ * what makes the type meaningful — every object has `toString()`.
39
+ */
40
+ export interface Href {
41
+ [HREF]: true;
42
+ toString(): string;
43
+ }
44
+
45
+ /**
46
+ * Whether `value` is an `Href`-branded URL-bearing value. Registered-symbol
47
+ * check, so it stays correct across duplicated module instances — same
48
+ * rationale as `isResponseEnvelope`.
49
+ */
50
+ export function isHref(value: unknown): value is Href;
51
+
26
52
  /** `ResponseInit` accepted by the response helpers, plus `revalidate`. */
27
53
  export interface ResponseHelperInit extends ResponseInit {
28
54
  /**
@@ -51,7 +77,7 @@ export interface ResponseHelperInit extends ResponseInit {
51
77
  * }
52
78
  * ```
53
79
  */
54
- export function redirect(url: string, init?: number | ResponseHelperInit): Response;
80
+ export function redirect(url: string | Href, init?: number | ResponseHelperInit): Response;
55
81
 
56
82
  /**
57
83
  * Empty response requesting revalidation of the named cache keys — all of
@@ -1,6 +1,51 @@
1
1
  import { JSONCodecOptions } from "../serializer.cjs";
2
+ import { ServerFunction, ServerFunctionMetadata } from "./shared.cjs";
2
3
 
3
- export { FUNCTION_HEADER, INSTANCE_HEADER, decodeResponse } from "./shared.cjs";
4
+ export {
5
+ ERROR_HEADER,
6
+ FUNCTION_HEADER,
7
+ INSTANCE_HEADER,
8
+ SINGLE_FLIGHT_HEADER,
9
+ decodeErrorHeaderValue,
10
+ decodeResponse,
11
+ encodeErrorHeaderValue,
12
+ getServerFunctionMetadata,
13
+ isServerFunction,
14
+ subscribeFlightData,
15
+ withMeta
16
+ } from "./shared.cjs";
17
+ export type {
18
+ FlightDataConsumer,
19
+ FlightDataContext,
20
+ ServerFunction,
21
+ ServerFunctionMetadata,
22
+ SingleFlightPayload
23
+ } from "./shared.cjs";
24
+
25
+ /** The context `prepareRequest` receives alongside the outgoing RequestInit. */
26
+ export interface PrepareRequestContext {
27
+ /** The build-stable id of the function being called. */
28
+ id: string;
29
+ /**
30
+ * The reference's declaration metadata (e.g. `method: "GET"` for
31
+ * `GET(fn)` references). Plain references carry an empty object.
32
+ */
33
+ meta: ServerFunctionMetadata | undefined;
34
+ }
35
+
36
+ /**
37
+ * Client-side session-dynamic transport hook: runs before every
38
+ * server-function fetch. Return (or mutate and return) the RequestInit the
39
+ * transport will use — the hook sees the final init, transport headers
40
+ * included. The motivating case is dynamic credentials that rotate during
41
+ * a session and apply uniformly to every call (OAuth bearer tokens); it is
42
+ * the client-side symmetric of the server handler hooks. Single hook, not
43
+ * a chain — compose by wrapping functions in userland.
44
+ */
45
+ export type PrepareRequestHook = (
46
+ init: RequestInit,
47
+ context: PrepareRequestContext
48
+ ) => RequestInit | Promise<RequestInit>;
4
49
 
5
50
  /** Options for `configureServerFunctionsClient`. */
6
51
  export interface ServerFunctionsClientConfig {
@@ -18,40 +63,80 @@ export interface ServerFunctionsClientConfig {
18
63
  * `decodeResponse` sees them too.
19
64
  */
20
65
  codec?: JSONCodecOptions;
66
+ /**
67
+ * Runs before every server-function fetch. Return (or mutate and return)
68
+ * the RequestInit the transport will use; `context.meta` is the
69
+ * reference's declaration metadata (e.g. method). For session-dynamic
70
+ * cross-cutting concerns — bearer tokens, tracing headers:
71
+ *
72
+ * ```ts
73
+ * configureServerFunctionsClient({
74
+ * prepareRequest(init) {
75
+ * return {
76
+ * ...init,
77
+ * headers: { ...init.headers, Authorization: `Bearer ${session.token()}` }
78
+ * };
79
+ * }
80
+ * });
81
+ * ```
82
+ */
83
+ prepareRequest?: PrepareRequestHook;
21
84
  }
22
85
 
23
86
  /**
24
87
  * Configures the client transport. Call once, before any server function is
25
88
  * invoked — typically in the client entry, next to `hydrate()`. Only needed
26
- * when deviating from the defaults (custom endpoint or codec plugins).
89
+ * when deviating from the defaults (custom endpoint, codec plugins, or a
90
+ * `prepareRequest` hook).
27
91
  */
28
92
  export function configureServerFunctionsClient(config?: ServerFunctionsClientConfig): void;
29
93
 
30
94
  /**
31
- * What a server function import is at runtime on the client: an async
32
- * callable that fetches the server, plus escape hatches for forms and
33
- * custom requests.
95
+ * Declares a server function callable over HTTP GET: calls to the returned
96
+ * reference go out as GET requests with the arguments codec-encoded in the
97
+ * query string — cacheable by HTTP infrastructure. Cache headers flow
98
+ * through the handler's header forwarding
99
+ * (`respond(data, { headers: { "cache-control": "max-age=60" } })`).
100
+ *
101
+ * The declaration rides the metadata channel
102
+ * (`getServerFunctionMetadata(fn)?.method === "GET"`) for routers and
103
+ * integrations to detect, and the server honors it: GET-declared functions
104
+ * accept GET requests in addition to the default POST transport (declaring
105
+ * GET grants, it does not revoke); functions that never declared GET answer
106
+ * GET requests with 405. Server-side the wrapper is identity-flavored — SSR
107
+ * calls stay in-process.
108
+ *
109
+ * Wrap the reference at its declaration; the compiler round-trips the call
110
+ * in both builds:
111
+ *
112
+ * ```ts
113
+ * export const getUser = GET(async (id: string) => {
114
+ * "use server";
115
+ * return db.users.find(id);
116
+ * });
117
+ * ```
34
118
  */
35
- export interface ServerFunctionCallable {
36
- (...args: any[]): Promise<any>;
37
- /** URL invoking this function directly over HTTP (e.g. form `action`s). */
38
- url: string;
39
- /**
40
- * Variant issuing GET requests with the arguments encoded in the query
41
- * string — cacheable by HTTP infrastructure.
42
- */
43
- GET: ServerFunctionCallable;
44
- /** Variant applying a custom RequestInit to every call (headers etc.). */
45
- withOptions(options: RequestInit): ServerFunctionCallable;
46
- }
119
+ export function GET<A extends readonly any[], R>(
120
+ fn: (...args: A) => R
121
+ ): ServerFunction<A, Awaited<R>>;
47
122
 
48
123
  /**
49
124
  * Compiler ABI — emitted by compiled `"use server"` client output where a
50
125
  * server function was referenced; produces the fetch-backed callable for
51
- * the function's build-stable id. Not meant for hand-written code.
126
+ * the function's build-stable id. Development builds pass the function's
127
+ * source name as the trailing argument (dev-only metadata seeded on the
128
+ * metadata channel; never emitted in production). Not meant for
129
+ * hand-written code.
130
+ *
131
+ * The optional `base` targets calls at that url verbatim instead of the
132
+ * configured endpoint — for integrations reconstructing a callable from a
133
+ * server-rendered action url (e.g. a router intercepting a form submit whose
134
+ * `action="/_server?id=...&args=..."` came off the wire): bound arguments
135
+ * stay in the query string, where the server reads them for natural-encoding
136
+ * bodies (FormData, urlencoded).
52
137
  * @internal
53
138
  */
54
- export function createServerReference(id: string): ServerFunctionCallable;
139
+ export function createServerReference(id: string, name?: string, base?: string): ServerFunction;
55
140
 
56
141
  /**
57
142
  * Compiler ABI — only ever referenced by server-mode compiler output;
@@ -2,7 +2,27 @@ import { ResponseEnvelope } from "../response.cjs";
2
2
  import { JSONCodecOptions } from "../serializer.cjs";
3
3
  import { RequestEvent } from "../server.cjs";
4
4
 
5
- export { FUNCTION_HEADER, INSTANCE_HEADER, decodeResponse } from "./shared.cjs";
5
+ export {
6
+ ERROR_HEADER,
7
+ FUNCTION_HEADER,
8
+ INSTANCE_HEADER,
9
+ SINGLE_FLIGHT_HEADER,
10
+ decodeErrorHeaderValue,
11
+ decodeResponse,
12
+ encodeErrorHeaderValue,
13
+ getServerFunctionMetadata,
14
+ isServerFunction,
15
+ subscribeFlightData,
16
+ withMeta
17
+ } from "./shared.cjs";
18
+ export type {
19
+ FlightDataConsumer,
20
+ FlightDataContext,
21
+ ServerFunction,
22
+ ServerFunctionMetadata,
23
+ SingleFlightPayload
24
+ } from "./shared.cjs";
25
+ import { ServerFunction } from "./shared.cjs";
6
26
 
7
27
  /**
8
28
  * The request event a server function call runs under: the base
@@ -13,6 +33,58 @@ export interface ServerFunctionEvent extends RequestEvent {
13
33
  serverOnly?: boolean;
14
34
  }
15
35
 
36
+ /**
37
+ * What a server function call resolved to, as seen by the single-flight
38
+ * hook — enough context for any data-production strategy without core
39
+ * assuming one.
40
+ */
41
+ export interface ServerFunctionOutcome {
42
+ /** The build-stable id of the function that ran. */
43
+ id: string;
44
+ /**
45
+ * The value the caller will receive: the raw return for plain results,
46
+ * the unwrapped `value` for `ResponseEnvelope`s, `null` for body-less
47
+ * control-flow `Response`s (redirect/reload).
48
+ */
49
+ value: unknown;
50
+ /**
51
+ * The `Response` carrying the result's HTTP metadata, when there is one
52
+ * (from a returned/thrown `Response` or a `ResponseEnvelope`). Read
53
+ * `Location` here for redirect-with-data — the data should describe the
54
+ * destination route — and `X-Revalidate` for the invalidated keys.
55
+ * Undefined for plain values.
56
+ */
57
+ response: Response | undefined;
58
+ /**
59
+ * The original HTTP request, untouched: headers the client integration
60
+ * sent (referrer, custom route context) ride here for the hook to read —
61
+ * core assigns them no meaning.
62
+ */
63
+ request: Request;
64
+ /** Whether the result was thrown rather than returned. */
65
+ thrown: boolean;
66
+ }
67
+
68
+ /**
69
+ * The single-flight server hook: given the request event and the function's
70
+ * outcome, optionally produce a data payload (possibly async) to fold into
71
+ * the response alongside the return value. Data production is a black box
72
+ * to the protocol — render data-only, run route preloads, query a cache,
73
+ * whatever the integration chooses; the payload just has to be
74
+ * codec-serializable. Return undefined to send the response unchanged
75
+ * (byte-identical to a call without the hook).
76
+ *
77
+ * Runs after `transformResult`, only for scripted calls that sent
78
+ * `SINGLE_FLIGHT_HEADER` on the request, on returned results and thrown
79
+ * `Response`/`ResponseEnvelope` control-flow signals alike (plain thrown
80
+ * errors never collect). The handler owns the enveloping: contributed data
81
+ * ships as `{ value, data }` under the single-flight response header.
82
+ */
83
+ export type CollectFlightDataHook = (
84
+ event: ServerFunctionEvent,
85
+ outcome: ServerFunctionOutcome
86
+ ) => unknown | Promise<unknown>;
87
+
16
88
  /** Options for `configureServerFunctionsServer`. */
17
89
  export interface ServerFunctionsServerConfig {
18
90
  /**
@@ -23,6 +95,13 @@ export interface ServerFunctionsServerConfig {
23
95
  * an established request scope parks on the global.
24
96
  */
25
97
  provideEvent?: <T>(event: ServerFunctionEvent, fn: () => T) => T;
98
+ /**
99
+ * The single-flight hook: produces the data payload folded into
100
+ * responses of calls that opted in (see `CollectFlightDataHook`).
101
+ * Registered once by the integration that owns data production (a
102
+ * router); per-handler `collectFlightData` options override it.
103
+ */
104
+ collectFlightData?: CollectFlightDataHook;
26
105
  /**
27
106
  * Endpoint the HTTP handler is mounted on, used for the `url` of SSR'd
28
107
  * references (e.g. form actions) — must match the client configuration.
@@ -42,7 +121,8 @@ export interface ServerFunctionsServerConfig {
42
121
  /**
43
122
  * Configures the server runtime. Call once at server startup, before
44
123
  * handling requests. Only needed when deviating from the defaults (custom
45
- * endpoint, codec plugins, or an explicit event provider).
124
+ * endpoint, codec plugins, an explicit event provider, or a single-flight
125
+ * hook).
46
126
  */
47
127
  export function configureServerFunctionsServer(config?: ServerFunctionsServerConfig): void;
48
128
 
@@ -57,6 +137,12 @@ export function configureServerFunctionsServer(config?: ServerFunctionsServerCon
57
137
  export interface ServerFunctionReference<T extends any[] = any[], R = any> {
58
138
  id: string;
59
139
  fn: (...args: T) => R;
140
+ /**
141
+ * The function's source name, emitted by development builds only —
142
+ * `createServerReference` seeds the metadata channel with it.
143
+ * @internal
144
+ */
145
+ name?: string;
60
146
  }
61
147
 
62
148
  /**
@@ -82,12 +168,15 @@ export function getServerFunction<T extends any[], R>(id: string): (...args: T)
82
168
  * Compiler ABI — emitted by compiled `"use server"` server output for
83
169
  * every server function: registers `fn` for HTTP dispatch under its
84
170
  * build-stable id and returns the reference the server-side
85
- * `createServerReference` consumes. Not meant for hand-written code.
171
+ * `createServerReference` consumes. Development builds pass the function's
172
+ * source name as the trailing argument (dev-only metadata; never emitted in
173
+ * production). Not meant for hand-written code.
86
174
  * @internal
87
175
  */
88
176
  export function registerServerReference<T extends any[], R>(
89
177
  id: string,
90
- fn: (...args: T) => R
178
+ fn: (...args: T) => R,
179
+ name?: string
91
180
  ): ServerFunctionReference<T, R>;
92
181
 
93
182
  /**
@@ -102,6 +191,30 @@ export function createServerReference<T extends any[], R>(
102
191
  reference: ServerFunctionReference<T, R>
103
192
  ): (...args: T) => R;
104
193
 
194
+ /**
195
+ * Declares a server function callable over HTTP GET. The server half is
196
+ * identity-flavored — SSR calls stay in-process — but it brands the
197
+ * declaration on the reference's metadata channel
198
+ * (`getServerFunctionMetadata(fn)?.method === "GET"`) and records the
199
+ * declared method for the function's id so `handleServerFunctionRequest`
200
+ * honors it: GET-declared functions accept GET requests in addition to the
201
+ * default POST transport (declaring GET grants, it does not revoke);
202
+ * functions that never declared GET answer GET requests with 405.
203
+ *
204
+ * Wrap the reference at its declaration; the compiler round-trips the call
205
+ * in both builds:
206
+ *
207
+ * ```ts
208
+ * export const getUser = GET(async (id: string) => {
209
+ * "use server";
210
+ * return db.users.find(id);
211
+ * });
212
+ * ```
213
+ */
214
+ export function GET<A extends readonly any[], R>(
215
+ fn: (...args: A) => R
216
+ ): ServerFunction<A, Awaited<R>>;
217
+
105
218
  /** Identity of the currently executing server function. */
106
219
  export interface ServerFunctionMeta {
107
220
  id: string;
@@ -133,17 +246,26 @@ export interface HandleServerFunctionOptions {
133
246
  provideEvent?<T>(event: ServerFunctionEvent, fn: () => T): T;
134
247
  /**
135
248
  * Observes or replaces the function's result before encoding — the
136
- * extension point for policies like single-flight payloads. Runs for
137
- * returned and thrown results alike (`context.thrown` distinguishes);
138
- * `context.instance` is null for no-JS calls. Return the result
139
- * unchanged to pass through, or a `ResponseEnvelope` (exposed through
140
- * the core entry) to send HTTP metadata plus a structured payload.
249
+ * extension point for response metadata policies (headers, statuses,
250
+ * substituted results). Runs for returned and thrown results alike
251
+ * (`context.thrown` distinguishes); `context.instance` is null for no-JS
252
+ * calls. Return the result unchanged to pass through, or a
253
+ * `ResponseEnvelope` (exposed through the core entry) to send HTTP
254
+ * metadata plus a structured payload. Runs before `collectFlightData`,
255
+ * so the flight hook sees the transformed outcome — use
256
+ * `collectFlightData`, not this, to fold data into the response.
141
257
  */
142
258
  transformResult?(
143
259
  event: ServerFunctionEvent,
144
260
  result: unknown,
145
261
  context: { instance: string | null; request: Request; thrown?: boolean }
146
262
  ): unknown | ResponseEnvelope | Promise<unknown | ResponseEnvelope>;
263
+ /**
264
+ * Overrides the configured single-flight hook for this handler — same
265
+ * contract as the `collectFlightData` config option (see
266
+ * `CollectFlightDataHook`).
267
+ */
268
+ collectFlightData?: CollectFlightDataHook;
147
269
  /**
148
270
  * Builds the response for calls made without the client runtime (no
149
271
  * instance header — no-JS form posts, direct HTTP) — the extension
@@ -164,12 +286,13 @@ export interface HandleServerFunctionOptions {
164
286
 
165
287
  /**
166
288
  * Web-standard HTTP handler for server function calls: resolves the
167
- * function id from the request, decodes arguments, runs the function under
168
- * a request-event scope, and encodes the result (forwarding
169
- * redirect/revalidation metadata through headers). Mount it on the endpoint
170
- * the client transport targets (default `/_server`); platform adapters
171
- * (h3, express, ...) convert their request shape to a web `Request` around
172
- * it.
289
+ * function id from the request, gates GET dispatch on the declaration (405
290
+ * for a GET request to a function that never declared `GET`; POST is always
291
+ * accepted), decodes arguments, runs the function under a request-event scope,
292
+ * and encodes the result (forwarding redirect/revalidation metadata
293
+ * through headers). Mount it on the endpoint the client transport targets
294
+ * (default `/_server`); platform adapters (h3, express, ...) convert their
295
+ * request shape to a web `Request` around it.
173
296
  *
174
297
  * @example
175
298
  * ```ts
@@ -38,6 +38,206 @@ export const FUNCTION_HEADER: string;
38
38
  */
39
39
  export const INSTANCE_HEADER: string;
40
40
 
41
+ /**
42
+ * Response header marking a thrown server-function error
43
+ * (`"X-Server-Function-Error"`). The client transport rejects with the
44
+ * decoded body when it is present (unless redirect/revalidation metadata
45
+ * marks the response as control flow). The value carries the error's
46
+ * message — `"true"` for thrown control-flow responses and non-Error
47
+ * values — encoded with `encodeErrorHeaderValue`, so integrations reading
48
+ * it must pass it through `decodeErrorHeaderValue`.
49
+ */
50
+ export const ERROR_HEADER: string;
51
+
52
+ /**
53
+ * Encodes an error message for the `ERROR_HEADER` value. HTTP header values
54
+ * are latin1 ByteStrings — `Headers.set` throws on code points above U+00FF
55
+ * — so plain printable-latin1 messages ride verbatim (ASCII stays
56
+ * byte-identical on the wire) and everything else (CJK, emoji, controls)
57
+ * travels percent-encoded behind a marker. `decodeErrorHeaderValue`
58
+ * round-trips the message exactly, astral-plane characters included (lone
59
+ * surrogates are replaced with U+FFFD — they cannot survive UTF-8 anyway).
60
+ */
61
+ export function encodeErrorHeaderValue(value: string): string;
62
+
63
+ /**
64
+ * Decodes an `ERROR_HEADER` value produced by `encodeErrorHeaderValue`:
65
+ * marked values are percent-decoded, everything else (including values from
66
+ * peers that never encode) passes through untouched.
67
+ */
68
+ export function decodeErrorHeaderValue(value: string): string;
69
+
70
+ /**
71
+ * Header driving the single-flight protocol on both legs
72
+ * (`"X-Single-Flight"`). On the request it opts the call into data
73
+ * collection — the transport sends it automatically on non-GET calls while
74
+ * a flight-data consumer is subscribed (subscribing IS the opt-in). On the
75
+ * response it marks a body carrying the standardized `SingleFlightPayload`.
76
+ * How the data is produced (a data-only render, running route preloads,
77
+ * anything else) and what it means is entirely the integration's business —
78
+ * the protocol only standardizes the wire shape and the delivery.
79
+ */
80
+ export const SINGLE_FLIGHT_HEADER: string;
81
+
82
+ /**
83
+ * The standardized body of a single-flight response (a response tagged with
84
+ * `SINGLE_FLIGHT_HEADER`): the function's return `value` plus the
85
+ * integration-produced `data` payload, folded into one round trip by the
86
+ * HTTP handler. Integrations decoding passthrough responses themselves (no
87
+ * registered consumer) see this shape from `decodeResponse`. The top level
88
+ * is reserved for the protocol — integration payload lives entirely under
89
+ * `data`, which can be any codec-serializable value.
90
+ */
91
+ export interface SingleFlightPayload<T = unknown, D = unknown> {
92
+ /** The server function's return (or thrown) value. */
93
+ value: T;
94
+ /** The integration-produced data payload. */
95
+ data: D;
96
+ }
97
+
98
+ /**
99
+ * Envelope context delivered alongside single-flight data: the transport
100
+ * response, whose headers carry the integration metadata (`Location` for
101
+ * redirect-with-data, `X-Revalidate` keys) and status. The body is already
102
+ * consumed — read `data` and `value` from the delivery, not from here.
103
+ */
104
+ export interface FlightDataContext {
105
+ /** The HTTP response the data arrived on (metadata only). */
106
+ response: Response;
107
+ }
108
+
109
+ /**
110
+ * Consumer receiving single-flight data on the client: `data` is the
111
+ * integration-produced payload (opaque to the protocol), `context` carries
112
+ * the envelope metadata. Async consumers are awaited before the function
113
+ * value is returned to the caller, so caches are seeded first.
114
+ */
115
+ export type FlightDataConsumer<D = unknown> = (
116
+ data: D,
117
+ context: FlightDataContext
118
+ ) => void | Promise<void>;
119
+
120
+ /**
121
+ * Registers the consumer the client transport delivers single-flight data
122
+ * to. Subscribing is the single-flight opt-in: while a consumer is
123
+ * registered the transport sends the request-leg `SINGLE_FLIGHT_HEADER` on
124
+ * non-GET calls (GET reads stay plain and cacheable), asking the server's
125
+ * collection hook to fold data into the response. When a single-flight
126
+ * response arrives, the transport decodes the standardized
127
+ * `{ value, data }` payload, delivers `data` (with the response as
128
+ * envelope context — redirect location, revalidation keys), and returns
129
+ * `value` to the caller as if the call were plain. What to do with the
130
+ * data (seed caches, navigate, ...) is entirely the consumer's business.
131
+ * One active consumer at a time — a later registration replaces the
132
+ * current one; returns an unsubscribe function. With no consumer
133
+ * registered, no header is sent and the server does no collection work;
134
+ * responses an integration opted in manually still pass through to the
135
+ * caller whole, exactly like other integration responses.
136
+ */
137
+ export function subscribeFlightData<D = unknown>(consumer: FlightDataConsumer<D>): () => void;
138
+
139
+ /**
140
+ * The currently registered single-flight consumer.
141
+ *
142
+ * Transport building block; not meant for hand-written code.
143
+ * @internal
144
+ */
145
+ export function getFlightDataConsumer(): FlightDataConsumer | undefined;
146
+
147
+ /**
148
+ * The public contract of a server function reference — what a `"use
149
+ * server"` import is at runtime on either side: an async callable plus its
150
+ * build-stable identity.
151
+ */
152
+ export interface ServerFunction<A extends readonly any[] = any[], T = any> {
153
+ (...args: A): Promise<T>;
154
+ /** The build-stable function id (stable across the client and server builds). */
155
+ readonly id: string;
156
+ /** URL invoking this function directly over HTTP (form `action`s, raw fetches). */
157
+ readonly url: string;
158
+ }
159
+
160
+ /**
161
+ * Declaration-static metadata attached to a server function reference
162
+ * through declaration wrappers (`GET`, `withMeta`). Read it with
163
+ * `getServerFunctionMetadata`; routers and integrations detect capability
164
+ * from here instead of property sniffing, and `prepareRequest` receives it
165
+ * as `context.meta`. Write through `withMeta` — later writes shallow-merge
166
+ * over earlier ones.
167
+ */
168
+ export interface ServerFunctionMetadata {
169
+ /** The declared HTTP method. Undeclared references call over POST. */
170
+ readonly method?: "GET" | "POST";
171
+ /**
172
+ * A human-readable label for the function, seeded by development builds
173
+ * from the compiled function's source name (dev tooling — inspectors,
174
+ * logs). Dev-only: production builds emit no name. Not unique and not an
175
+ * identity key — use `id` for identity. Seeded as a default: an explicit
176
+ * `withMeta` write wins.
177
+ */
178
+ readonly name?: string;
179
+ /** User-declared transport metadata attached with `withMeta`. */
180
+ readonly [key: string]: unknown;
181
+ }
182
+
183
+ /**
184
+ * Reads a server function reference's declaration metadata — e.g.
185
+ * `getServerFunctionMetadata(fn)?.method === "GET"` detects a `GET(fn)`
186
+ * declaration. Returns undefined when `fn` is not a server function
187
+ * reference; plain references carry an empty metadata object. Works on
188
+ * client proxies and server-side references alike, across duplicated
189
+ * module instances (registered-symbol brand).
190
+ */
191
+ export function getServerFunctionMetadata(fn: unknown): ServerFunctionMetadata | undefined;
192
+
193
+ /**
194
+ * Whether `fn` is a server function reference (a client proxy or a
195
+ * server-side registered callable). Detection is structural — a
196
+ * registered-symbol metadata brand — so it holds across duplicated module
197
+ * instances and both sides of the directive boundary.
198
+ */
199
+ export function isServerFunction(fn: unknown): fn is ServerFunction;
200
+
201
+ /**
202
+ * Attaches user-declared transport metadata to a server function reference
203
+ * (client proxy or server-registered callable) and returns the reference.
204
+ * Writes ride the same channel `GET` uses: later writes shallow-merge over
205
+ * earlier ones, and `getServerFunctionMetadata(fn)` reads the merged bag —
206
+ * so `withMeta` composes with `GET` in either order
207
+ * (`GET(withMeta(fn, meta))` ≡ `withMeta(GET(fn), meta)`).
208
+ *
209
+ * The pattern is declare-on-function, react-in-hook: metadata declared
210
+ * here reaches `prepareRequest` as `context.meta`, letting session-dynamic
211
+ * transport policy key on declarations instead of comparing function ids:
212
+ *
213
+ * ```ts
214
+ * export const chargeCard = withMeta(async (amount: number) => {
215
+ * "use server";
216
+ * // ...
217
+ * }, { requiresAuth: true });
218
+ *
219
+ * configureServerFunctionsClient({
220
+ * prepareRequest(init, { meta }) {
221
+ * if (meta?.requiresAuth) {
222
+ * return {
223
+ * ...init,
224
+ * headers: { ...init.headers, Authorization: `Bearer ${session.token()}` }
225
+ * };
226
+ * }
227
+ * return init;
228
+ * }
229
+ * });
230
+ * ```
231
+ */
232
+ export function withMeta<F extends (...args: any[]) => any>(fn: F, meta: ServerFunctionMetadata): F;
233
+
234
+ /**
235
+ * The registered symbol branding server function references with their
236
+ * declaration metadata. Use the typed accessors instead.
237
+ * @internal
238
+ */
239
+ export const SERVER_FUNCTION_METADATA: unique symbol;
240
+
41
241
  /**
42
242
  * Header carrying the body format tag (a `BodyFormat` value) —
43
243
  * `"X-Server-Function-Format"`.
@@ -205,6 +205,14 @@ export function setAttribute(node: Element, name: string, value: string): void;
205
205
  /** @deprecated not supported on the server side */
206
206
  export function setAttributeNS(node: Element, namespace: string, name: string, value: string): void;
207
207
 
208
+ /**
209
+ * Server no-op: element claims are a client-only concern, but consumers may
210
+ * register isomorphically. Returns a no-op unregister function.
211
+ */
212
+ export function registerElementClaim(handler: (element: Element) => void): () => void;
213
+ /** Server no-op: returns `node` unchanged. Claims never fire during SSR. */
214
+ export function claimElement<T extends Element>(node: T): T;
215
+
208
216
  /** @deprecated not supported on the server side */
209
217
  export function addEvent(node: Element, name: string, handler: () => void, delegate: boolean): void;
210
218