nitro-web 0.0.164 → 0.0.165

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/client/app.tsx CHANGED
@@ -38,6 +38,9 @@ type RouteWithPolicies = Route & {
38
38
  [key: string]: true | string | (string | true)[]
39
39
  }
40
40
 
41
+ let lastRedirectUrl = ''
42
+ let lastRedirectTimesForSameUrl: number[] = []
43
+
41
44
  export async function setupApp(config: Config, storeContainer: StoreContainer, layouts: React.FC<LayoutProps>[]) {
42
45
  if (!layouts) throw new Error('layouts are required')
43
46
  if (!(window as unknown as { useTracked: unknown }).useTracked) {
@@ -207,7 +210,8 @@ function getRouter({ settings, config }: { settings: Settings, config: Config })
207
210
  <RouteComponent route={route} config={config} />
208
211
  ),
209
212
  path: route.path,
210
- loader: async () => { // request
213
+ loader: async ({ request }: { request: Request }) => { // request
214
+ catchRedirectLoop(request, route.name)
211
215
  // wait for container/exposedStoreData to be setup (note that this causes ReactRouter to re-render, but not the page)
212
216
  if (!nonce) {
213
217
  nonce = true
@@ -216,7 +220,13 @@ function getRouter({ settings, config }: { settings: Settings, config: Config })
216
220
  for (const key of route.middleware) {
217
221
  const error = settings.middleware[key](route, exposedStoreData || {})
218
222
  if (error && error.redirect) {
219
- return redirect(error.redirect)
223
+ // Redirect() will use the new pathname instead of the current one for values without a pathname causing guard
224
+ // redirect loops! We assume these query string redirects are intended to be relative to the current path.
225
+ if (error.redirect.startsWith('?')) {
226
+ return redirect(window.location.pathname + error.redirect)
227
+ } else {
228
+ return redirect(error.redirect)
229
+ }
220
230
  }
221
231
  }
222
232
  return null
@@ -269,6 +279,22 @@ function scrollbarElement() {
269
279
  return document.getElementById('app') // was window.scrollY
270
280
  }
271
281
 
282
+ function catchRedirectLoop(request: Request, routeName: string) {
283
+ if (request.url === lastRedirectUrl) {
284
+ const lastRedirectTime = lastRedirectTimesForSameUrl[lastRedirectTimesForSameUrl.length - 1] || 0
285
+ lastRedirectUrl = request.url
286
+ lastRedirectTimesForSameUrl.push(Date.now())
287
+ if (lastRedirectTimesForSameUrl.length > 5 && (Date.now() < lastRedirectTime + 100)) {
288
+ throw new Error(
289
+ `Nitro: A redirect loop has been detected for route '${routeName}'. This ismost likely due to a redirect loop caused by your middleware.`
290
+ )
291
+ }
292
+ } else {
293
+ lastRedirectUrl = request.url
294
+ lastRedirectTimesForSameUrl = []
295
+ }
296
+ }
297
+
272
298
  // ---- Overridable defaults ------------
273
299
 
274
300
  async function beforeApp(config: Config) {
@@ -115,7 +115,7 @@ export function Message({ className, classNameWrapper, icons: iconsProp, positio
115
115
  if (Array.isArray(query[key])) continue
116
116
  const rawQueryValue = query[key] as string
117
117
 
118
- if (rawQueryValue.match(/=$/) && !isFirstRender) {
118
+ if (rawQueryValue.match(/~$/) && !isFirstRender) {
119
119
  // Only show if first render, otherwise skip internal tracking of the message
120
120
  continue
121
121
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.164",
3
+ "version": "0.0.165",
4
4
  "repository": "github:boycce/nitro-web",
5
5
  "homepage": "https://boycce.github.io/nitro-web/",
6
6
  "description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",