pnpm add @feelinglovelynow/svelte-catch
- Ease error handling in SvelteKit with functions to help with catching, parsing and logging errors
- Errors condense down to an array of strings that works nicely with @feelinglovelynow/toast
- Original error, formatted error, and stack trace is logged on error
log (data: any): void
import { log } from '@feelinglovelynow/svelte-catch'
log({ hello: 'world', foo: 'bar' })
- Terminal Output
---FLN LOG START---
{ hello: 'world', foo: 'bar' }
Trace
at Module.log (/Users/fln/@feelinglovelynow/svelte-catch/dist/log.js:6:13)
at load (/Users/fln/feelinglovelynow/src/routes/+layout.server.ts:18:27)
at Module.load_server_data (/Users/fln/feelinglovelynow/node_modules/.pnpm/@sveltejs+kit@1.27.6_svelte@4.2.3_vite@4.5.0/node_modules/@sveltejs/kit/src/runtime/server/page/load_data.js:57:41)
---FLN LOG END---
import { onMount } from 'svelte'
import { json } from '@sveltejs/kit'
import showToast from '@feelinglovelynow/toast'
import { SvelteCatch, enumCatchLocation } from '@feelinglovelynow/svelte-catch'
export function pageServerCatch (e: any) {
const svelteCatch = new SvelteCatch(enumCatchLocation.pageServer, 'We apologize, there is an error with this page. Please try again and/or <a href="/links">contact us</a>')
return svelteCatch.catch(e)
}
export function serverCatch (e: any) {
const svelteCatch = new SvelteCatch(enumCatchLocation.server, 'We apologize, there is an error with this request. Please try again and/or <a href="/links">contact us</a>')
return svelteCatch.catch(e, json)
}
export function routeCatch (data: any) {
if (data?._errors?.length) {
onMount(() => {
showToast('info', data._errors)
})
}
}
import { one } from '@feelinglovelynow/svelte-catch'
export const load = (async () => {
try {
throw one('hello world', { foo: 'bar' })
} catch (e) {
return pageServerCatch(e)
}
}) satisfies LayoutServerLoad
- Terminal Output
originalError
is the error that was recieved by the format error functionformattedError
is the error that will be returned to thefrontend
---FLN LOG START---
{
originalError: { _errors: [ 'hello world' ], _errorData: { foo: 'bar' } },
formattedError: { _errors: [ 'hello world' ] }
}
Trace
at Module.log (/Users/fln/@feelinglovelynow/svelte-catch/dist/log.js:6:13)
at SvelteCatch.catch (/Users/fln/@feelinglovelynow/svelte-catch/dist/SvelteCatch.js:18:35)
at Module.pageServerCatch (/Users/fln/feelinglovelynow/src/lib/global/catch.ts:11:27)
---FLN LOG END---
- Frontend that shows toast notification with the error
<script lang="ts">
import type { PageData } from './$types'
import { routeCatch } from '$lib/global/catch'
export let data: PageData
routeCatch(data)
</script>
many (_errors: string[], _errorData: any = undefined)
import { many } from '@feelinglovelynow/svelte-catch'
import { serverCatch } from '$lib/global/catch'
export const GET = (async () => {
try {
const errors = [{ message: 'foo' }, { message: 'bar' }] // example graphql error
const errorsAsArrayOfStrings = errors.map(e => e.message)
const errorData = JSON.stringify({ errors })
throw many(errorsAsArrayOfStrings, errorData)
} catch (e) {
return serverCatch(e)
}
}) satisfies RequestHandler
- Terminal Output
originalError
is the error that was recieved by the parserformattedError
is the error that will be returned to thefrontend
---FLN LOG START---
{
originalError: {
_errors: [ 'foo', 'bar' ],
_errorData: '{"errors":[{"message":"foo"},{"message":"bar"}]}'
},
formattedError: { _errors: [ 'foo', 'bar' ] }
}
Trace
at Module.log (/Users/fln/@feelinglovelynow/svelte-catch/dist/log.js:6:13)
at SvelteCatch.catch (/Users/fln/@feelinglovelynow/svelte-catch/dist/SvelteCatch.js:19:62)
at Module.serverCatch (/Users/fln/feelinglovelynow/src/lib/global/catch.ts:16:27)
---FLN LOG END---
- Frontend that shows toast notification with the error
<script lang="ts">
import type { PageData } from './$types'
import { routeCatch } from '$lib/global/catch'
export let data: PageData
routeCatch(data)
</script>
- Schema
import { z } from 'zod'
export const schemaSearch = z
.object({
isQuotesChecked: z.any().optional(), // allow .superRefine() to do the validation
isSourcesByTitleChecked: z.any().optional(), // allow .superRefine() to do the validation
isSourcesByDescriptionChecked: z.any().optional(), // allow .superRefine() to do the validation
query: z.string().min(3, 'Query is at least 3 characters please'),
})
.superRefine(({ isQuotesChecked, isSourcesByTitleChecked, isSourcesByDescriptionChecked }, ctx) => {
if (!isQuotesChecked && !isSourcesByTitleChecked && !isSourcesByDescriptionChecked) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Select atleast one checkbox please' })
})
export type SchemaSearch = z.infer<typeof schemaSearch>
- Server
import type { RequestHandler } from './$types'
import { serverCatch } from '$lib/global/catch'
import { schemaSearch, type SchemaSearch } from '$lib/zod/search'
export const POST = (async ({ request }) => {
try {
const body = (await request.json()) as SchemaSearch
schemaSearch.parse(body)
} catch (e) {
return serverCatch(e)
}
}) satisfies RequestHandler
- Response to Frontend
_errors
can be sent to @feelinglovelynow/toast
{
"_errors":[
"Select atleast one checkbox please"
],
"query":{
"_errors":[
"Query is at least 3 characters please"
]
}
}
import { redirect } from '@sveltejs/kit'
import type { PageServerLoad } from './$types'
import { pageServerCatch } from '$lib/global/catch'
export const load = (async ({ locals }) => {
try {
if (!locals.userUid) throw redirect(302, '/auth/sign-in')
} catch (e) {
return pageServerCatch(e)
}
}) satisfies PageServerLoad
formattedError
is the error that will be returned to thefrontend
- IF
_errorData
is in the throw we do not return_errorData
to the frontend but_errorData
is logged in the terminal
throw 'hello world' // IF e is strng => we put string into array
formattedError: { _errors: [ 'hello world' ] }
throw new Error('foo') // IF e.message found => we put e.message into array
formattedError: { _errors: [ 'foo' ] }
throw { format: () => ({ foo: 'bar' }) } // IF e.format() found => formattedError is the response from e.format()
formattedError: { foo: 'bar' }
throw null // IF !e => formattedError is the default error set above @ pageServerCatch or serverCatch
formattedError: {
_errors: [
'We apologize, there is an error with this page. Please try again and/or <a href="/links">contact us</a>'
]
}
throw { _errors: [ 'hello', 'world' ], foo: 'bar' } // IF _errors array found => no parsing done
formattedError: { _errors: [ 'hello', 'world' ], foo: 'bar' }
throw { message: 'hello world' } // IF e.message found => we put e.message into array
formattedError: { _errors: [ 'hello world' ] }
- @feelinglovelynow/dgraph: NPM β Github
- @feelinglovelynow/env-write: NPM β Github
- @feelinglovelynow/get-form-entries: NPM β Github
- @feelinglovelynow/get-relative-time: NPM β Github
- @feelinglovelynow/global-style: NPM β Github
- @feelinglovelynow/jwt: NPM β Github
- @feelinglovelynow/loop-backwards: NPM β Github
- @feelinglovelynow/slug: NPM β Github
- @feelinglovelynow/svelte-catch: NPM β Github
- @feelinglovelynow/svelte-kv: NPM β Github
- @feelinglovelynow/svelte-loading-anchor: NPM β Github
- @feelinglovelynow/svelte-modal: NPM β Github
- @feelinglovelynow/svelte-turnstile: NPM β Github
- @feelinglovelynow/toast: NPM β Github