@solidjs/router 0.10.9 → 0.10.10

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.
@@ -1,7 +1,7 @@
1
1
  import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
2
2
  import { isServer } from "solid-js/web";
3
3
  import { useRouter } from "../routing";
4
- import { redirectStatusCodes } from "../utils";
4
+ import { redirectStatusCodes, mockBase } from "../utils";
5
5
  import { cacheKeyOp, hashKey, revalidate } from "./cache";
6
6
  export const actions = /* #__PURE__ */ new Map();
7
7
  export function useSubmissions(fn, filter) {
@@ -80,7 +80,7 @@ function toAction(fn, url) {
80
80
  const newFn = function (...passedArgs) {
81
81
  return fn.call(this, ...args, ...passedArgs);
82
82
  };
83
- const uri = new URL(url, "http://sar");
83
+ const uri = new URL(url, mockBase);
84
84
  uri.searchParams.set("args", hashKey(args));
85
85
  return toAction(newFn, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search);
86
86
  };
@@ -48,6 +48,9 @@ function revalidateSignals(set, time) {
48
48
  }
49
49
  export function cache(fn, name, options) {
50
50
  const [store, setStore] = createStore({});
51
+ // prioritize GET for server functions
52
+ if (fn.GET)
53
+ fn = fn.GET;
51
54
  const cachedFn = ((...args) => {
52
55
  const cache = getCache();
53
56
  const intent = getIntent();
@@ -75,7 +78,9 @@ export function cache(fn, name, options) {
75
78
  "then" in cached[1]
76
79
  ? cached[1].then(handleResponse(false), handleResponse(true))
77
80
  : handleResponse(false)(cached[1]);
78
- !isServer && intent === "navigate" && startTransition(() => revalidateSignals(cached[3], cached[0])); // update version
81
+ !isServer &&
82
+ intent === "navigate" &&
83
+ startTransition(() => revalidateSignals(cached[3], cached[0])); // update version
79
84
  }
80
85
  return res;
81
86
  }
@@ -106,22 +111,26 @@ export function cache(fn, name, options) {
106
111
  }
107
112
  return res;
108
113
  function handleResponse(error) {
109
- return (v) => {
110
- if (v instanceof Response && redirectStatusCodes.has(v.status)) {
111
- if (navigate) {
112
- startTransition(() => {
113
- let url = v.headers.get(LocationHeader);
114
- if (url && url.startsWith("/")) {
115
- navigate(url, {
116
- replace: true
117
- });
118
- }
119
- else if (!isServer && url) {
120
- window.location.href = url;
121
- }
122
- });
114
+ return async (v) => {
115
+ if (v instanceof Response) {
116
+ if (redirectStatusCodes.has(v.status)) {
117
+ if (navigate) {
118
+ startTransition(() => {
119
+ let url = v.headers.get(LocationHeader);
120
+ if (url && url.startsWith("/")) {
121
+ navigate(url, {
122
+ replace: true
123
+ });
124
+ }
125
+ else if (!isServer && url) {
126
+ window.location.href = url;
127
+ }
128
+ });
129
+ }
130
+ return;
123
131
  }
124
- return;
132
+ if (v.customBody)
133
+ v = await v.customBody();
125
134
  }
126
135
  if (error)
127
136
  throw v;
@@ -1,6 +1,7 @@
1
1
  import { delegateEvents } from "solid-js/web";
2
2
  import { onCleanup } from "solid-js";
3
3
  import { actions } from "./action";
4
+ import { mockBase } from "../utils";
4
5
  export function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "/_server") {
5
6
  return (router) => {
6
7
  const basePath = router.base.path();
@@ -20,7 +21,7 @@ export function setupNativeEvents(preload = true, explicitLinks = false, actionB
20
21
  const a = evt
21
22
  .composedPath()
22
23
  .find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
23
- if (!a || (explicitLinks && !a.getAttribute("link")))
24
+ if (!a || (explicitLinks && !a.hasAttribute("link")))
24
25
  return;
25
26
  const svg = isSvg(a);
26
27
  const href = svg ? a.href.baseVal : a.href;
@@ -83,12 +84,13 @@ export function setupNativeEvents(preload = true, explicitLinks = false, actionB
83
84
  }
84
85
  function handleFormSubmit(evt) {
85
86
  let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction")
86
- ? evt.submitter.formAction
87
- : evt.target.action;
87
+ ? evt.submitter.getAttribute("formaction")
88
+ : evt.target.getAttribute("action");
88
89
  if (!actionRef)
89
90
  return;
90
91
  if (!actionRef.startsWith("https://action/")) {
91
- const url = new URL(actionRef);
92
+ // normalize server actions
93
+ const url = new URL(actionRef, mockBase);
92
94
  actionRef = router.parsePath(url.pathname + url.search);
93
95
  if (!actionRef.startsWith(actionBase))
94
96
  return;
@@ -1,4 +1,4 @@
1
1
  export { createAsync } from "./createAsync";
2
2
  export { action, useSubmission, useSubmissions, useAction, type Action } from "./action";
3
3
  export { cache, revalidate, type CachedFunction } from "./cache";
4
- export { redirect, reload } from "./response";
4
+ export { redirect, reload, json } from "./response";
@@ -1,4 +1,4 @@
1
1
  export { createAsync } from "./createAsync";
2
2
  export { action, useSubmission, useSubmissions, useAction } from "./action";
3
3
  export { cache, revalidate } from "./cache";
4
- export { redirect, reload } from "./response";
4
+ export { redirect, reload, json } from "./response";
@@ -1,5 +1,6 @@
1
1
  export type RouterResponseInit = ResponseInit & {
2
2
  revalidate?: string | string[];
3
3
  };
4
- export declare function redirect(url: string, init?: number | RouterResponseInit): Response;
5
- export declare function reload(init: RouterResponseInit): Response;
4
+ export declare function redirect(url: string, init?: number | RouterResponseInit): never;
5
+ export declare function reload(init: RouterResponseInit): never;
6
+ export declare function json<T>(data: T, init?: Omit<ResponseInit, "body">): T;
@@ -23,6 +23,18 @@ export function reload(init) {
23
23
  const { revalidate, ...responseInit } = init;
24
24
  return new Response(null, {
25
25
  ...responseInit,
26
- ...(revalidate ? { headers: new Headers(responseInit.headers).set("X-Revalidate", revalidate.toString()) } : {})
26
+ ...(revalidate
27
+ ? { headers: new Headers(responseInit.headers).set("X-Revalidate", revalidate.toString()) }
28
+ : {})
27
29
  });
28
30
  }
31
+ export function json(data, init) {
32
+ const headers = new Headers((init || {}).headers);
33
+ headers.set("Content-Type", "application/json");
34
+ const response = new Response(JSON.stringify(data), {
35
+ ...init,
36
+ headers
37
+ });
38
+ response.customBody = () => data;
39
+ return response;
40
+ }
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ function createBeforeLeave() {
38
38
 
39
39
  const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
40
40
  const trimPathRegex = /^\/+|(\/)\/+$/g;
41
+ const mockBase = "http://sr";
41
42
  const redirectStatusCodes = new Set([204, 301, 302, 303, 307, 308]);
42
43
  function normalizePath(path, omitSlash = false) {
43
44
  const s = path.replace(trimPathRegex, "$1");
@@ -327,7 +328,7 @@ function getRouteMatches(branches, location) {
327
328
  return [];
328
329
  }
329
330
  function createLocation(path, state) {
330
- const origin = new URL("http://sar");
331
+ const origin = new URL(mockBase);
331
332
  const url = createMemo(prev => {
332
333
  const path_ = path();
333
334
  try {
@@ -812,6 +813,8 @@ function revalidateSignals(set, time) {
812
813
  }
813
814
  function cache(fn, name, options) {
814
815
  const [store, setStore] = createStore({});
816
+ // prioritize GET for server functions
817
+ if (fn.GET) fn = fn.GET;
815
818
  const cachedFn = (...args) => {
816
819
  const cache = getCache();
817
820
  const intent = getIntent();
@@ -865,21 +868,24 @@ function cache(fn, name, options) {
865
868
  }
866
869
  return res;
867
870
  function handleResponse(error) {
868
- return v => {
869
- if (v instanceof Response && redirectStatusCodes.has(v.status)) {
870
- if (navigate) {
871
- startTransition(() => {
872
- let url = v.headers.get(LocationHeader);
873
- if (url && url.startsWith("/")) {
874
- navigate(url, {
875
- replace: true
876
- });
877
- } else if (!isServer && url) {
878
- window.location.href = url;
879
- }
880
- });
871
+ return async v => {
872
+ if (v instanceof Response) {
873
+ if (redirectStatusCodes.has(v.status)) {
874
+ if (navigate) {
875
+ startTransition(() => {
876
+ let url = v.headers.get(LocationHeader);
877
+ if (url && url.startsWith("/")) {
878
+ navigate(url, {
879
+ replace: true
880
+ });
881
+ } else if (!isServer && url) {
882
+ window.location.href = url;
883
+ }
884
+ });
885
+ }
886
+ return;
881
887
  }
882
- return;
888
+ if (v.customBody) v = await v.customBody();
883
889
  }
884
890
  if (error) throw v;
885
891
  if (isServer) return v;
@@ -1003,7 +1009,7 @@ function toAction(fn, url) {
1003
1009
  const newFn = function (...passedArgs) {
1004
1010
  return fn.call(this, ...args, ...passedArgs);
1005
1011
  };
1006
- const uri = new URL(url, "http://sar");
1012
+ const uri = new URL(url, mockBase);
1007
1013
  uri.searchParams.set("args", hashKey(args));
1008
1014
  return toAction(newFn, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search);
1009
1015
  };
@@ -1048,7 +1054,7 @@ function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "
1048
1054
  function handleAnchor(evt) {
1049
1055
  if (evt.defaultPrevented || evt.button !== 0 || evt.metaKey || evt.altKey || evt.ctrlKey || evt.shiftKey) return;
1050
1056
  const a = evt.composedPath().find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
1051
- if (!a || explicitLinks && !a.getAttribute("link")) return;
1057
+ if (!a || explicitLinks && !a.hasAttribute("link")) return;
1052
1058
  const svg = isSvg(a);
1053
1059
  const href = svg ? a.href.baseVal : a.href;
1054
1060
  const target = svg ? a.target.baseVal : a.target;
@@ -1099,10 +1105,11 @@ function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "
1099
1105
  }
1100
1106
  }
1101
1107
  function handleFormSubmit(evt) {
1102
- let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction") ? evt.submitter.formAction : evt.target.action;
1108
+ let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction") ? evt.submitter.getAttribute("formaction") : evt.target.getAttribute("action");
1103
1109
  if (!actionRef) return;
1104
1110
  if (!actionRef.startsWith("https://action/")) {
1105
- const url = new URL(actionRef);
1111
+ // normalize server actions
1112
+ const url = new URL(actionRef, mockBase);
1106
1113
  actionRef = router.parsePath(url.pathname + url.search);
1107
1114
  if (!actionRef.startsWith(actionBase)) return;
1108
1115
  }
@@ -1412,5 +1419,15 @@ function reload(init) {
1412
1419
  } : {})
1413
1420
  });
1414
1421
  }
1422
+ function json(data, init) {
1423
+ const headers = new Headers((init || {}).headers);
1424
+ headers.set("Content-Type", "application/json");
1425
+ const response = new Response(JSON.stringify(data), {
1426
+ ...init,
1427
+ headers
1428
+ });
1429
+ response.customBody = () => data;
1430
+ return response;
1431
+ }
1415
1432
 
1416
- export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createMemoryHistory, createRouter, redirect, reload, revalidate, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
1433
+ export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createMemoryHistory, createRouter, json, redirect, reload, revalidate, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
package/dist/routing.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, startTransition, resetErrorBoundaries } from "solid-js";
2
2
  import { isServer, getRequestEvent } from "solid-js/web";
3
3
  import { createBeforeLeave } from "./lifecycle";
4
- import { createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, expandOptionals } from "./utils";
4
+ import { mockBase, createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, expandOptionals } from "./utils";
5
5
  const MAX_REDIRECTS = 100;
6
6
  export const RouterContextObj = createContext();
7
7
  export const RouteContextObj = createContext();
@@ -140,7 +140,7 @@ export function getRouteMatches(branches, location) {
140
140
  return [];
141
141
  }
142
142
  export function createLocation(path, state) {
143
- const origin = new URL("http://sar");
143
+ const origin = new URL(mockBase);
144
144
  const url = createMemo(prev => {
145
145
  const path_ = path();
146
146
  try {
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { MatchFilters, Params, PathMatch, Route, SetParams } from "./types";
2
+ export declare const mockBase = "http://sr";
2
3
  export declare const redirectStatusCodes: Set<number>;
3
4
  export declare function normalizePath(path: string, omitSlash?: boolean): string;
4
5
  export declare function resolvePath(base: string, path: string, from?: string): string | undefined;
package/dist/utils.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createMemo, getOwner, runWithOwner } from "solid-js";
2
2
  const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
3
3
  const trimPathRegex = /^\/+|(\/)\/+$/g;
4
+ export const mockBase = "http://sr";
4
5
  export const redirectStatusCodes = new Set([204, 301, 302, 303, 307, 308]);
5
6
  export function normalizePath(path, omitSlash = false) {
6
7
  const s = path.replace(trimPathRegex, "$1");
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "0.10.9",
9
+ "version": "0.10.10",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",