@solidjs/web 2.0.0-rc.4 → 2.0.0-rc.5

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 (57) hide show
  1. package/dist/dev.cjs +52 -7
  2. package/dist/dev.js +51 -8
  3. package/dist/server.cjs +162 -35
  4. package/dist/server.js +161 -36
  5. package/dist/web.cjs +32 -7
  6. package/dist/web.js +31 -8
  7. package/frames/dist/client.cjs +41 -8
  8. package/frames/dist/client.dev.cjs +41 -8
  9. package/frames/dist/client.dev.js +41 -8
  10. package/frames/dist/client.js +41 -8
  11. package/frames/dist/server.cjs +432 -44
  12. package/frames/dist/server.js +432 -44
  13. package/package.json +2 -2
  14. package/serialization/dist/decode.cjs +4 -2
  15. package/serialization/dist/decode.js +4 -2
  16. package/serialization/dist/serialization.cjs +12 -8
  17. package/serialization/dist/serialization.js +12 -8
  18. package/serialization/types/index.d.ts +7 -0
  19. package/serialization/types/serializer-decode.d.ts +14 -1
  20. package/serialization/types/serializer.d.ts +7 -0
  21. package/serialization/types-cjs/index.d.cts +7 -0
  22. package/serialization/types-cjs/serializer-decode.d.cts +14 -1
  23. package/serialization/types-cjs/serializer.d.cts +7 -0
  24. package/server-functions/dist/client.cjs +150 -33
  25. package/server-functions/dist/client.js +147 -34
  26. package/server-functions/dist/server.cjs +731 -118
  27. package/server-functions/dist/server.dev.cjs +751 -118
  28. package/server-functions/dist/server.dev.js +747 -119
  29. package/server-functions/dist/server.js +727 -119
  30. package/types/cookies.d.ts +6 -14
  31. package/types/frames/frame-client.d.ts +4 -0
  32. package/types/frames/serializer-decode.d.ts +14 -1
  33. package/types/frames/serializer.d.ts +7 -0
  34. package/types/jsx.d.ts +11 -16
  35. package/types/response.d.ts +11 -0
  36. package/types/serializer-decode.d.ts +14 -1
  37. package/types/serializer.d.ts +7 -0
  38. package/types/server-functions/client.d.ts +22 -2
  39. package/types/server-functions/flash.d.ts +9 -0
  40. package/types/server-functions/server.d.ts +58 -9
  41. package/types/server-functions/shared.d.ts +77 -14
  42. package/types/server-mock.d.ts +17 -2
  43. package/types/server.d.ts +16 -2
  44. package/types-cjs/cookies.d.cts +6 -14
  45. package/types-cjs/frames/frame-client.d.cts +4 -0
  46. package/types-cjs/frames/serializer-decode.d.cts +14 -1
  47. package/types-cjs/frames/serializer.d.cts +7 -0
  48. package/types-cjs/jsx.d.cts +11 -16
  49. package/types-cjs/response.d.cts +11 -0
  50. package/types-cjs/serializer-decode.d.cts +14 -1
  51. package/types-cjs/serializer.d.cts +7 -0
  52. package/types-cjs/server-functions/client.d.cts +22 -2
  53. package/types-cjs/server-functions/flash.d.cts +9 -0
  54. package/types-cjs/server-functions/server.d.cts +58 -9
  55. package/types-cjs/server-functions/shared.d.cts +77 -14
  56. package/types-cjs/server-mock.d.cts +17 -2
  57. package/types-cjs/server.d.cts +16 -2
package/dist/dev.cjs CHANGED
@@ -215,7 +215,8 @@ function resourceIdentity(tag, props) {
215
215
  let id = "res:" + tag + ":" + (props.rel || "") + ":" + (props.href || props.src || "");
216
216
  for (let i = 0; i < RESOURCE_QUALIFIERS.length; i++) {
217
217
  const q = RESOURCE_QUALIFIERS[i];
218
- if (props[q] != null) id += ":" + q + "=" + props[q];
218
+ const value = props[q];
219
+ if (value != null) id += ":" + q + "=" + (value === true ? "" : value);
219
220
  }
220
221
  return id;
221
222
  }
@@ -288,6 +289,7 @@ function decodeSafe(text) {
288
289
  }
289
290
  }
