@solidjs/web 2.0.0-beta.26 → 2.0.0-beta.28

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.
Files changed (43) hide show
  1. package/dist/dev.cjs +3 -1
  2. package/dist/dev.js +3 -2
  3. package/dist/server.cjs +64 -84
  4. package/dist/server.js +65 -86
  5. package/dist/web.cjs +3 -1
  6. package/dist/web.js +3 -2
  7. package/frames/dist/client.cjs +69 -21
  8. package/frames/dist/client.dev.cjs +69 -21
  9. package/frames/dist/client.dev.js +70 -22
  10. package/frames/dist/client.js +70 -22
  11. package/frames/dist/server.cjs +55 -50
  12. package/frames/dist/server.js +55 -50
  13. package/package.json +4 -4
  14. package/serialization/dist/serialization.cjs +6 -3
  15. package/serialization/dist/serialization.js +6 -3
  16. package/serialization/types/index.d.ts +7 -1
  17. package/serialization/types-cjs/index.d.cts +7 -1
  18. package/server-functions/dist/client.cjs +28 -2
  19. package/server-functions/dist/client.js +25 -3
  20. package/server-functions/dist/server.cjs +194 -5
  21. package/server-functions/dist/server.js +187 -6
  22. package/types/client.d.ts +3 -3
  23. package/types/frames/client.d.ts +1 -0
  24. package/types/frames/serializer.d.ts +7 -1
  25. package/types/frames/server.d.ts +28 -0
  26. package/types/jsx.d.ts +1 -1
  27. package/types/response.d.ts +10 -0
  28. package/types/serializer.d.ts +7 -1
  29. package/types/server-functions/client.d.ts +4 -0
  30. package/types/server-functions/flash.d.ts +38 -0
  31. package/types/server-functions/server.d.ts +109 -6
  32. package/types/server-functions/shared.d.ts +48 -0
  33. package/types-cjs/client.d.cts +3 -3
  34. package/types-cjs/frames/client.d.cts +1 -0
  35. package/types-cjs/frames/serializer.d.cts +7 -1
  36. package/types-cjs/frames/server.d.cts +28 -0
  37. package/types-cjs/jsx.d.cts +1 -1
  38. package/types-cjs/response.d.cts +10 -0
  39. package/types-cjs/serializer.d.cts +7 -1
  40. package/types-cjs/server-functions/client.d.cts +4 -0
  41. package/types-cjs/server-functions/flash.d.cts +38 -0
  42. package/types-cjs/server-functions/server.d.cts +109 -6
  43. package/types-cjs/server-functions/shared.d.cts +48 -0
@@ -4,13 +4,17 @@ import { RequestEvent } from "../server.cjs";
4
4
 
5
5
  export {
6
6
  ERROR_HEADER,
7
+ FLASH_COOKIE,
7
8
  FUNCTION_HEADER,
8
9
  INSTANCE_HEADER,
9
10
  SINGLE_FLIGHT_HEADER,
11
+ clearFlashCookie,
10
12
  decodeErrorHeaderValue,
11
13
  decodeResponse,
14
+ decodeResponsePayload,
12
15
  encodeErrorHeaderValue,
13
16
  getServerFunctionMetadata,
17
+ hasFlashCookie,
14
18
  isServerFunction,
15
19
  subscribeFlightData,
16
20
  withMeta
@@ -22,6 +26,8 @@ export type {
22
26
  ServerFunctionMetadata,
23
27
  SingleFlightPayload
24
28
  } from "./shared.cjs";
29
+ export { decodeFlashCookie, encodeFlashCookie } from "./flash.cjs";
30
+ export type { FlashSubmission } from "./flash.cjs";
25
31
  import { ServerFunction } from "./shared.cjs";
26
32
 
27
33
  /**
@@ -63,6 +69,29 @@ export interface ServerFunctionOutcome {
63
69
  request: Request;
64
70
  /** Whether the result was thrown rather than returned. */
65
71
  thrown: boolean;
72
+ /**
73
+ * The URL the client will show after the mutation — the redirect
74
+ * `Location` when the outcome carries one (resolved against the request
75
+ * URL, as a browser would), the referring page otherwise. Undefined
76
+ * without a usable referer (a non-browser caller has no page to produce
77
+ * data for) and for redirects leaving the app's origin: produce no data
78
+ * when this is undefined.
79
+ */
80
+ targetUrl: string | undefined;
81
+ /**
82
+ * The outcome's `X-Revalidate` keys, split — the invalidation scope the
83
+ * mutation declared. Undefined when the outcome carries none (integrations
84
+ * typically collect everything for the target in that case).
85
+ */
86
+ revalidateKeys: string[] | undefined;
87
+ /**
88
+ * The request headers with the mutation's cookie effects applied: the
89
+ * event response's `Set-Cookie`s (set during the call), then the
90
+ * outcome's own (e.g. `redirect(to, { headers })`), later winning on
91
+ * conflict, deletions honored. Build the data-collection request from
92
+ * these so re-run reads observe post-mutation cookie state.
93
+ */
94
+ foldedHeaders: Headers;
66
95
  }