290
291
  function serializeCookie(name, value, options = {}) {
292
+ assertServableCookie(name, options);
291
293
  let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
292
294
  cookie += `; Path=${options.path === undefined ? "/" : options.path}`;
293
295
  if (options.domain) cookie += `; Domain=${options.domain}`;
@@ -295,12 +297,32 @@ function serializeCookie(name, value, options = {}) {
295
297
  if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
296
298
  if (options.httpOnly) cookie += "; HttpOnly";
297
299
  if (options.secure) cookie += "; Secure";
300
+ if (options.partitioned) cookie += "; Partitioned";
298
301
  if (options.sameSite) {
299
302
  const sameSite = options.sameSite.toLowerCase();
300
303
  cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
301
304
  }
302
305
  return cookie;
303
306
  }
307
+ function assertServableCookie(name, options) {
308
+ const reject = reason => {
309
+ throw new Error(`serializeCookie: every browser silently rejects this cookie — ${reason}. ` + `It would never come back on a request, with no error anywhere.`);
310
+ };
311
+ const lower = name.toLowerCase();
312
+ if (lower.startsWith("__host-")) {
313
+ if (!options.secure) reject(`the __Host- prefix on \`${name}\` requires \`secure: true\``);
314
+ if (options.path !== undefined && options.path !== "/") reject(`the __Host- prefix on \`${name}\` requires \`Path=/\` (got \`${options.path}\`) — ` + `host-locking is the prefix's whole contract, so it cannot be path-scoped`);
315
+ if (options.domain) reject(`the __Host- prefix on \`${name}\` forbids \`Domain\` (got \`${options.domain}\`)`);
316
+ } else if (lower.startsWith("__secure-") && !options.secure) {
317
+ reject(`the __Secure- prefix on \`${name}\` requires \`secure: true\``);
318
+ }
319
+ if (options.sameSite && options.sameSite.toLowerCase() === "none" && !options.secure) {
320
+ reject("`SameSite=None` requires `secure: true`");
321
+ }
322
+ if (options.partitioned && !options.secure) {
323
+ reject("`Partitioned` requires `secure: true`");
324
+ }
325
+ }
304
326
  const FLASH_COOKIE = "flash";
305
327
  const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
306
328
  function hasFlashCookie(cookieHeader) {
@@ -589,16 +611,18 @@ function setStyleProperty(node, name, value) {
589
611
  }
590
612
  function spread(node, props = {}, skipChildren) {
591
613
  const prevProps = {};
592
- if (!skipChildren) insert(node, () => props.children);
614
+ const get = typeof props === "function" ? props : () => props;
615
+ if (!skipChildren) insert(node, () => get().children);
593
616
  effect(() => {
594
- const r = props.ref;
617
+ const r = get().ref;
595
618
  (typeof r === "function" || Array.isArray(r)) && ref(() => r, node);
596
619
  }, () => {});
597
620
  effect(() => {
621
+ const source = get();
598
622
  const newProps = {};
599
- for (const prop in props) {
623
+ for (const prop in source) {
600
624
  if (prop === "children" || prop === "ref") continue;
601
- newProps[prop] = props[prop];
625
+ newProps[prop] = source[prop];
602
626
  }
603
627
  return newProps;
604
628
  }, props => assign(node, props, true, prevProps, true));
@@ -2092,6 +2116,7 @@ function isSafeError(value) {
2092
2116
  return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
2093
2117
  }
2094
2118
  const REVALIDATE_HEADER = "X-Revalidate";
2119
+ const RESPONSE_HEADER_VALUE_LIMIT = 4096;
2095
2120
  function initWithRevalidate(init = {}) {
2096
2121
  const resolved = typeof init === "number" ? {
2097
2122
  status: init
@@ -2112,7 +2137,13 @@ function initWithRevalidate(init = {}) {
2112
2137
  } else {
2113
2138
  headers = new Headers(responseInit.headers);
2114
2139
  }
2115
- revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
2140
+ if (revalidate !== undefined) {
2141
+ const keys = revalidate.toString();
2142
+ if (keys.length > RESPONSE_HEADER_VALUE_LIMIT) {
2143
+ throw new TypeError(`revalidate names ${keys.length} characters of cache keys; past ` + `${RESPONSE_HEADER_VALUE_LIMIT} the ${REVALIDATE_HEADER} header would overflow ` + `receivers (an 8 KiB proxy buffer holds the whole header block) and the response ` + `dies at the socket after the mutation committed. Split the invalidation across ` + `calls or use coarser keys — a dropped key would be a silently stale cache, so ` + `the runtime refuses rather than trims.`);
2144
+ }
2145
+ headers.set(REVALIDATE_HEADER, keys);
2146
+ }
2116
2147
  return {
2117
2148
  responseInit,
2118
2149
  headers
@@ -2130,7 +2161,12 @@ function redirect(url, init = 302) {
2130
2161
  responseInit.status = 302;
2131
2162
  }
2132
2163
  const target = typeof url === "string" ? url : url[HREF];
2133
- headers.set("Location", typeof target === "string" ? target : String(url));
2164
+ const location = typeof target === "string" ? target : String(url);
2165
+ const encoded = location.replace(/[^\x00-\x7f]/gu, encodeURIComponent);
2166
+ if (encoded.length > RESPONSE_HEADER_VALUE_LIMIT) {
2167
+ throw new TypeError(`redirect() target is ${encoded.length} characters; past ` + `${RESPONSE_HEADER_VALUE_LIMIT} the Location header (and the scripted transport's ` + `redirect header) would overflow receivers and the response dies at the socket. ` + `A target this size is usually unbounded input echoed into the url — carry the ` + `state server-side instead. Refused rather than trimmed: a cut target is a ` + `different address.`);
2168
+ }
2169
+ headers.set("Location", encoded);
2134
2170
  return new Response(null, {
2135
2171
  ...responseInit,
2136
2172
  headers
@@ -2146,11 +2182,18 @@ function reload(init = {}) {
2146
2182
  headers
2147
2183
  });
2148
2184
  }
2185
+ const NULL_BODY_STATUSES = new Set([204, 205, 304]);
2149
2186
  function respond(value, init = {}) {
2150
2187
  const {
2151
2188
  responseInit,
2152
2189
  headers
2153
2190
  } = initWithRevalidate(init);
2191
+ if (NULL_BODY_STATUSES.has(responseInit.status)) {
2192
+ return new ResponseEnvelope(new Response(null, {
2193
+ ...responseInit,
2194
+ headers
2195
+ }), value);
2196
+ }
2154
2197
  headers.set("Content-Type", "application/json");
2155
2198
  return new ResponseEnvelope(new Response(JSON.stringify(value), {
2156
2199
  ...responseInit,
@@ -2368,8 +2411,10 @@ exports.Dynamic = Dynamic;
2368
2411
  exports.HREF = HREF;
2369
2412
  exports.HydrationScript = HydrationScript;
2370
2413
  exports.MathMLElements = MathMLElements;
2414
+ exports.NULL_BODY_STATUSES = NULL_BODY_STATUSES;
2371
2415
  exports.Namespaces = Namespaces;
2372
2416
  exports.Portal = Portal;
2417
+ exports.RESPONSE_HEADER_VALUE_LIMIT = RESPONSE_HEADER_VALUE_LIMIT;
2373
2418
  exports.REVALIDATE_HEADER = REVALIDATE_HEADER;
2374
2419
  exports.RawTextElements = RawTextElements;
2375
2420
  exports.RequestContext = RequestContext;
package/dist/dev.js CHANGED
@@ -214,7 +214,8 @@ function resourceIdentity(tag, props) {
214
214
  let id = "res:" + tag + ":" + (props.rel || "") + ":" + (props.href || props.src || "");
215
215
  for (let i = 0; i < RESOURCE_QUALIFIERS.length; i++) {
216
216
  const q = RESOURCE_QUALIFIERS[i];
217
- if (props[q] != null) id += ":" + q + "=" + props[q];
217
+ const value = props[q];
218
+ if (value != null) id += ":" + q + "=" + (value === true ? "" : value);
218
219
  }
219
220
  return id;
220
221
  }
@@ -287,6 +288,7 @@ function decodeSafe(text) {
287
288
  }
288
289
  }
289
290
  function serializeCookie(name, value, options = {}) {
291
+ assertServableCookie(name, options);
290
292
  let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
291
293
  cookie += `; Path=${options.path === undefined ? "/" : options.path}`;
292
294
  if (options.domain) cookie += `; Domain=${options.domain}`;
@@ -294,12 +296,32 @@ function serializeCookie(name, value, options = {}) {
294
296
  if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
295
297
  if (options.httpOnly) cookie += "; HttpOnly";
296
298
  if (options.secure) cookie += "; Secure";
299
+ if (options.partitioned) cookie += "; Partitioned";
297
300
  if (options.sameSite) {
298
301
  const sameSite = options.sameSite.toLowerCase();
299
302
  cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
300
303
  }
301
304
  return cookie;
302
305
  }
306
+ function assertServableCookie(name, options) {
307
+ const reject = reason => {
308
+ throw new Error(`serializeCookie: every browser silently rejects this cookie — ${reason}. ` + `It would never come back on a request, with no error anywhere.`);
309
+ };
310
+ const lower = name.toLowerCase();
311
+ if (lower.startsWith("__host-")) {
312
+ if (!options.secure) reject(`the __Host- prefix on \`${name}\` requires \`secure: true\``);
313
+ if (options.path !== undefined && options.path !== "/") reject(`the __Host- prefix on \`${name}\` requires \`Path=/\` (got \`${options.path}\`) — ` + `host-locking is the prefix's whole contract, so it cannot be path-scoped`);
314
+ if (options.domain) reject(`the __Host- prefix on \`${name}\` forbids \`Domain\` (got \`${options.domain}\`)`);
315
+ } else if (lower.startsWith("__secure-") && !options.secure) {
316
+ reject(`the __Secure- prefix on \`${name}\` requires \`secure: true\``);
317
+ }
318
+ if (options.sameSite && options.sameSite.toLowerCase() === "none" && !options.secure) {
319
+ reject("`SameSite=None` requires `secure: true`");
320
+ }
321
+ if (options.partitioned && !options.secure) {
322
+ reject("`Partitioned` requires `secure: true`");
323
+ }
324
+ }
303
325
  const FLASH_COOKIE = "flash";
304
326
  const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
305
327
  function hasFlashCookie(cookieHeader) {
@@ -588,16 +610,18 @@ function setStyleProperty(node, name, value) {
588
610
  }
589
611
  function spread(node, props = {}, skipChildren) {
590
612
  const prevProps = {};
591
- if (!skipChildren) insert(node, () => props.children);
613
+ const get = typeof props === "function" ? props : () => props;
614
+ if (!skipChildren) insert(node, () => get().children);
592
615
  effect(() => {
593
- const r = props.ref;
616
+ const r = get().ref;
594
617
  (typeof r === "function" || Array.isArray(r)) && ref(() => r, node);
595
618
  }, () => {});
596
619
  effect(() => {
620
+ const source = get();
597
621
  const newProps = {};
598
- for (const prop in props) {
622
+ for (const prop in source) {
599
623
  if (prop === "children" || prop === "ref") continue;
600
- newProps[prop] = props[prop];
624
+ newProps[prop] = source[prop];
601
625
  }
602
626
  return newProps;
603
627
  }, props => assign(node, props, true, prevProps, true));
@@ -2091,6 +2115,7 @@ function isSafeError(value) {
2091
2115
  return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
2092
2116
  }
2093
2117
  const REVALIDATE_HEADER = "X-Revalidate";
2118
+ const RESPONSE_HEADER_VALUE_LIMIT = 4096;
2094
2119
  function initWithRevalidate(init = {}) {
2095
2120
  const resolved = typeof init === "number" ? {
2096
2121
  status: init
@@ -2111,7 +2136,13 @@ function initWithRevalidate(init = {}) {
2111
2136
  } else {
2112
2137
  headers = new Headers(responseInit.headers);
2113
2138
  }
2114
- revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
2139
+ if (revalidate !== undefined) {
2140
+ const keys = revalidate.toString();
2141
+ if (keys.length > RESPONSE_HEADER_VALUE_LIMIT) {
2142
+ throw new TypeError(`revalidate names ${keys.length} characters of cache keys; past ` + `${RESPONSE_HEADER_VALUE_LIMIT} the ${REVALIDATE_HEADER} header would overflow ` + `receivers (an 8 KiB proxy buffer holds the whole header block) and the response ` + `dies at the socket after the mutation committed. Split the invalidation across ` + `calls or use coarser keys — a dropped key would be a silently stale cache, so ` + `the runtime refuses rather than trims.`);
2143
+ }
2144
+ headers.set(REVALIDATE_HEADER, keys);
2145
+ }
2115
2146
  return {
2116
2147
  responseInit,
2117
2148
  headers
@@ -2129,7 +2160,12 @@ function redirect(url, init = 302) {
2129
2160
  responseInit.status = 302;
2130
2161
  }
2131
2162
  const target = typeof url === "string" ? url : url[HREF];
2132
- headers.set("Location", typeof target === "string" ? target : String(url));
2163
+ const location = typeof target === "string" ? target : String(url);
2164
+ const encoded = location.replace(/[^\x00-\x7f]/gu, encodeURIComponent);
2165
+ if (encoded.length > RESPONSE_HEADER_VALUE_LIMIT) {
2166
+ throw new TypeError(`redirect() target is ${encoded.length} characters; past ` + `${RESPONSE_HEADER_VALUE_LIMIT} the Location header (and the scripted transport's ` + `redirect header) would overflow receivers and the response dies at the socket. ` + `A target this size is usually unbounded input echoed into the url — carry the ` + `state server-side instead. Refused rather than trimmed: a cut target is a ` + `different address.`);
2167
+ }
2168
+ headers.set("Location", encoded);
2133
2169
  return new Response(null, {
2134
2170
  ...responseInit,
2135
2171
  headers
@@ -2145,11 +2181,18 @@ function reload(init = {}) {
2145
2181
  headers
2146
2182
  });
2147
2183
  }
2184
+ const NULL_BODY_STATUSES = new Set([204, 205, 304]);
2148
2185
  function respond(value, init = {}) {
2149
2186
  const {
2150
2187
  responseInit,
2151
2188
  headers
2152
2189
  } = initWithRevalidate(init);
2190
+ if (NULL_BODY_STATUSES.has(responseInit.status)) {
2191
+ return new ResponseEnvelope(new Response(null, {
2192
+ ...responseInit,
2193
+ headers
2194
+ }), value);
2195
+ }
2153
2196
  headers.set("Content-Type", "application/json");
2154
2197
  return new ResponseEnvelope(new Response(JSON.stringify(value), {
2155
2198
  ...responseInit,
@@ -2303,4 +2346,4 @@ _moduleUrl) {
2303
2346
  function httpStatus(_code, _text) {}
2304
2347
  function httpHeader(_name, _value, _options) {}
2305
2348
 
2306
- export { ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HREF, HydrationScript, MathMLElements, Namespaces, Portal, REVALIDATE_HEADER, RawTextElements, RequestContext, ResponseEnvelope, SAFE_ERROR, SVGElements, VoidElements, acquireAsset, addEvent, applyRef, assign, claimElement, claimElementTree, className, clearFlashCookie, clientOnly, commitEventResponse, composeMiddleware, createRequestEvent, createResponseStub, createSSRResponse, delegateEvents, driveList, dynamic, dynamicProperty, effect, escape, generateHydrationScript, getDelegatedRoot, getExpectedRedirectStatus, getFirstChild, getHydrationKey, getNextElement, getNextMarker, getNextMatch, getNextSibling, getRequestEvent, getServerFunctionMetadata, getServerFunctionRPC, hasFlashCookie, httpHeader, httpStatus, hydrate, insert, installHydrationRuntime, installListDriver, isDev, isHref, isResponseEnvelope, isSafeError, isServer, isServerFunction, listDriver, markSafeError, memo, parseCookieHeader, patchDriver, redirect, ref, registerDelegatedContainer, registerDelegatedRoot, registerElementClaim, reload, render, renderToStream, renderToString, resolveSSRNode, respond, rowProof, runHydrationEvents, scope, serializeCookie, setAttribute, setAttributeNS, setProperty, setStyleProperty, spread, ssr, ssrAttribute, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrStyle, ssrStyleProperty, style, template, unregisterDelegatedContainer, unregisterDelegatedRoot, useHead, waitAsset, warmAsset };
2349
+ export { ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HREF, HydrationScript, MathMLElements, NULL_BODY_STATUSES, Namespaces, Portal, RESPONSE_HEADER_VALUE_LIMIT, REVALIDATE_HEADER, RawTextElements, RequestContext, ResponseEnvelope, SAFE_ERROR, SVGElements, VoidElements, acquireAsset, addEvent, applyRef, assign, claimElement, claimElementTree, className, clearFlashCookie, clientOnly, commitEventResponse, composeMiddleware, createRequestEvent, createResponseStub, createSSRResponse, delegateEvents, driveList, dynamic, dynamicProperty, effect, escape, generateHydrationScript, getDelegatedRoot, getExpectedRedirectStatus, getFirstChild, getHydrationKey, getNextElement, getNextMarker, getNextMatch, getNextSibling, getRequestEvent, getServerFunctionMetadata, getServerFunctionRPC, hasFlashCookie, httpHeader, httpStatus, hydrate, insert, installHydrationRuntime, installListDriver, isDev, isHref, isResponseEnvelope, isSafeError, isServer, isServerFunction, listDriver, markSafeError, memo, parseCookieHeader, patchDriver, redirect, ref, registerDelegatedContainer, registerDelegatedRoot, registerElementClaim, reload, render, renderToStream, renderToString, resolveSSRNode, respond, rowProof, runHydrationEvents, scope, serializeCookie, setAttribute, setAttributeNS, setProperty, setStyleProperty, spread, ssr, ssrAttribute, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrStyle, ssrStyleProperty, style, template, unregisterDelegatedContainer, unregisterDelegatedRoot, useHead, waitAsset, warmAsset };