67
96
 
68
97
  /**
@@ -77,14 +106,69 @@ export interface ServerFunctionOutcome {
77
106
  * Runs after `transformResult`, only for scripted calls that sent
78
107
  * `SINGLE_FLIGHT_HEADER` on the request, on returned results and thrown
79
108
  * `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.
109
+ * errors never collect, and neither do raw body-carrying `Response` values
110
+ * those are the caller's verbatim payload). The handler owns the
111
+ * enveloping: contributed data ships as `{ value, data }` under the
112
+ * single-flight response header. The generic halves of collection arrive
113
+ * pre-digested on the outcome (`targetUrl`, `revalidateKeys`,
114
+ * `foldedHeaders`); the hook supplies only the data strategy.
82
115
  */
83
116
  export type CollectFlightDataHook = (
84
117
  event: ServerFunctionEvent,
85
118
  outcome: ServerFunctionOutcome
86
119
  ) => unknown | Promise<unknown>;
87
120
 
121
+ /**
122
+ * Request headers with `setCookies` folded into the `Cookie` header, as the
123
+ * browser would have applied them before its next request. Later entries
124
+ * win on conflict, and deletions are honored (`Max-Age` at or below zero,
125
+ * `Expires` in the past). The input headers are not modified.
126
+ *
127
+ * For work re-run on the server after a mutation — a
128
+ * `CollectFlightDataHook` gathering fresh data, typically. That pass starts
129
+ * from the request that triggered the mutation, whose cookies are
130
+ * pre-mutation by definition, so a read depending on a session the mutation
131
+ * just established would otherwise see the old state. Which responses
132
+ * contribute their `Set-Cookie`s, and in what order, is the caller's
133
+ * decision.
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * const headers = foldSetCookies(event.request.headers, [
138
+ * ...(event.response?.headers?.getSetCookie() ?? []),
139
+ * ...(outcome.response?.headers?.getSetCookie() ?? [])
140
+ * ]);
141
+ * ```
142
+ */
143
+ export function foldSetCookies(headers: Headers, setCookies: readonly string[]): Headers;
144
+
145
+ /** Options for `createNoJSHandler`. */
146
+ export interface NoJSHandlerOptions {
147
+ /** The app's mount path, for resolving a relative redirect `Location`. */
148
+ base?: string;
149
+ }
150
+
151
+ /**
152
+ * Builds the `handleNoJS` implementation for the no-JS form convention: a
153
+ * form posted without the client runtime has no way to receive a value, so
154
+ * the call redirects back to the referring page (or to the result's own
155
+ * `Location`, resolved against `base`) with the outcome riding a one-shot
156
+ * flash cookie. `303 See Other` turns the POST into a GET unless the result
157
+ * names a redirect status of its own. A result that is already a `Response`
158
+ * carries its meaning in its metadata and is not flashed.
159
+ *
160
+ * The render that follows reads the cookie with `decodeFlashCookie` and
161
+ * surfaces the outcome however it likes — that half is the integration's.
162
+ *
163
+ * The handler applies to every call it receives. `handleServerFunctionRequest`
164
+ * already uses it for browser form posts, so wire it explicitly only to set
165
+ * a `base`, or to extend the convention to direct HTTP calls by registering
166
+ * it through `configureServerFunctionsServer`.
167
+ */
168
+ export function createNoJSHandler(
169
+ options?: NoJSHandlerOptions
170
+ ): (result: unknown, request: Request, args: unknown[], thrown?: boolean) => Response;
171
+
88
172
  /** Options for `configureServerFunctionsServer`. */
89
173
  export interface ServerFunctionsServerConfig {
90
174
  /**
@@ -119,6 +203,23 @@ export interface ServerFunctionsServerConfig {
119
203
  * calls during document SSR — e.g. frames' `frameTransformDirectResult`.
120
204
  */
121
205
  transformDirectResult?(value: unknown, options: { id: string }): unknown;
206
+ /**
207
+ * Server-wide response builder for calls made without the client runtime
208
+ * (see `handleNoJS` in `HandleServerFunctionRequestOptions`); a
209
+ * per-request option overrides it. Set it to `createNoJSHandler({ base })`
210
+ * to apply the convention to every non-scripted call rather than only to
211
+ * browser form posts, to a handler of your own to replace it, or to
212
+ * `null` to disable the built-in convention and answer form posts with
213
+ * the plain serialized response.
214
+ */
215
+ handleNoJS?:
216
+ | ((
217
+ result: unknown,
218
+ request: Request,
219
+ args: unknown[],
220
+ thrown?: boolean
221
+ ) => Response | Promise<Response>)
222
+ | null;
122
223
  /**
123
224
  * Endpoint the HTTP handler is mounted on, used for the `url` of SSR'd
124
225
  * references (e.g. form actions) — must match the client configuration.
@@ -285,11 +386,13 @@ export interface HandleServerFunctionOptions {
285
386
  collectFlightData?: CollectFlightDataHook;
286
387
  /**
287
388
  * Builds the response for calls made without the client runtime (no
288
- * instance header — no-JS form posts, direct HTTP) the extension
289
- * point for conventions like redirect-with-flash-cookie. Receives the
389
+ * instance header — no-JS form posts, direct HTTP). Receives the
290
390
  * (transformed) result, the request, and the decoded arguments; `thrown`
291
- * is set when the result was thrown rather than returned. Defaults to
292
- * the normal serialized response.
391
+ * is set when the result was thrown rather than returned.
392
+ *
393
+ * Overrides the configured hook, which in turn overrides the built-in
394
+ * `createNoJSHandler()` applied to browser form posts. Other
395
+ * no-instance callers get the normal serialized response.
293
396
  */
294
397
  handleNoJS?(
295
398
  result: unknown,
@@ -136,6 +136,41 @@ export type FlightDataConsumer<D = unknown> = (
136
136
  */
137
137
  export function subscribeFlightData<D = unknown>(consumer: FlightDataConsumer<D>): () => void;
138
138
 
139
+ /**
140
+ * Name of the cookie carrying the outcome of a call made without the client
141
+ * runtime (`"flash"`). A no-JS form post has no way to receive a value —
142
+ * the browser follows the redirect and renders the next page — so the
143
+ * handler stashes the outcome here for the render after it to pick up,
144
+ * which is how a form submitted without JavaScript still shows its result.
145
+ *
146
+ * The name, detection and clearing are isomorphic (integrations read the
147
+ * cookie from code that also ships to the browser); the codec that fills it
148
+ * is server-only and lives behind the server entry.
149
+ */
150
+ export const FLASH_COOKIE: string;
151
+
152
+ /**
153
+ * Whether a Cookie header carries a flash cookie, readable or not. Cheap
154
+ * enough to call on every render so the clear can be queued before the
155
+ * response headers flush.
156
+ */
157
+ export function hasFlashCookie(cookieHeader: string | null): boolean;
158
+
159
+ /**
160
+ * The `Set-Cookie` value clearing the flash cookie. The outcome is
161
+ * one-shot: append this as soon as the cookie is detected, whether or not
162
+ * it decodes, so a stale outcome cannot resurface on a later request.
163
+ */
164
+ export function clearFlashCookie(): string;
165
+
166
+ /**
167
+ * The raw encoded flash payload out of a Cookie header, if present — the
168
+ * codec's own accessor.
169
+ *
170
+ * @internal
171
+ */
172
+ export function matchFlashCookie(cookieHeader: string | null): string | undefined;
173
+
139
174
  /**
140
175
  * The currently registered single-flight consumer.
141
176
  *
@@ -370,6 +405,19 @@ export function decodeResponse<T = unknown>(
370
405
  codecOptions?: JSONCodecOptions
371
406
  ): Promise<T | undefined>;
372
407
 
408
+ /**
409
+ * `decodeResponse` plus the single-flight envelope split: when the response
410
+ * carries the single-flight header the decoded `{ value, data }` payload is
411
+ * unwrapped into `{ value, flightData }`; otherwise the decoded body (or
412
+ * undefined for body-less responses) rides as `{ value }`. Integrations
413
+ * that apply response metadata themselves use this so the payload shape
414
+ * stays core's own.
415
+ */
416
+ export function decodeResponsePayload<T = unknown, D = unknown>(
417
+ response: Response,
418
+ codecOptions?: JSONCodecOptions
419
+ ): Promise<{ value: T | undefined; flightData?: D }>;
420
+
373
421
  /**
374
422
  * Frame one payload for the server-function wire: a `;0x<len32>;` length
375
423
  * prefix followed by the utf-8 data. Both transports (server-function