diff --git a/.gitignore b/.gitignore index d79e7a25e..2e69639ed 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,8 @@ .env .env.* !.env.example +!/content/tutorial/04-advanced-sveltekit/06-environment-variables/**/.env .apps .vercel /content/tutorial/common/.svelte-kit -/content/tutorial/common/node_modules -/content/tutorial/common/package-lock.json +/content/tutorial/common/node_modules \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 5a5649779..810dc1f2c 100644 --- a/.prettierrc +++ b/.prettierrc @@ -7,9 +7,15 @@ { "files": ["content/**/*.svelte"], "options": { - "printWidth": 50, + "printWidth": 70, "requirePragma": true } + }, + { + "files": ["content/**/*.js"], + "options": { + "printWidth": 70 + } } ] } diff --git a/README.md b/README.md index 87c27566b..db85c2ead 100644 --- a/README.md +++ b/README.md @@ -24,4 +24,4 @@ The next steps depend on whether you want to run this locally in filesystem mode ## Creating new tutorials -Tutorials live inside `content`. Each tutorial consists of a `README.md`, which is the text to the left, and `app-a` and `app-b` folders, which represent the initial and solved state. Files that stay the same can be omitted from `app-b`. Files are marked as deleted in `app-b` if they start with `__delete`. Folders that are marked as deleted in `app-b` if they contain a file named `__delete`. Folders that contain a file named `__hidden` are not visible in the file tree. +Tutorials live inside `content`. Each tutorial consists of a `README.md`, which is the text to the left, and `app-a` and `app-b` folders, which represent the initial and solved state. Files that stay the same can be omitted from `app-b`. Files are marked as deleted in `app-b` if they start with `__delete`. Folders that are marked as deleted in `app-b` if they contain a file named `__delete`. diff --git a/content/tutorial/01-svelte/01-introduction/01-welcome-to-svelte/README.md b/content/tutorial/01-svelte/01-introduction/01-welcome-to-svelte/README.md index 334208c98..b2447d72f 100644 --- a/content/tutorial/01-svelte/01-introduction/01-welcome-to-svelte/README.md +++ b/content/tutorial/01-svelte/01-introduction/01-welcome-to-svelte/README.md @@ -2,8 +2,6 @@ title: Welcome to Svelte --- -> WARNING: this content is a work in progress and may be out of date. If you are learning Svelte, please refer to the [tutorial on svelte.dev](https://svelte.dev/tutorial) for now. If you are learning SvelteKit, refer to the [SvelteKit docs](https://kit.svelte.dev/docs). - Welcome to the Svelte tutorial! This will teach you everything you need to know to easily build fast, small web applications. You can also consult the [API docs](https://svelte.dev/docs) and the [examples](https://svelte.dev/examples), or — if you're impatient to start hacking on your machine locally — create a project with `npm init svelte`. @@ -25,8 +23,8 @@ This tutorial is split into four main parts: - [Welcome to Svelte](/tutorial/welcome-to-svelte) (you are here) - [Introduction to SvelteKit](/tutorial/introducing-sveltekit) - [Advanced Svelte](/tutorial/tweens) -- [Advanced SvelteKit](/tutorial/sandbox) +- [Advanced SvelteKit](/tutorial/optional-params) -Each section will present an exercise designed to illustrate a feature. Later sections build on the knowledge gained in earlier ones, so it's recommended that you go from start to finish. If necessary, you can navigate via the menu above. +Each section will present an exercise designed to illustrate a feature. Later exercises build on the knowledge gained in earlier ones, so it's recommended that you go from start to finish. If necessary, you can navigate via the menu above. If you get stuck, you can click the `solve` button to the left of the editor. (It's disabled on sections like this one that don't include an exercise.) Try not to rely on it too much; you will learn faster by figuring out where to put each suggested code block and manually typing it in to the editor. diff --git a/content/tutorial/02-sveltekit/01-concepts/01-introducing-sveltekit/README.md b/content/tutorial/02-sveltekit/01-concepts/01-introducing-sveltekit/README.md index 500297f91..077f9fdaf 100644 --- a/content/tutorial/02-sveltekit/01-concepts/01-introducing-sveltekit/README.md +++ b/content/tutorial/02-sveltekit/01-concepts/01-introducing-sveltekit/README.md @@ -2,8 +2,6 @@ title: What is SvelteKit? --- -> WARNING: this content is a work in progress and is not up to date with breaking changes in the latest version of SvelteKit. For the latest information, refer to the [SvelteKit docs](https://kit.svelte.dev/docs). - So far, we've been working on individual components, or groups of components, in isolation. But to build a complete app, you need more than just components. That's where SvelteKit comes in. Whereas Svelte is a _component framework_, SvelteKit is an _app framework_ (or 'metaframework', depending on who you ask) that solves the tricky problems of building something production-ready: @@ -20,6 +18,6 @@ That's where SvelteKit comes in. Whereas Svelte is a _component framework_, Svel - Deploying to different hosting providers - ...and so on -It also provides a world-class development experience powered by [Vite](https://vitejs.dev). SvelteKit apps are server-rendered by default (like traditional 'multi-page apps' or MPAs) for excellent first load performance and SEO characteristics, but can then transition to client-side navigation (like modern 'single-page apps' or SPAs) to avoid jankily reloading everything (including things like third-party analytics code) when the user navigates. They can run anywhere JavaScript runs, though — as we'll see — your users may not need to run any JavaScript at all. +SvelteKit apps are server-rendered by default (like traditional 'multi-page apps' or MPAs) for excellent first load performance and SEO characteristics, but can then transition to client-side navigation (like modern 'single-page apps' or SPAs) to avoid jankily reloading everything (including things like third-party analytics code) when the user navigates. They can run anywhere JavaScript runs, though — as we'll see — your users may not need to run any JavaScript at all. If that sounds complicated, worry not: you've been using SvelteKit this whole time! diff --git a/content/tutorial/02-sveltekit/01-concepts/02-project-structure/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/01-concepts/02-project-structure/app-a/src/routes/+page.svelte deleted file mode 100644 index fa17b223d..000000000 --- a/content/tutorial/02-sveltekit/01-concepts/02-project-structure/app-a/src/routes/+page.svelte +++ /dev/null @@ -1 +0,0 @@ -

Welcome to SvelteKit

diff --git a/content/tutorial/02-sveltekit/01-concepts/03-server-and-client/README.md b/content/tutorial/02-sveltekit/01-concepts/03-server-and-client/README.md index feb6bb0c7..e9b409b79 100644 --- a/content/tutorial/02-sveltekit/01-concepts/03-server-and-client/README.md +++ b/content/tutorial/02-sveltekit/01-concepts/03-server-and-client/README.md @@ -8,4 +8,6 @@ A SvelteKit app can be thought of as two distinct entities working in tandem — 'Client' refers to the JavaScript that loads in the browser. -TODO +SvelteKit makes the two communicate with each other seamlessly. On the initial page load, the server renders the HTML, meaning content is visible as quickly as possible. The client then takes over in a process called 'hydration', so that subsequent navigations happen without full page reloads. It will request additional code and data from the server as needed. + +> You can [adjust this behavior](https://kit.svelte.dev/docs/page-options) as needed. SvelteKit is very versatile! diff --git a/content/tutorial/02-sveltekit/01-concepts/03-server-and-client/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/01-concepts/03-server-and-client/app-a/src/routes/+page.svelte deleted file mode 100644 index 5033c31fc..000000000 --- a/content/tutorial/02-sveltekit/01-concepts/03-server-and-client/app-a/src/routes/+page.svelte +++ /dev/null @@ -1 +0,0 @@ -

todo

diff --git a/content/tutorial/02-sveltekit/01-concepts/04-server-side-rendering/README.md b/content/tutorial/02-sveltekit/01-concepts/04-server-side-rendering/README.md deleted file mode 100644 index e5046f007..000000000 --- a/content/tutorial/02-sveltekit/01-concepts/04-server-side-rendering/README.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Server-side rendering ---- - -TODO diff --git a/content/tutorial/02-sveltekit/01-concepts/04-server-side-rendering/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/01-concepts/04-server-side-rendering/app-a/src/routes/+page.svelte deleted file mode 100644 index 5033c31fc..000000000 --- a/content/tutorial/02-sveltekit/01-concepts/04-server-side-rendering/app-a/src/routes/+page.svelte +++ /dev/null @@ -1 +0,0 @@ -

todo

diff --git a/content/tutorial/02-sveltekit/01-concepts/05-prerendering/README.md b/content/tutorial/02-sveltekit/01-concepts/05-prerendering/README.md deleted file mode 100644 index 8e98db599..000000000 --- a/content/tutorial/02-sveltekit/01-concepts/05-prerendering/README.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prerendering ---- - -TODO diff --git a/content/tutorial/02-sveltekit/01-concepts/05-prerendering/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/01-concepts/05-prerendering/app-a/src/routes/+page.svelte deleted file mode 100644 index 5033c31fc..000000000 --- a/content/tutorial/02-sveltekit/01-concepts/05-prerendering/app-a/src/routes/+page.svelte +++ /dev/null @@ -1 +0,0 @@ -

todo

diff --git a/content/tutorial/02-sveltekit/02-routing/01-pages/README.md b/content/tutorial/02-sveltekit/02-routing/01-pages/README.md index 57eae033f..d7f921b47 100644 --- a/content/tutorial/02-sveltekit/02-routing/01-pages/README.md +++ b/content/tutorial/02-sveltekit/02-routing/01-pages/README.md @@ -4,13 +4,23 @@ title: Pages SvelteKit uses filesystem-based routing, which means that the _routes_ of your app — in other words, what the app should do when a user navigates to a particular URL — are defined by the directories in your codebase. -In this app we have two routes — `src/routes/+page.svelte`, which maps to `/`, and `src/routes/about/+page.svelte`, which maps to `/about`. Clicking the `about` link will take you from the home page to the about page. +The routes are located within `src/routes`. Every directory within which contains a `+page.svelte` file creates a route in your app. -> Unlike traditional multi-page apps, navigating to `/about` updates the contents of the current page, like a single-page app. This gives us the best of both worlds — fast server-rendered startup, then instant navigation. +In this app we currently have one route — `src/routes/+page.svelte`, which maps to `/`. -Let's add a link in `src/routes/about/+page.svelte` back to the homepage: +Let's add a second route, `src/routes/about/+page.svelte`, which maps to `/about`: ```svelte +/// file: src/routes/about/+page.svelte + + +

About

This is the about page.

-

Go to the ++++++home++++++ page

``` + +We can now navigate between `/` and `/about`. + +> Unlike traditional multi-page apps, navigating to `/about` and back updates the contents of the current page, like a single-page app. This gives us the best of both worlds — fast server-rendered startup, then instant navigation. (This behaviour can be [configured](https://kit.svelte.dev/docs/page-options).) diff --git a/content/tutorial/02-sveltekit/02-routing/01-pages/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/02-routing/01-pages/app-a/src/routes/+page.svelte index fbb0f5613..60f6c57b7 100644 --- a/content/tutorial/02-sveltekit/02-routing/01-pages/app-a/src/routes/+page.svelte +++ b/content/tutorial/02-sveltekit/02-routing/01-pages/app-a/src/routes/+page.svelte @@ -1,4 +1,7 @@ -

Home

+ +

Home

This is the home page.

-

Go to the about page.

diff --git a/content/tutorial/02-sveltekit/02-routing/01-pages/app-b/src/routes/about/+page.svelte b/content/tutorial/02-sveltekit/02-routing/01-pages/app-b/src/routes/about/+page.svelte index 9a753d3d0..43ce718a3 100644 --- a/content/tutorial/02-sveltekit/02-routing/01-pages/app-b/src/routes/about/+page.svelte +++ b/content/tutorial/02-sveltekit/02-routing/01-pages/app-b/src/routes/about/+page.svelte @@ -1,4 +1,7 @@ -

About

+ +

About

This is the about page.

-

Go to the home page

diff --git a/content/tutorial/02-sveltekit/02-routing/02-endpoints/README.md b/content/tutorial/02-sveltekit/02-routing/02-endpoints/README.md deleted file mode 100644 index 62a7c7d07..000000000 --- a/content/tutorial/02-sveltekit/02-routing/02-endpoints/README.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Endpoints ---- - -TODO diff --git a/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-a/src/routes/+page.svelte deleted file mode 100644 index fbb0f5613..000000000 --- a/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-a/src/routes/+page.svelte +++ /dev/null @@ -1,4 +0,0 @@ -

Home

- -

This is the home page.

-

Go to the about page.

diff --git a/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-a/src/routes/about/+page.svelte b/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-a/src/routes/about/+page.svelte deleted file mode 100644 index b74a0b67c..000000000 --- a/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-a/src/routes/about/+page.svelte +++ /dev/null @@ -1,4 +0,0 @@ -

About

- -

This is the about page.

-

Go to the home page

diff --git a/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-b/src/routes/about/+page.svelte b/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-b/src/routes/about/+page.svelte deleted file mode 100644 index 9a753d3d0..000000000 --- a/content/tutorial/02-sveltekit/02-routing/02-endpoints/app-b/src/routes/about/+page.svelte +++ /dev/null @@ -1,4 +0,0 @@ -

About

- -

This is the about page.

-

Go to the home page

diff --git a/content/tutorial/02-sveltekit/02-routing/02-layouts/README.md b/content/tutorial/02-sveltekit/02-routing/02-layouts/README.md new file mode 100644 index 000000000..fa885e194 --- /dev/null +++ b/content/tutorial/02-sveltekit/02-routing/02-layouts/README.md @@ -0,0 +1,29 @@ +--- +title: Layouts +--- + +Different routes of your app will often share common UI. Instead of repeating it in each `+page.svelte` component, we can use a `+layout.svelte` component that applies to all routes in the same directory. + +In this app we have two routes, `src/routes/+page.svelte` and `src/routes/about/+page.svelte`, that contain the same navigation UI. Let's create a new file, `src/routes/+layout.svelte`... + +```diff +src/routes/ +├ about/ +│ └ +page.svelte ++├ +layout.svelte +└ +page.svelte +``` + +...and move the duplicated content from the `+page.svelte` files into the new `+layout.svelte` file. The `` element is where the page content will be rendered: + +```svelte +/// file: src/routes/about/+page.svelte + + + +``` + +A `+layout.svelte` file applies to every child route, including the sibling `+page.svelte` (if it exists). You can nest layouts to arbitrary depth. diff --git a/content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/+layout.svelte b/content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/+layout.svelte new file mode 100644 index 000000000..8a38e3a9a --- /dev/null +++ b/content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/+layout.svelte @@ -0,0 +1,6 @@ + + + diff --git a/content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/+page.svelte b/content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..d48a73513 --- /dev/null +++ b/content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/+page.svelte @@ -0,0 +1,2 @@ +

Home

+

This is the home page.

diff --git a/content/tutorial/02-sveltekit/02-routing/01-pages/app-a/src/routes/about/+page.svelte b/content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/about/+page.svelte similarity index 62% rename from content/tutorial/02-sveltekit/02-routing/01-pages/app-a/src/routes/about/+page.svelte rename to content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/about/+page.svelte index b74a0b67c..f4692177f 100644 --- a/content/tutorial/02-sveltekit/02-routing/01-pages/app-a/src/routes/about/+page.svelte +++ b/content/tutorial/02-sveltekit/02-routing/02-layouts/app-b/src/routes/about/+page.svelte @@ -1,4 +1,2 @@

About

-

This is the about page.

-

Go to the home page

diff --git a/content/tutorial/02-sveltekit/02-routing/03-params/README.md b/content/tutorial/02-sveltekit/02-routing/03-params/README.md new file mode 100644 index 000000000..891e04570 --- /dev/null +++ b/content/tutorial/02-sveltekit/02-routing/03-params/README.md @@ -0,0 +1,16 @@ +--- +title: Route parameters +--- + +To create routes with dynamic parameters, use square brackets around a valid variable name. For example, a file like `src/routes/blog/[slug]/+page.svelte` will create a route that matches `/blog/one`, `/blog/two`, `/blog/three` and so on. + +Let's create that file: + +```svelte +/// file: src/routes/blog/[slug]/+page.svelte +

Blog post

+``` + +We can now navigate from the `/blog` page to individual blog posts. In the next chapter, we'll see how to load their content. + +> Multiple route parameters can appear _within_ one URL segment, as long as they are separated by at least one static character: `foo/[bar]x[baz]` is a valid route where `[bar]` and `[bar]` are dynamic parameters. diff --git a/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/+layout.svelte b/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..140c2cffc --- /dev/null +++ b/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/+layout.svelte @@ -0,0 +1,6 @@ + + + diff --git a/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..e5324dcb6 --- /dev/null +++ b/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

Home Page

diff --git a/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/blog/+page.svelte b/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/blog/+page.svelte new file mode 100644 index 000000000..f047f5398 --- /dev/null +++ b/content/tutorial/02-sveltekit/02-routing/03-params/app-a/src/routes/blog/+page.svelte @@ -0,0 +1,7 @@ +

Blog

+ + diff --git a/content/tutorial/02-sveltekit/02-routing/03-params/app-b/src/routes/blog/[slug]/+page.svelte b/content/tutorial/02-sveltekit/02-routing/03-params/app-b/src/routes/blog/[slug]/+page.svelte new file mode 100644 index 000000000..efd7040f5 --- /dev/null +++ b/content/tutorial/02-sveltekit/02-routing/03-params/app-b/src/routes/blog/[slug]/+page.svelte @@ -0,0 +1 @@ +

Blog post

diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/README.md b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/README.md new file mode 100644 index 000000000..2143a9a50 --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/README.md @@ -0,0 +1,94 @@ +--- +title: Page data +--- + +At its core, SvelteKit's job boils down to three things: + +1. **Routing** — figure out which route matches an incoming request +2. **Loading** — get the data needed by the route +3. **Rendering** - generate some HTML (on the server) or update the DOM (in the browser) + +We've seen how routing and rendering work. Let's talk about the middle part — loading. + +Every page of your app can declare a `load` function in a `+page.server.js` file alongside the `+page.svelte` file. As the file name suggests, this module only ever runs on the server, including for client-side navigations. Let's add a `src/routes/blog/+page.server.js` file so that we can replace the hard-coded links in `src/routes/blog/+page.svelte` with actual blog post data: + +```js +/// file: src/routes/blog/+page.server.js +import { posts } from './data.js'; + +export function load() { + return { + summaries: posts.map((post) => ({ + slug: post.slug, + title: post.title + })) + }; +} +``` + +> For the sake of the tutorial, we're importing data from `src/routes/blog/data.js`. In a real app, you'd be more likely to load the data from a database or a CMS, but for now we'll do it like this. + +We can access this data in `src/routes/blog/+page.svelte` via the `data` prop: + +```svelte +++++++ + +

Blog

+ +
    +---
  • one
  • +
  • two
  • +
  • three
  • --- ++++ {#each data.summaries as { slug, title }} +
  • {title}
  • + {/each}+++ +
+``` + +Now, let's do the same for the post page: + +```js +/// file: src/routes/blog/[slug]/+page.server.js +import { posts } from '../data.js'; + +export function load({ params }) { + const post = posts.find((post) => post.slug === params.slug); + + return { + post + }; +} +``` + +```svelte +/// file: src/routes/blog/[slug]/+page.svelte +++++++ + +---

Blog post

--- ++++

{data.post.title}

+
{@html data.post.content}
+++ +``` + +There's one last detail we need to take care of — the user might visit an invalid pathname like `/blog/nope`, in which case we'd like to respond with a 404 page: + +```js +/// file: src/routes/blog/[slug]/+page.server.js ++++import { error } from '@sveltejs/kit';+++ +import { posts } from '../data.js'; + +export function load({ params }) { + const post = posts.find((post) => post.slug === params.slug); + + +++if (!post) throw error(404);+++ + + return { + post + }; +} +``` + +We'll learn more about error handling in later chapters. diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/+layout.svelte b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..140c2cffc --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/+layout.svelte @@ -0,0 +1,6 @@ + + + diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..e5324dcb6 --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

Home Page

diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/+page.svelte b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/+page.svelte new file mode 100644 index 000000000..f047f5398 --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/+page.svelte @@ -0,0 +1,7 @@ +

Blog

+ + diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/[slug]/+page.svelte b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/[slug]/+page.svelte new file mode 100644 index 000000000..efd7040f5 --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/[slug]/+page.svelte @@ -0,0 +1 @@ +

Blog post

diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/data.js b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/data.js new file mode 100644 index 000000000..4901dad9d --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-a/src/routes/blog/data.js @@ -0,0 +1,21 @@ +export const posts = [ + { + slug: 'welcome', + title: 'Welcome to the Aperture Science computer-aided enrichment center', + content: + '

We hope your brief detention in the relaxation vault has been a pleasant one.

Your specimen has been processed and we are now ready to begin the test proper.

' + }, + + { + slug: 'safety', + title: 'Safety notice', + content: + '

While safety is one of many Enrichment Center Goals, the Aperture Science High Energy Pellet, seen to the left of the chamber, can and has caused permanent disabilities, such as vaporization. Please be careful.

' + }, + + { + slug: 'cake', + title: 'This was a triumph', + content: "

I'm making a note here: HUGE SUCCESS.

" + } +]; diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/+page.server.js b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/+page.server.js new file mode 100644 index 000000000..8581b617c --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/+page.server.js @@ -0,0 +1,10 @@ +import { posts } from './data.js'; + +export function load() { + return { + summaries: posts.map((post) => ({ + slug: post.slug, + title: post.title + })) + }; +} diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/+page.svelte b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/+page.svelte new file mode 100644 index 000000000..ab1cfe1b8 --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/+page.svelte @@ -0,0 +1,11 @@ + + +

Blog

+ +
    + {#each data.summaries as { slug, title }} +
  • {title}
  • + {/each} +
diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/[slug]/+page.server.js b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/[slug]/+page.server.js new file mode 100644 index 000000000..99e67c281 --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/[slug]/+page.server.js @@ -0,0 +1,12 @@ +import { error } from '@sveltejs/kit'; +import { posts } from '../data.js'; + +export function load({ params }) { + const post = posts.find((post) => post.slug === params.slug); + + if (!post) throw error(404); + + return { + post + }; +} diff --git a/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/[slug]/+page.svelte b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/[slug]/+page.svelte new file mode 100644 index 000000000..e54908bf9 --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/01-page-data/app-b/src/routes/blog/[slug]/+page.svelte @@ -0,0 +1,6 @@ + + +

{data.post.title}

+
{@html data.post.content}
diff --git a/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/README.md b/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/README.md new file mode 100644 index 000000000..9c757656d --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/README.md @@ -0,0 +1,49 @@ +--- +title: Layout data +--- + +Just as `+layout.svelte` files create UI for every child route, `+layout.server.js` files load data for every child route. + +Suppose we'd like to add a 'more posts' sidebar to our blog post page. We _could_ return `summaries` from the `load` function in `src/blog/[slug]/+page.server.js`, like we do in `src/blog/+page.server.js`, but that would be repetitive. + +Instead, let's rename `src/blog/+page.server.js` to `src/blog/+layout.server.js`. Notice that the `/blog` route continues to work — `data.summaries` is still available to the page. + +Now, create a layout for the post page: + +```svelte +/// file: src/routes/blog/[slug]/+layout.svelte + + +
+
+ +
+ + +
+ + +``` + +The layout (and the page below it) inherits `data.summaries` from the parent `+layout.server.js`. + +When we navigate from one post to another, we only need to load the data for the post itself — the layout data is still valid. See the documentation on [invalidation](https://kit.svelte.dev/docs/load#invalidation) to learn more. diff --git a/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/+layout.server.js b/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/+layout.server.js new file mode 100644 index 000000000..8581b617c --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/+layout.server.js @@ -0,0 +1,10 @@ +import { posts } from './data.js'; + +export function load() { + return { + summaries: posts.map((post) => ({ + slug: post.slug, + title: post.title + })) + }; +} diff --git a/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/+page.server.js b/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/+page.server.js new file mode 100644 index 000000000..5d003dc7d --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/+page.server.js @@ -0,0 +1 @@ +__delete; diff --git a/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/[slug]/+layout.svelte b/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/[slug]/+layout.svelte new file mode 100644 index 000000000..d455eefce --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/02-layout-data/app-b/src/routes/blog/[slug]/+layout.svelte @@ -0,0 +1,30 @@ + + +
+
+ +
+ + +
+ + diff --git a/content/tutorial/02-sveltekit/03-loading-data/03-universal-load-functions/README.md b/content/tutorial/02-sveltekit/03-loading-data/03-universal-load-functions/README.md new file mode 100644 index 000000000..38bdaa984 --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/03-universal-load-functions/README.md @@ -0,0 +1,22 @@ +--- +title: Universal load functions +--- + +> Coming soon + + diff --git a/content/tutorial/02-sveltekit/03-loading-data/meta.json b/content/tutorial/02-sveltekit/03-loading-data/meta.json new file mode 100644 index 000000000..8ec527b6f --- /dev/null +++ b/content/tutorial/02-sveltekit/03-loading-data/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Loading data" +} diff --git a/content/tutorial/02-sveltekit/04-forms/01-the-form-element/README.md b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/README.md new file mode 100644 index 000000000..76fdbc6f9 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/README.md @@ -0,0 +1,43 @@ +--- +title: The
element +--- + +In the previous chapter, we saw how to get data from the server to the browser. Sometimes you need to send data in the opposite direction, and that's where `` — the web platform's way of submitting data — comes in. + +Let's build a todo app. We've already got an in-memory database set up in `src/lib/server/database.js`, and our `load` function in `src/routes/+page.server.js` uses the [`cookies`](https://kit.svelte.dev/docs/load#cookies-and-headers) API so that we can have a per-user todo list, but we need to add a `` to create new todos: + +```svelte +/// file: src/routes/+page.svelte +

Todos

+ ++++ + +
+++ + +{#each data.todos as todo} +``` + +If we type something into the `` and hit Enter, the browser makes a POST request (because of the `method="POST"` attribute) to the current page. But that results in an error, because we haven't created a server-side _action_ to handle the POST request. Let's do that now: + +```js +/// file: src/routes/+page.server.js +import * as db from '$lib/server/database.js'; + +export function load({ cookies }) { + // ... +} + ++++export const actions = { + default: async ({ cookies, request }) => { + const data = await request.formData(); + db.createTodo(cookies.get('userid'), data.get('description')); + } +};+++ +``` + +When we hit Enter, the database is updated and the page reloads with the new data. + +Notice that we haven't had to write any `fetch` code or anything like that — data updates automatically. And because we're using a `
` element, this app would work even if JavaScript was disabled or unavailable. diff --git a/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/lib/server/database.js b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/lib/server/database.js new file mode 100644 index 000000000..06afbf801 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/lib/server/database.js @@ -0,0 +1,30 @@ +// In a real app, this data would live in a database, +// rather than in memory. But for now, we cheat. +const db = new Map(); + +export function getTodos(userid) { + return db.get(userid); +} + +export function createTodo(userid, description) { + if (!db.has(userid)) { + db.set(userid, []); + } + + const todos = db.get(userid); + + todos.push({ + id: crypto.randomUUID(), + description, + done: false + }); +} + +export function deleteTodo(userid, todoid) { + const todos = db.get(userid); + const index = todos.findIndex((todo) => todo.id === todoid); + + if (index !== -1) { + todos.splice(index, 1); + } +} diff --git a/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/routes/+page.server.js b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/routes/+page.server.js new file mode 100644 index 000000000..d6e0c46da --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/routes/+page.server.js @@ -0,0 +1,13 @@ +import * as db from '$lib/server/database.js'; + +export function load({ cookies }) { + const id = cookies.get('userid'); + + if (!id) { + cookies.set('userid', crypto.randomUUID(), { path: '/' }); + } + + return { + todos: db.getTodos(id) ?? [] + }; +} diff --git a/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..0c2fd19d2 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-a/src/routes/+page.svelte @@ -0,0 +1,13 @@ + + +

todos

+ +
    + {#each data.todos as todo (todo.id)} +
  • + {todo.description} +
  • + {/each} +
diff --git a/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-b/src/routes/+page.server.js b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..d2627e926 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-b/src/routes/+page.server.js @@ -0,0 +1,20 @@ +import * as db from '$lib/server/database.js'; + +export function load({ cookies }) { + const id = cookies.get('userid'); + + if (!id) { + cookies.set('userid', crypto.randomUUID(), { path: '/' }); + } + + return { + todos: db.getTodos(id) ?? [] + }; +} + +export const actions = { + default: async ({ cookies, request }) => { + const data = await request.formData(); + db.createTodo(cookies.get('userid'), data.get('description')); + } +}; diff --git a/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-b/src/routes/+page.svelte b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..23d07eb27 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/01-the-form-element/app-b/src/routes/+page.svelte @@ -0,0 +1,20 @@ + + +

todos

+ + + +
+ +
    + {#each data.todos as todo (todo.id)} +
  • + {todo.description} +
  • + {/each} +
diff --git a/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/README.md b/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/README.md new file mode 100644 index 000000000..cba70bb56 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/README.md @@ -0,0 +1,55 @@ +--- +title: Named form actions +--- + +A page that only has a single action is, in practice, quite rare. Most of the time you'll need to have multiple actions on a page. In this app, creating a todo isn't enough — we'd like to delete them once they're complete. + +Begin by replacing our `default` action with named `create` and `delete` actions: + +```js +/// file: src/routes/+page.server.js +export const actions = { + +++create+++: async ({ cookies, request }) => { + const data = await request.formData(); + db.createTodo(cookies.get('userid'), data.get('description')); + }, + ++++ delete: async ({ cookies, request }) => { + const data = await request.formData(); + db.deleteTodo(cookies.get('userid'), data.get('id')); + }+++ +}; +``` + +> Default actions cannot coexist with named actions. + +The `
` element has an optional `action` attribute, which is similar to an `` element's `href` attribute. Update the existing form so that it points to the new `create` action: + +```svelte +/// file: src/routes/+page.svelte + + + +``` + +> The `action` attribute can be any URL — if the action was defined on another page, you might have something like `/todos?/create`. Since the action is on _this_ page, we can omit the pathname altogether, hence the leading `?` character. + +Next, we want to create a form for each todo, complete with a hidden `` that uniquely identifies it: + +```svelte +/// file: src/routes/+page.svelte +
    + {#each data.todos as todo (todo.id)} +
  • ++++
    + + +++ + {todo.description} ++++
    +++ +
  • + {/each} +
+``` diff --git a/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/app-b/src/routes/+page.server.js b/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..40015d591 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/app-b/src/routes/+page.server.js @@ -0,0 +1,25 @@ +import * as db from '$lib/server/database.js'; + +export function load({ cookies }) { + const id = cookies.get('userid'); + + if (!id) { + cookies.set('userid', crypto.randomUUID(), { path: '/' }); + } + + return { + todos: db.getTodos(id) ?? [] + }; +} + +export const actions = { + create: async ({ cookies, request }) => { + const data = await request.formData(); + db.createTodo(cookies.get('userid'), data.get('description')); + }, + + delete: async ({ cookies, request }) => { + const data = await request.formData(); + db.deleteTodo(cookies.get('userid'), data.get('id')); + } +}; diff --git a/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/app-b/src/routes/+page.svelte b/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..9c1809b36 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/02-named-form-actions/app-b/src/routes/+page.svelte @@ -0,0 +1,25 @@ + + +

todos

+ +
+ +
+ +
    + {#each data.todos as todo (todo.id)} +
  • +
    + + + + {todo.description} +
    +
  • + {/each} +
diff --git a/content/tutorial/02-sveltekit/04-forms/03-form-validation/README.md b/content/tutorial/02-sveltekit/04-forms/03-form-validation/README.md new file mode 100644 index 000000000..432168eca --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/03-form-validation/README.md @@ -0,0 +1,104 @@ +--- +title: Validation +--- + +Users are a mischievous bunch, who will submit all kinds of nonsensical data if given the chance. To prevent them from causing chaos, it's important to validate form data. + +The first line of defense is the browser's [built-in form validation](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#using_built-in_form_validation), which makes it easy to, for example, mark an `` as required: + +```svelte +
+ +
+``` + +Try hitting Enter while the `` is empty. + +This kind of validation is helpful, but insufficient. Some validation rules (e.g. uniqueness) can't be expressed using `` attributes, and in any case, if the user is an elite hacker they might simply delete the attributes using the browser's devtools. To guard against these sorts of shenanigans, you should always use server-side validation. + +In `src/lib/server/database.js`, validate that the description exists and is unique: + +```js +/// file: src/lib/server/database.js +export function createTodo(userid, description) { ++++ if (description === '') { + throw new Error('todo must have a description'); + }+++ + + if (!db.has(userid)) { + db.set(userid, []); + } + + const todos = db.get(userid); + ++++ if (todos.find((todo) => todo.description === description)) { + throw new Error('todos must be unique'); + }+++ + + todos.push({ + id: crypto.randomUUID(), + description, + done: false + }); +} +``` + +Try submitting a duplicate todo. Yikes! SvelteKit takes us to an unfriendly-looking error page. On the server, we see a 'todos must be unique' error, but SvelteKit hides unexpected error messages from users because they often contain sensitive data. + +It would be much better to stay on the same page and provide an indication of what went wrong so that the user can fix it. To do this, we can use the `fail` function to return data from the action along with an appropriate HTTP status code: + +```js +/// file: src/routes/+page.server.js ++++import { fail } from '@sveltejs/kit';+++ + +export function load({ cookies }) {...} + +export const actions = { + create: async ({ cookies, request }) => { + const data = await request.formData(); + ++++ try {+++ + db.createTodo(cookies.get('userid'), data.get('description')); ++++ } catch (error) { + return fail(422, { + description: data.get('description'), + error: error.message + }); + }+++ + } +``` + +In `src/routes/+page.svelte`, we can access the returned value via the `form` prop, which is only ever populated after a form submission: + +```svelte +/// file: src/routes/+page.svelte + + +

todos

+ ++++{#if form?.error} +

{form.error}

+{/if}+++ + +
+ +
+``` + +> You can also return data from an action _without_ wrapping it in `fail` — for example to show a 'success!' message when data was saved — and it will be available via the `form` prop. diff --git a/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/lib/server/database.js b/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/lib/server/database.js new file mode 100644 index 000000000..ff6a48db8 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/lib/server/database.js @@ -0,0 +1,38 @@ +// In a real app, this data would live in a database, +// rather than in memory. But for now, we cheat. +const db = new Map(); + +export function getTodos(userid) { + return db.get(userid); +} + +export function createTodo(userid, description) { + if (description === '') { + throw new Error('todo must have a description'); + } + + if (!db.has(userid)) { + db.set(userid, []); + } + + const todos = db.get(userid); + + if (todos.find((todo) => todo.description === description)) { + throw new Error('todos must be unique'); + } + + todos.push({ + id: crypto.randomUUID(), + description, + done: false + }); +} + +export function deleteTodo(userid, todoid) { + const todos = db.get(userid); + const index = todos.findIndex((todo) => todo.id === todoid); + + if (index !== -1) { + todos.splice(index, 1); + } +} diff --git a/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/routes/+page.server.js b/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..c91d6fd60 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/routes/+page.server.js @@ -0,0 +1,34 @@ +import { fail } from '@sveltejs/kit'; +import * as db from '$lib/server/database.js'; + +export function load({ cookies }) { + const id = cookies.get('userid'); + + if (!id) { + cookies.set('userid', crypto.randomUUID(), { path: '/' }); + } + + return { + todos: db.getTodos(id) ?? [] + }; +} + +export const actions = { + create: async ({ cookies, request }) => { + const data = await request.formData(); + + try { + db.createTodo(cookies.get('userid'), data.get('description')); + } catch (error) { + return fail(422, { + description: data.get('description'), + error: error.message + }); + } + }, + + delete: async ({ cookies, request }) => { + const data = await request.formData(); + db.deleteTodo(cookies.get('userid'), data.get('id')); + } +}; diff --git a/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/routes/+page.svelte b/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..fdc24c779 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/03-form-validation/app-b/src/routes/+page.svelte @@ -0,0 +1,34 @@ + + +

todos

+ +{#if form?.error} +

{form.error}

+{/if} + +
+ +
+ +
    + {#each data.todos as todo (todo.id)} +
  • +
    + + + + {todo.description} +
    +
  • + {/each} +
diff --git a/content/tutorial/02-sveltekit/04-forms/04-progressive-enhancement/README.md b/content/tutorial/02-sveltekit/04-forms/04-progressive-enhancement/README.md new file mode 100644 index 000000000..9cbe818ea --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/04-progressive-enhancement/README.md @@ -0,0 +1,53 @@ +--- +title: Progressive enhancement +--- + +Because we're using `
`, our app works even if the user doesn't have JavaScript ([which happens more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html)). That's great, because it means our app is resilient. + +Most of the time, users _do_ have JavaScript. In those cases, we can _progressively enhance_ the experience, the same way SvelteKit progressively enhances `` elements by using client-side routing. + +Import the `enhance` function from `$app/forms`... + +```svelte +/// file: src/routes/+page.svelte + +``` + +...and add the `use:enhance` directive to the `` elements: + +```svelte + +``` + +```svelte + +``` + +And that's all it takes! Now, when JavaScript is enabled, `use:enhance` will emulate the browser-native behaviour except for the full-page reloads. It will: + +- update the `form` prop +- invalidate all data on a successful response, causing `load` functions to re-run +- navigate to the new page on a redirect response +- render the nearest error page if an error occurs + +Now that we're updating the page rather than reloading it, we can get fancy with things like transitions: + +```svelte +/// file: src/routes/+page.svelte + +``` + +```svelte +
  • ...
  • +``` diff --git a/content/tutorial/02-sveltekit/04-forms/04-progressive-enhancement/app-b/src/routes/+page.svelte b/content/tutorial/02-sveltekit/04-forms/04-progressive-enhancement/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..629d09091 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/04-progressive-enhancement/app-b/src/routes/+page.svelte @@ -0,0 +1,37 @@ + + +

    todos

    + +{#if form?.error} +

    {form.error}

    +{/if} + + + + + +
      + {#each data.todos as todo (todo.id)} +
    • +
      + + + + {todo.description} +
      +
    • + {/each} +
    diff --git a/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/README.md b/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/README.md new file mode 100644 index 000000000..525e6d044 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/README.md @@ -0,0 +1,92 @@ +--- +title: Customizing use:enhance +--- + +With `use:enhance`, we can go further than just emulating the browser's native behaviour. By providing a callback, we can add things like **pending states** and **optimistic UI**. Let's simulate a slow network by adding an artificial delay to our two actions: + +```js +/// file: src/routes/+page.server.js +export const actions = { + create: async ({ cookies, request }) => { + +++await new Promise((fulfil) => setTimeout(fulfil, 1000));+++ + ... + }, + + delete: async ({ cookies, request }) => { + +++await new Promise((fulfil) => setTimeout(fulfil, 1000));+++ + ... + } +}; +``` + +When we create or delete items, it now takes a full second before the UI updates, leaving the user wondering if they messed up somehow. To solve that, add some local state... + +```svelte +/// file: src/routes/+page.svelte + +``` + +...and toggle `creating` inside the first `use:enhance`: + +```svelte +
    { + creating = true; + + return async ({ update }) => { + await update(); + creating = false; + }; + }}+++ +> + +
    +``` + +In the case of deletions, we don't really need to wait for the server to validate anything — we can just update the UI immediately: + +```svelte +
      + {#each +++data.todos.filter((todo) => !deleting.includes(todo.id))+++ as todo (todo.id)} +
    • +
      { + deleting = [...deleting, todo.id]; + return async ({ update }) => { + await update(); + deleting = deleting.filter((id) => id !== todo.id); + }; + }}+++ + > + + + + {todo.description} +
      +
    • + {/each} +
    +``` + +> `use:enhance` is very customizable — you can `cancel()` submissions, handle redirects, control whether the form is reset, and so on. [See the docs](https://kit.svelte.dev/docs/modules#$app-forms-enhance) for full details. diff --git a/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/app-b/src/routes/+page.server.js b/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..334b79ddd --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/app-b/src/routes/+page.server.js @@ -0,0 +1,38 @@ +import { fail } from '@sveltejs/kit'; +import * as db from '$lib/server/database.js'; + +export function load({ cookies }) { + const id = cookies.get('userid'); + + if (!id) { + cookies.set('userid', crypto.randomUUID(), { path: '/' }); + } + + return { + todos: db.getTodos(id) ?? [] + }; +} + +export const actions = { + create: async ({ cookies, request }) => { + await new Promise((fulfil) => setTimeout(fulfil, 1000)); + + const data = await request.formData(); + + try { + db.createTodo(cookies.get('userid'), data.get('description')); + } catch (error) { + return fail(422, { + description: data.get('description'), + error: error.message + }); + } + }, + + delete: async ({ cookies, request }) => { + await new Promise((fulfil) => setTimeout(fulfil, 1000)); + + const data = await request.formData(); + db.deleteTodo(cookies.get('userid'), data.get('id')); + } +}; diff --git a/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/app-b/src/routes/+page.svelte b/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..a74c2fe62 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/05-customizing-use-enhance/app-b/src/routes/+page.svelte @@ -0,0 +1,62 @@ + + +

    todos

    + +{#if form?.error} +

    {form.error}

    +{/if} + +
    { + creating = true; + + return async ({ update }) => { + await update(); + creating = false; + }; + }} +> + +
    + +
      + {#each data.todos.filter((todo) => !deleting.includes(todo.id)) as todo (todo.id)} +
    • +
      { + deleting = [...deleting, todo.id]; + return async ({ update }) => { + await update(); + deleting = deleting.filter((id) => id !== todo.id); + }; + }} + > + + + + {todo.description} +
      +
    • + {/each} +
    diff --git a/content/tutorial/02-sveltekit/04-forms/meta.json b/content/tutorial/02-sveltekit/04-forms/meta.json new file mode 100644 index 000000000..ba55ade29 --- /dev/null +++ b/content/tutorial/02-sveltekit/04-forms/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Forms" +} diff --git a/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/README.md b/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/README.md new file mode 100644 index 000000000..763befb80 --- /dev/null +++ b/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/README.md @@ -0,0 +1,36 @@ +--- +title: GET handlers +--- + +SvelteKit allows you to create more than just pages. We can also create _API routes_ by adding a `+server.js` file that exports functions corresponding to HTTP methods: `GET`, `PUT`, `POST`, `PATCH` and `DELETE`. + +This app fetches data from a `/roll` API route when you click the button. Create that route by adding a `src/routes/roll/+server.js` file: + +```js +/// file: src/routes/roll/+server.js +export function GET() { + const number = Math.ceil(Math.random() * 6); + + return new Response(number, { + 'Content-Type': 'application/json' + }); +} +``` + +Clicking the button now works. + +Request handlers must return a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response) object. Since it's common to return JSON from an API route, SvelteKit provides a convenience function for generating these responses: + +```js +/// file: src/routes/roll/+server.js ++++import { json } from '@sveltejs/kit';+++ + +export function GET() { + const number = Math.ceil(Math.random() * 6); + +--- return new Response(number, { + 'Content-Type': 'application/json' + });--- ++++ return json(number);+++ +} +``` diff --git a/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..99955f2ed --- /dev/null +++ b/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-a/src/routes/+page.svelte @@ -0,0 +1,15 @@ + + + + +{#if number !== undefined} +

    You rolled a {number}

    +{/if} diff --git a/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-b/src/routes/+page.svelte b/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..99955f2ed --- /dev/null +++ b/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-b/src/routes/+page.svelte @@ -0,0 +1,15 @@ + + + + +{#if number !== undefined} +

    You rolled a {number}

    +{/if} diff --git a/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-b/src/routes/roll/+server.js b/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-b/src/routes/roll/+server.js new file mode 100644 index 000000000..98c2e6de8 --- /dev/null +++ b/content/tutorial/02-sveltekit/05-api-routes/01-get-handlers/app-b/src/routes/roll/+server.js @@ -0,0 +1,7 @@ +import { json } from '@sveltejs/kit'; + +export function GET() { + const number = Math.ceil(Math.random() * 6); + + return json(number); +} diff --git a/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/README.md b/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/README.md new file mode 100644 index 000000000..42f96bdc7 --- /dev/null +++ b/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/README.md @@ -0,0 +1,5 @@ +--- +title: POST, PUT, PATCH, DELETE +--- + +> Coming soon diff --git a/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..1333ed77b --- /dev/null +++ b/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +TODO diff --git a/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/app-b/src/routes/+page.svelte b/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..1333ed77b --- /dev/null +++ b/content/tutorial/02-sveltekit/05-api-routes/02-post-put-patch-delete/app-b/src/routes/+page.svelte @@ -0,0 +1 @@ +TODO diff --git a/content/tutorial/02-sveltekit/05-api-routes/meta.json b/content/tutorial/02-sveltekit/05-api-routes/meta.json new file mode 100644 index 000000000..a3fdf1da8 --- /dev/null +++ b/content/tutorial/02-sveltekit/05-api-routes/meta.json @@ -0,0 +1,3 @@ +{ + "title": "API routes" +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/README.md b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/README.md new file mode 100644 index 000000000..dd4ac1e64 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/README.md @@ -0,0 +1,31 @@ +--- +title: Basics +--- + +There are two types of errors in SvelteKit — _expected_ errors and _unexpected_ errors. + +An expected error is one that was created with the [`error`](https://kit.svelte.dev/docs/modules#sveltejs-kit-error) helper from `@sveltejs/kit`, as in `src/routes/expected/+page.server.js`: + +```js +/// file: src/routes/expected/+page.server.js +import { error } from '@sveltejs/kit'; + +export function load() { + throw error(420, 'Enhance your calm'); +} +``` + +Any other error — such as the one in `src/routes/unexpected/+page.server.js` — is treated as unexpected: + +```js +/// file: src/routes/unexpected/+page.server.js +export function load() { + throw new Error('Kaboom!'); +} +``` + +When you throw an expected error, you're telling SvelteKit 'don't worry, I know what I'm doing here'. An unexpected error, by contrast, is assumed to be a bug in your app. When an unexpected error is thrown, its message and stack trace will be logged to the console. + +> In a later chapter we'll learn about how to add custom error handling using the `handleError` hook. + +If you click the links in this app, you'll notice an important difference: the expected error message is shown to the user, whereas the unexpected error message is redacted and replaced with a generic 'Internal Error' message and a 500 status code. That's because error messages can contain sensitive data. diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/+layout.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..98719ede2 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/+layout.svelte @@ -0,0 +1,7 @@ +
    + + diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..415b7b290 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    home

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/expected/+page.server.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/expected/+page.server.js new file mode 100644 index 000000000..c3140a7c6 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/expected/+page.server.js @@ -0,0 +1,5 @@ +import { error } from '@sveltejs/kit'; + +export function load() { + throw error(420, 'Enhance your calm'); +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/expected/+page.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/expected/+page.svelte new file mode 100644 index 000000000..1ae4bca6b --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/expected/+page.svelte @@ -0,0 +1 @@ +

    This page will never be rendered

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/unexpected/+page.server.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/unexpected/+page.server.js new file mode 100644 index 000000000..c204bc29f --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/unexpected/+page.server.js @@ -0,0 +1,3 @@ +export function load() { + throw new Error('Kaboom!'); +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/unexpected/+page.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/unexpected/+page.svelte new file mode 100644 index 000000000..1ae4bca6b --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/01-error-basics/app-a/src/routes/unexpected/+page.svelte @@ -0,0 +1 @@ +

    This page will never be rendered

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/README.md b/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/README.md new file mode 100644 index 000000000..83f5bdfcb --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/README.md @@ -0,0 +1,36 @@ +--- +title: Error pages +--- + +When something goes wrong inside a `load` function, SvelteKit renders an error page. + +The default error page is somewhat bland. We can customize it by creating a `src/routes/+error.svelte` component: + +```svelte +/// file: src/routes/+error.svelte + + +

    {$page.status} {$page.error.message}

    + + {emojis[$page.status] ?? emojis[500]} + +``` + +> We're using the `page` store, which we'll learn more about in a later chapter. + +Notice that the `+error.svelte` component is rendered inside the root `+layout.svelte`. We can create more granular `+error.svelte` boundaries: + +```svelte +/// file: src/routes/expected/+error.svelte +

    this error was expected

    +``` + +This component will be rendered for `/expected`, while the root `src/routes/+error.svelte` page will be rendered for any other errors that occur. diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/app-b/src/routes/+error.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/app-b/src/routes/+error.svelte new file mode 100644 index 000000000..729571952 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/app-b/src/routes/+error.svelte @@ -0,0 +1,14 @@ + + +

    {$page.status} {$page.error.message}

    + + {emojis[$page.status] ?? emojis[500]} + diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/app-b/src/routes/expected/+error.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/app-b/src/routes/expected/+error.svelte new file mode 100644 index 000000000..c6eca1ce9 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/02-error-pages/app-b/src/routes/expected/+error.svelte @@ -0,0 +1 @@ +

    this error was expected

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/README.md b/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/README.md new file mode 100644 index 000000000..5c7964e1b --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/README.md @@ -0,0 +1,36 @@ +--- +title: Fallback errors +--- + +If things go _really_ wrong — an error occurs while loading the root layout data, or while rendering the error page — SvelteKit will fall back to a static error page. + +Add a new `src/routes/+layout.server.js` file to see this in action: + +```js +/// file: src/routes/+layout.server.js +export function load() { + throw new Error('😬'); +} +``` + +You can customise the fallback error page. Create a `src/error.html` file: + +```html +/// file: src/error.html + + + + + %sveltekit.error.message% + + +

    Game over

    +

    Error code %sveltekit.status%

    + + +``` + +This file can include the following: + +- `%sveltekit.status%` — the HTTP status code +- `%sveltekit.error.message%` — the error message diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/app-b/src/error.html b/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/app-b/src/error.html new file mode 100644 index 000000000..af5d22a3a --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/app-b/src/error.html @@ -0,0 +1,11 @@ + + + + + %sveltekit.error.message% + + +

    Game over

    +

    Error code %sveltekit.status%

    + + diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/app-b/src/routes/+layout.server.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/app-b/src/routes/+layout.server.js new file mode 100644 index 000000000..663e21d3b --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/03-fallback-errors/app-b/src/routes/+layout.server.js @@ -0,0 +1,3 @@ +export function load() { + throw new Error('😬'); +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/README.md b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/README.md new file mode 100644 index 000000000..3fd3a5313 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/README.md @@ -0,0 +1,26 @@ +--- +title: Redirects +--- + +We can also use the `throw` mechanism to redirect from one page to another. + +Create a new `load` function in `src/routes/a/+page.server.js`: + +```js +/// file: src/routes/a/+page.server.js +import { redirect } from '@sveltejs/kit'; + +export function load() { + throw redirect(307, '/b'); +} +``` + +Navigating to `/a` will now take us straight to `/b`. + +You can `throw redirect(...)` inside `load` functions, form actions, API routes and the `handle` hook, which we'll discuss in a later chapter. + +The most common status codes you'll use: + +- `303` — for form actions, following a successful submission +- `307` — for temporary redirects +- `308` — for permanent redirects diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/+layout.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..f418852ea --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/+layout.svelte @@ -0,0 +1,7 @@ + + + diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..0a88878c3 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    home

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/a/+page.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/a/+page.svelte new file mode 100644 index 000000000..57f9d4079 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/a/+page.svelte @@ -0,0 +1 @@ +

    a

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/b/+page.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/b/+page.svelte new file mode 100644 index 000000000..e96ed3db8 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-a/src/routes/b/+page.svelte @@ -0,0 +1 @@ +

    b

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-b/src/routes/a/+page.server.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-b/src/routes/a/+page.server.js new file mode 100644 index 000000000..4e4a8a37b --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/04-redirects/app-b/src/routes/a/+page.server.js @@ -0,0 +1,5 @@ +import { redirect } from '@sveltejs/kit'; + +export function load() { + throw redirect(307, '/b'); +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/meta.json b/content/tutorial/02-sveltekit/06-errors-and-redirects/meta.json new file mode 100644 index 000000000..cb12a3840 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Errors and redirects" +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/README.md b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/README.md new file mode 100644 index 000000000..77f50d589 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/README.md @@ -0,0 +1,54 @@ +--- +title: Customizing the error message +--- + +The error page in the previous exercise is rather static. Maybe you want to show the error message so you can help people turning up in your support channels faster. + +For this, SvelteKit provides you with `$page.error` and `$page.status`, which contain information about the error and the status code. Let's add it to `+error.svelte`: + +```svelte +/// file: src/routes/+error.svelte + + ++++{#if $page.status === 404} +

    Not found

    +{:else +++if !online} +

    You're offline

    +{:else} +

    Oops!

    + ---

    Something went wrong

    --- + +++

    {$page.error.message}

    +++ +{/if} +``` + +That's better, but `$page.error.message` always contains "Internal Error" - how so? This is because SvelteKit plays it safe and prevents you from accidentally showing sensitive information as part of the error message. + +To customize it, implement the `handleError` hook in `hooks.server.js` and `hooks.client.js` which run when an unexpected error is thrown during data loads on the server or client respectively. + +```js +// hooks.server.js +export function handleError(+++{ error }+++) { + ---return { message: 'Internal Error' }; // the default implementation of this hook--- + +++return { message: error instanceof Error ? error.message : 'Internal Error' };+++ +} +``` + +```js +// hooks.client.js +export function handleError(+++{ error }+++) { + ---return { message: 'Internal Error' }; // the default implementation of this hook--- + +++return { message: error instanceof Error ? error.message : 'Internal Error' };+++ +} +``` + +You could also call your error reporting service in these hooks. + +Note that you can return more than an error message if you like. Whatever object shape you return will be available in `$page.error`, the only requirement is a `message` property. You can read more about this (and how to make it type-safe!) in the [error docs](https://kit.svelte.dev/docs/errors). + +> When handling errors, be careful to not assume it's an `Error` object, anything could be thrown. Also make sure not to expose senstive data by forwarding too much information diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/hooks.client.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/hooks.client.js new file mode 100644 index 000000000..62a95696f --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/hooks.client.js @@ -0,0 +1,3 @@ +export function handleError() { + return { message: 'Internal Error' }; // the default implementation of this hook +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/hooks.server.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/hooks.server.js new file mode 100644 index 000000000..62a95696f --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/hooks.server.js @@ -0,0 +1,3 @@ +export function handleError() { + return { message: 'Internal Error' }; // the default implementation of this hook +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+error.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+error.svelte new file mode 100644 index 000000000..6798048ac --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+error.svelte @@ -0,0 +1,11 @@ + + +{#if !online} +

    you're offline

    +{:else} +

    oops!

    +

    Something went wrong

    +{/if} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+layout.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..8a38e3a9a --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+layout.svelte @@ -0,0 +1,6 @@ + + + diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..68002cd17 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    Welcome

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/about/+page.server.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/about/+page.server.js new file mode 100644 index 000000000..70e38a999 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/about/+page.server.js @@ -0,0 +1,5 @@ +export function load() { + throw new Error( + 'Something went terribly wrong loading the about page' + ); +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/about/+page.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/about/+page.svelte new file mode 100644 index 000000000..934797c93 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-a/src/routes/about/+page.svelte @@ -0,0 +1,4 @@ +

    + This is the best about page of all time. Sad + that you'll never see it because of the error. +

    diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/hooks.client.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/hooks.client.js new file mode 100644 index 000000000..5057ad2af --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/hooks.client.js @@ -0,0 +1,3 @@ +export function handleError({ error }) { + return { message: error instanceof Error ? error.message : 'Internal Error' }; +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/hooks.server.js b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/hooks.server.js new file mode 100644 index 000000000..5057ad2af --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/hooks.server.js @@ -0,0 +1,3 @@ +export function handleError({ error }) { + return { message: error instanceof Error ? error.message : 'Internal Error' }; +} diff --git a/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/routes/+error.svelte b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/routes/+error.svelte new file mode 100644 index 000000000..f92d0b2a1 --- /dev/null +++ b/content/tutorial/02-sveltekit/06-errors-and-redirects/xx-custom-error-messages/app-b/src/routes/+error.svelte @@ -0,0 +1,15 @@ + + +{#if $page.status === 404} +

    Not found

    +{:else if !online} +

    You're offline

    +{:else} +

    Oops!

    +

    {$page.error.message}

    +{/if} diff --git a/content/tutorial/02-sveltekit/07-page-options/01-page-options/README.md b/content/tutorial/02-sveltekit/07-page-options/01-page-options/README.md new file mode 100644 index 000000000..0c8e182c7 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/01-page-options/README.md @@ -0,0 +1,16 @@ +--- +title: Basics +--- + +In the chapter on [loading data](/tutorial/page-data), we saw how you can export `load` functions from `+page.js`, `+page.server.js`, `+layout.js` and `+layout.server.js` files. We can also export various **page options** from these modules: + +- `ssr` — whether or not pages should be server-rendered +- `csr` — whether to load the SvelteKit client +- `prerender` — whether to prerender pages at build time, instead of per-request +- `trailingSlash` — whether to strip, add, or ignore trailing slashes in URLs + +In the following exercises, we'll learn about each of these in turn. + +Page options can apply to individual pages (if exported from `+page.js` or `+page.server.js`), or groups of pages (if exported from `+layout.js` or `+layout.server.js`). To define an option for the whole app, export it from the root layout. Child layouts and pages override values set in parent layouts, so — for example — you can enable prerendering for your entire app then disable it for pages that need to be dynamically rendered. + +You can mix and match these options in different areas of your app — you could prerender your marketing pages, dynamically server-render your data-driven pages, and treat your admin pages as a client-rendered SPA. This makes SvelteKit very versatile. diff --git a/content/tutorial/02-sveltekit/07-page-options/01-page-options/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/07-page-options/01-page-options/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..36a41a3d7 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/01-page-options/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    Page options

    diff --git a/content/tutorial/02-sveltekit/07-page-options/02-ssr/README.md b/content/tutorial/02-sveltekit/07-page-options/02-ssr/README.md new file mode 100644 index 000000000..3e451bca4 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/02-ssr/README.md @@ -0,0 +1,14 @@ +--- +title: ssr +--- + +Server-side rendering (SSR) is the process of generating HTML on the server, and is what SvelteKit does by default. It's important for performance and [resilience](https://kryogenix.org/code/browser/everyonehasjs.html), and is very beneficial for search engine optimization (SEO) — while some search engines can index content that is rendered in the browser with JavaScript, it happens less frequently and reliably. + +That said, some components _can't_ be rendered on the server, perhaps because they expect to be able to access browser globals like `window` immediately. If you can, you should change those components so that they _can_ render on the server, but if you can't then you can disable SSR: + +```js +/// file: src/routes/+page.server.js +export const ssr = false; +``` + +> Setting `ssr` to `false` inside your root `+layout.server.js` effectively turns your entire app into an SPA. diff --git a/content/tutorial/02-sveltekit/07-page-options/02-ssr/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/07-page-options/02-ssr/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..15828786e --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/02-ssr/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    {window.innerWidth}x{window.innerHeight}

    diff --git a/content/tutorial/02-sveltekit/07-page-options/02-ssr/app-b/src/routes/+page.server.js b/content/tutorial/02-sveltekit/07-page-options/02-ssr/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..a3d15781a --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/02-ssr/app-b/src/routes/+page.server.js @@ -0,0 +1 @@ +export const ssr = false; diff --git a/content/tutorial/02-sveltekit/07-page-options/03-csr/README.md b/content/tutorial/02-sveltekit/07-page-options/03-csr/README.md new file mode 100644 index 000000000..239835930 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/03-csr/README.md @@ -0,0 +1,14 @@ +--- +title: csr +--- + +Client-side rendering is what makes the page interactive — such as incrementing the counter when you click the button in this app — and enables SvelteKit to update the page upon navigation without a full-page reload. + +As with `ssr`, you can disable client-side rendering altogether: + +```js +/// file: src/routes/+page.server.js +export const csr = false; +``` + +This means that no JavaScript is served to the client, but it also means that your components are no longer interactive. It can be a useful way to check whether or not your application is usable for people who — for whatever reason — cannot use JavaScript. diff --git a/content/tutorial/02-sveltekit/07-page-options/03-csr/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/07-page-options/03-csr/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..3f3888c81 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/03-csr/app-a/src/routes/+page.svelte @@ -0,0 +1,15 @@ + + +

    Rendered {browser ? 'in the browser' : 'on the server'}

    + + diff --git a/content/tutorial/02-sveltekit/07-page-options/03-csr/app-b/src/routes/+page.server.js b/content/tutorial/02-sveltekit/07-page-options/03-csr/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..26bb56887 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/03-csr/app-b/src/routes/+page.server.js @@ -0,0 +1 @@ +export const csr = false; diff --git a/content/tutorial/02-sveltekit/07-page-options/04-prerender/README.md b/content/tutorial/02-sveltekit/07-page-options/04-prerender/README.md new file mode 100644 index 000000000..d9fa996fc --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/04-prerender/README.md @@ -0,0 +1,21 @@ +--- +title: prerender +--- + +Prerendering means generating HTML for a page once, at build time, rather than dynamically for each request. + +The advantage is that serving static data is extremely cheap and performant, allowing you to easily serve large numbers of users without worrying about cache-control headers (which are easy to get wrong). + +The tradeoff is that the build process takes longer, and prerendered content can only be updated by building and deploying a new version of the application. + +To prerender a page, set `prerender` to `true`: + +```js +export const prerender = true; +``` + +Here in the tutorial, this won't have any observable effect, since the application is running in `dev` mode. + +Not all pages can be prerendered. The basic rule is this: for content to be prerenderable, any two users hitting it directly must get the same content from the server, and the page must not contain form actions. Pages with dynamic route parameters can be prerendered as long as they are specified in the [`prerender.entries`](https://kit.svelte.dev/docs/configuration#prerender) configuration or can be reached by following links from pages that _are_ in `prerender.entries`. + +> Setting `prerender` to `true` inside your root `+layout.server.js` effectively turns SvelteKit into a static site generator (SSG). diff --git a/content/tutorial/02-sveltekit/07-page-options/04-prerender/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/07-page-options/04-prerender/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..4f54d4549 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/04-prerender/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    Prerendering

    diff --git a/content/tutorial/02-sveltekit/07-page-options/04-prerender/app-b/src/routes/+page.server.js b/content/tutorial/02-sveltekit/07-page-options/04-prerender/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..189f71e2e --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/04-prerender/app-b/src/routes/+page.server.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/README.md b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/README.md new file mode 100644 index 000000000..e5375f823 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/README.md @@ -0,0 +1,25 @@ +--- +title: trailingSlash +--- + +Two URLs like `/foo` and `/foo/` might look the same, but they're actually different. A relative URL like `bar` will resolve to `/bar` in the first case and `/foo/bar` in the second, and search engines will treat them as separate entries, harming your SEO. + +In short, being loosey-goosey about trailing slashes is a bad idea. By default, SvelteKit strips trailing slashes, meaning that a request for `/foo/` will result in a redirect to `/foo`. + +If you instead want to ensure that a trailing slash is always present, you can specify the `trailingSlash` option accordingly: + +```js +/// file: src/routes/always/+page.server.js +export const trailingSlash = 'always'; +``` + +To accommodate both cases (this is not recommended!), use `'ignore`': + +```js +/// file: src/routes/ignore/+page.server.js +export const trailingSlash = 'ignore'; +``` + +The default value is `'never'`. + +Whether or not trailing slashes are applied affects prerendering. A URL like `/always/` will be saved to disk as `always/index.html` whereas a URL like `/never` will be saved as `never.html`. diff --git a/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/+layout.svelte b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..40c5435dc --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/+layout.svelte @@ -0,0 +1,10 @@ + + + diff --git a/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/+page.svelte b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..9b482681e --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    trailingSlash

    diff --git a/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/always/+page.svelte b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/always/+page.svelte new file mode 100644 index 000000000..438025994 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/always/+page.svelte @@ -0,0 +1 @@ +

    always

    diff --git a/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/ignore/+page.svelte b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/ignore/+page.svelte new file mode 100644 index 000000000..9812f0980 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/ignore/+page.svelte @@ -0,0 +1 @@ +

    ignore

    diff --git a/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/never/+page.svelte b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/never/+page.svelte new file mode 100644 index 000000000..6a2e6f466 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-a/src/routes/never/+page.svelte @@ -0,0 +1 @@ +

    never

    diff --git a/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-b/src/routes/always/+page.server.js b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-b/src/routes/always/+page.server.js new file mode 100644 index 000000000..d3c325085 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-b/src/routes/always/+page.server.js @@ -0,0 +1 @@ +export const trailingSlash = 'always'; diff --git a/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-b/src/routes/ignore/+page.server.js b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-b/src/routes/ignore/+page.server.js new file mode 100644 index 000000000..42a828c11 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/05-trailingslash/app-b/src/routes/ignore/+page.server.js @@ -0,0 +1 @@ +export const trailingSlash = 'ignore'; diff --git a/content/tutorial/02-sveltekit/07-page-options/meta.json b/content/tutorial/02-sveltekit/07-page-options/meta.json new file mode 100644 index 000000000..d97850af8 --- /dev/null +++ b/content/tutorial/02-sveltekit/07-page-options/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Page options" +} diff --git a/content/tutorial/03-advanced-svelte/08-context/01-context-api/app-a/src/lib/Map.svelte b/content/tutorial/03-advanced-svelte/08-context/01-context-api/app-a/src/lib/Map.svelte index 1ab73211f..10e77087a 100644 --- a/content/tutorial/03-advanced-svelte/08-context/01-context-api/app-a/src/lib/Map.svelte +++ b/content/tutorial/03-advanced-svelte/08-context/01-context-api/app-a/src/lib/Map.svelte @@ -25,7 +25,7 @@ }); - + - + Coming soon diff --git a/content/tutorial/04-advanced-sveltekit/01-hooks/meta.json b/content/tutorial/04-advanced-sveltekit/01-hooks/meta.json new file mode 100644 index 000000000..a224e7261 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/01-hooks/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Hooks" +} diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/README.md b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/README.md deleted file mode 100644 index dd6c3a722..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/README.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Sandbox ---- - -ignore me diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/cjs-dep/index.js b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/cjs-dep/index.js deleted file mode 100644 index 281fec0c3..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/cjs-dep/index.js +++ /dev/null @@ -1,9 +0,0 @@ -// line 1 -// line 2 -// line 2 -// line 2 -// line 2 -// line 2 -// line 2 -// line 2 -module.exports = () => 'wooo!!! cjs'; \ No newline at end of file diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/cjs-dep/package.json b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/cjs-dep/package.json deleted file mode 100644 index a2091cee3..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/cjs-dep/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "commonjs" -} \ No newline at end of file diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/esm-dep/index.js b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/esm-dep/index.js deleted file mode 100644 index 38e1306fd..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/esm-dep/index.js +++ /dev/null @@ -1 +0,0 @@ -export default () => 'wooo!!! esm'; \ No newline at end of file diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/esm-dep/package.json b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/esm-dep/package.json deleted file mode 100644 index 47dc78d39..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/node_modules/esm-dep/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} \ No newline at end of file diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/src/lib/b.js b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/src/lib/b.js deleted file mode 100644 index 7b9db73a0..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/src/lib/b.js +++ /dev/null @@ -1,3 +0,0 @@ -export function foo() { - return 42; -} diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/src/routes/+page.svelte deleted file mode 100644 index 1afc09501..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/src/routes/+page.svelte +++ /dev/null @@ -1 +0,0 @@ -

    sandbox

    diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/svelte.config.js b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/svelte.config.js deleted file mode 100644 index 301e785eb..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/svelte.config.js +++ /dev/null @@ -1,10 +0,0 @@ -import adapter from '@sveltejs/adapter-auto'; - -/** @type {import('@sveltejs/kit').Config} */ -const config = { - kit: { - adapter: adapter() - } -}; - -export default config; diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/vite.config.js b/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/vite.config.js deleted file mode 100644 index da06c515e..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/vite.config.js +++ /dev/null @@ -1,6 +0,0 @@ -/** @type {import('vite').UserConfig} */ -export default { - optimizeDeps: { - include: ['cjs-dep'] - } -}; diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/meta.json b/content/tutorial/04-advanced-sveltekit/01-todo/meta.json deleted file mode 100644 index 20a00a555..000000000 --- a/content/tutorial/04-advanced-sveltekit/01-todo/meta.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "title": "TODO" -} diff --git a/content/tutorial/04-advanced-sveltekit/02-stores/01-page-store/README.md b/content/tutorial/04-advanced-sveltekit/02-stores/01-page-store/README.md new file mode 100644 index 000000000..641a3f687 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/02-stores/01-page-store/README.md @@ -0,0 +1,5 @@ +--- +title: page +--- + +> Coming soon diff --git a/content/tutorial/04-advanced-sveltekit/02-stores/02-navigating-store/README.md b/content/tutorial/04-advanced-sveltekit/02-stores/02-navigating-store/README.md new file mode 100644 index 000000000..48cde502b --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/02-stores/02-navigating-store/README.md @@ -0,0 +1,5 @@ +--- +title: navigating +--- + +> Coming soon diff --git a/content/tutorial/04-advanced-sveltekit/02-stores/03-updated-store/README.md b/content/tutorial/04-advanced-sveltekit/02-stores/03-updated-store/README.md new file mode 100644 index 000000000..b892450a8 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/02-stores/03-updated-store/README.md @@ -0,0 +1,5 @@ +--- +title: updated +--- + +> Coming soon diff --git a/content/tutorial/04-advanced-sveltekit/02-stores/meta.json b/content/tutorial/04-advanced-sveltekit/02-stores/meta.json new file mode 100644 index 000000000..c70d14efe --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/02-stores/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Stores" +} diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/README.md b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/README.md new file mode 100644 index 000000000..e822b7f4f --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/README.md @@ -0,0 +1,28 @@ +--- +title: Optional parameters +--- + +In the first chapter on [routing](/tutorial/pages), we learned how to create routes with [dynamic parameters](/tutorial/params). + +Sometimes it's helpful to make a parameter optional. A classic example is when you use the pathname to determine the locale — `/fr/...`, `/de/...` and so on — but you also want to have a default locale. + +To do that, we use double brackets. Rename the `[lang]` directory to `[[lang]]`. + +The app now fails to build, because `src/routes/+page.svelte` and `src/routes/[[lang]]/+page.svelte` would both match `/`. Delete `src/routes/+page.svelte`. (You may need to reload the app to recover from the error page). + +Lastly, edit `src/routes/[[lang]]/+page.server.js` to specify the default locale: + +```js +/// file: src/routes/[[lang]]/+page.server.js +const greetings = { + en: 'hello!', + de: 'hallo!', + fr: 'bonjour!' +}; + +export function load({ params }) { + return { + greeting: greetings[params.lang +++?? 'en'+++] + }; +} +``` diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/+layout.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..1b7838205 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/+layout.svelte @@ -0,0 +1,8 @@ + + + diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..88e87e748 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    hello!

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/[lang]/+page.server.js b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/[lang]/+page.server.js new file mode 100644 index 000000000..3318ab14e --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/[lang]/+page.server.js @@ -0,0 +1,11 @@ +const greetings = { + en: 'hello!', + de: 'hallo!', + fr: 'bonjour!' +}; + +export function load({ params }) { + return { + greeting: greetings[params.lang] + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/[lang]/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/[lang]/+page.svelte new file mode 100644 index 000000000..a791437ec --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-a/src/routes/[lang]/+page.svelte @@ -0,0 +1,5 @@ + + +

    {data.greeting}

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..5d003dc7d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/+page.svelte @@ -0,0 +1 @@ +__delete; diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/[[lang]]/+page.server.js b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/[[lang]]/+page.server.js new file mode 100644 index 000000000..ded09d03b --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/[[lang]]/+page.server.js @@ -0,0 +1,11 @@ +const greetings = { + en: 'hello!', + de: 'hallo!', + fr: 'bonjour!' +}; + +export function load({ params }) { + return { + greeting: greetings[params.lang ?? 'en'] + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/[[lang]]/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/[[lang]]/+page.svelte new file mode 100644 index 000000000..a791437ec --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/[[lang]]/+page.svelte @@ -0,0 +1,5 @@ + + +

    {data.greeting}

    diff --git a/content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/src/lib/a.js b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/[lang]/__delete similarity index 100% rename from content/tutorial/04-advanced-sveltekit/01-todo/01-sandbox/app-a/src/lib/a.js rename to content/tutorial/04-advanced-sveltekit/03-advanced-routing/01-optional-params/app-b/src/routes/[lang]/__delete diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/README.md b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/README.md new file mode 100644 index 000000000..d003c037a --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/README.md @@ -0,0 +1,22 @@ +--- +title: Rest parameters +--- + +To match an unknown number of path segments, use a `[...rest]` parameter, so named for its resemblance to [rest parameters in JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters). + +Rename `src/routes/[path]` to `src/routes/[...path]`. The route now matches any path. + +> Other, more specific routes will be tested first, making rest parameters useful as 'catch-all' routes. For example, if you needed a custom 404 page for pages inside `/categories/...`, you could add these files: +> +> ```diff +> src/routes/ +> ├ categories/ +> │ ├ animal/ +> │ ├ mineral/ +> │ ├ vegetable/ +> +│ ├ [...catchall]/ +> +│ │ ├ +error.svelte +> +│ │ └ +page.server.js +> ``` +> +> Inside the `+page.server.js` file, `throw error(404)` inside `load`. diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-a/src/routes/[path]/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-a/src/routes/[path]/+page.svelte new file mode 100644 index 000000000..1b18eb336 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-a/src/routes/[path]/+page.svelte @@ -0,0 +1,31 @@ + + +{words[depth] ?? '?'} + + diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-b/src/routes/[...path]/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-b/src/routes/[...path]/+page.svelte new file mode 100644 index 000000000..1b18eb336 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-b/src/routes/[...path]/+page.svelte @@ -0,0 +1,31 @@ + + +{words[depth] ?? '?'} + + diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-b/src/routes/[path]/__delete b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-b/src/routes/[path]/__delete new file mode 100644 index 000000000..e69de29bb diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/README.md b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/README.md new file mode 100644 index 000000000..e39f0efb5 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/README.md @@ -0,0 +1,20 @@ +--- +title: Param matchers +--- + +To prevent the router from matching on invalid input, you can specify a _matcher_. For example, you might want a route like `/colors/[value]` to match hex values like `/colors/ff3e00` but not named colors like `/colors/octarine` or any other arbitrary input. + +First, create a new file called `src/params/hex.js` and export a `match` function from it: + +```js +/// file: src/params/hex.js +export function match(value) { + return /^[0-9a-f]{6}$/.test(value); +} +``` + +Then, to use the new matcher, rename `src/routes/colors/[color]` to `src/routes/colors/[color=hex]`. + +Now, whenever someone navigates to that route, SvelteKit will verify that `color` is a valid `hex` value. If not, SvelteKit will try to match other routes, before eventually returning a 404. + +> Matchers run both on the server and in the browser. diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/+layout.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..287ab0a77 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/+layout.svelte @@ -0,0 +1,26 @@ + + + + + + + diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..9fa39b3ef --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    color picker

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/colors/[color]/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/colors/[color]/+page.svelte new file mode 100644 index 000000000..6a6c4d6b9 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-a/src/routes/colors/[color]/+page.svelte @@ -0,0 +1,28 @@ + + +
    + #{$page.params.color} +
    + + diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-b/src/params/hex.js b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-b/src/params/hex.js new file mode 100644 index 000000000..e6887590a --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-b/src/params/hex.js @@ -0,0 +1,3 @@ +export function match(value) { + return /^[0-9a-f]{6}$/.test(value); +} diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-b/src/routes/colors/[color=hex]/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-b/src/routes/colors/[color=hex]/+page.svelte new file mode 100644 index 000000000..6a6c4d6b9 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-b/src/routes/colors/[color=hex]/+page.svelte @@ -0,0 +1,28 @@ + + +
    + #{$page.params.color} +
    + + diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-b/src/routes/colors/[color]/__delete b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/03-param-matchers/app-b/src/routes/colors/[color]/__delete new file mode 100644 index 000000000..e69de29bb diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/README.md b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/README.md new file mode 100644 index 000000000..9b28d4d5e --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/README.md @@ -0,0 +1,35 @@ +--- +title: Route groups +--- + +As we saw in the [routing introduction](/tutorial/layouts), layouts are a way to share UI and data loading logic between different routes. + +Sometimes it's useful to use layouts without affecting the route — for example, you might need your `/app` and `/account` routes to be behind authentication, while your `/about` page is open to the world. We can do this with a _route group_, which is a directory in parentheses. + +Create an `(authed)` group by renaming `account` to `(authed)/account` then renaming `app` to `(authed)/app`. + +Now we can control access to these routes by creating `src/routes/(authed)/+layout.server.js`: + +```js +/// file: src/routes/(authed)/+layout.server.js +import { redirect } from '@sveltejs/kit'; + +export function load({ cookies, url }) { + if (!cookies.get('logged_in')) { + throw redirect(307, `/login?redirectTo=${url.pathname}`); + } +} +``` + +If you try to visit these pages, you'll be redirected to the `/login` route, which has a form action in `src/routes/login/+page.server.js` that sets the `logged_in` cookie. + +We can also add some UI to these two routes by adding a `src/routes/(authed)/+layout.svelte` file: + +```svelte +/// file: src/routes/(authed)/+layout.svelte +
    + +
    + + +``` diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/+layout.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..fc8efa3fd --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/+layout.svelte @@ -0,0 +1,8 @@ + + + diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..eeec61273 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/+page.svelte @@ -0,0 +1,3 @@ +

    home

    + +

    this is the home page.

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/about/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/about/+page.svelte new file mode 100644 index 000000000..aa6882d72 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/about/+page.svelte @@ -0,0 +1,3 @@ +

    about

    + +

    this is the about page.

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/account/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/account/+page.svelte new file mode 100644 index 000000000..8bb052b58 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/account/+page.svelte @@ -0,0 +1,3 @@ +

    account

    + +

    this is the account page

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/app/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/app/+page.svelte new file mode 100644 index 000000000..9e2673c97 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/app/+page.svelte @@ -0,0 +1,3 @@ +

    app

    + +

    this is the app

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/login/+page.server.js b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/login/+page.server.js new file mode 100644 index 000000000..4cd9254f9 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/login/+page.server.js @@ -0,0 +1,8 @@ +import { redirect } from '@sveltejs/kit'; + +export const actions = { + default: ({ cookies, url }) => { + cookies.set('logged_in', 'true', { path: '/' }); + throw redirect(307, url.searchParams.get('redirectTo') ?? '/'); + } +}; diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/login/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/login/+page.svelte new file mode 100644 index 000000000..93bbe41a4 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/login/+page.svelte @@ -0,0 +1,5 @@ +

    log in

    + +
    + +
    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/logout/+page.server.js b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/logout/+page.server.js new file mode 100644 index 000000000..b0e98ae19 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-a/src/routes/logout/+page.server.js @@ -0,0 +1,8 @@ +import { redirect } from '@sveltejs/kit'; + +export const actions = { + default: ({ cookies }) => { + cookies.delete('logged_in', { path: '/' }); + throw redirect(307, '/'); + } +}; diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/+layout.server.js b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/+layout.server.js new file mode 100644 index 000000000..b952a183a --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/+layout.server.js @@ -0,0 +1,7 @@ +import { redirect } from '@sveltejs/kit'; + +export function load({ cookies, url }) { + if (!cookies.get('logged_in')) { + throw redirect(307, `/login?redirectTo=${url.pathname}`); + } +} diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/+layout.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/+layout.svelte new file mode 100644 index 000000000..d2e2c27f4 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/+layout.svelte @@ -0,0 +1,5 @@ + + +
    + +
    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/account/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/account/+page.svelte new file mode 100644 index 000000000..8bb052b58 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/account/+page.svelte @@ -0,0 +1,3 @@ +

    account

    + +

    this is the account page

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/app/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/app/+page.svelte new file mode 100644 index 000000000..9e2673c97 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/(authed)/app/+page.svelte @@ -0,0 +1,3 @@ +

    app

    + +

    this is the app

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/account/__delete b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/account/__delete new file mode 100644 index 000000000..8bb052b58 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/account/__delete @@ -0,0 +1,3 @@ +

    account

    + +

    this is the account page

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/app/__delete b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/app/__delete new file mode 100644 index 000000000..8bb052b58 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/04-route-groups/app-b/src/routes/app/__delete @@ -0,0 +1,3 @@ +

    account

    + +

    this is the account page

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/README.md b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/README.md new file mode 100644 index 000000000..a3484df9d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/README.md @@ -0,0 +1,16 @@ +--- +title: Breaking out of layouts +--- + +Ordinarily, a page inherits every layout above it, meaning that `src/routes/a/b/c/+page.svelte` inherits four layouts: + +- `src/routes/+layout.svelte` +- `src/routes/a/+layout.svelte` +- `src/routes/a/b/+layout.svelte` +- `src/routes/a/b/c/+layout.svelte` + +Occasionally, it's useful to break out of the current layout hierarchy. We can do that by adding the `@` sign followed by the name of the parent segment to 'reset' to — for example `+page@b.svelte` would put `/a/b/c` inside `src/routes/a/b/+layout.svelte`, while `+page@a.svelte` would put it inside `src/routes/a/+layout.svelte`. + +Let's reset it all the way to the root layout, by renaming it to `+page@.svelte`. + +> The root layout applies to every page of your app, you cannot break out of it. diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/+layout.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..d6c9a2ffa --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/+layout.svelte @@ -0,0 +1,30 @@ + + +
    + +
    + + diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..415b7b290 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/+page.svelte @@ -0,0 +1 @@ +

    home

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/+layout.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/+layout.svelte new file mode 100644 index 000000000..502a6de62 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/+layout.svelte @@ -0,0 +1,3 @@ +
    + +
    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/+page.svelte new file mode 100644 index 000000000..57f9d4079 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/+page.svelte @@ -0,0 +1 @@ +

    a

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/+layout.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/+layout.svelte new file mode 100644 index 000000000..0e7880ef2 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/+layout.svelte @@ -0,0 +1,3 @@ +
    + +
    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/+page.svelte new file mode 100644 index 000000000..e96ed3db8 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/+page.svelte @@ -0,0 +1 @@ +

    b

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/c/+layout.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/c/+layout.svelte new file mode 100644 index 000000000..c742401ed --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/c/+layout.svelte @@ -0,0 +1,3 @@ +
    + +
    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/c/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/c/+page.svelte new file mode 100644 index 000000000..232c276f8 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-a/src/routes/a/b/c/+page.svelte @@ -0,0 +1 @@ +

    c

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-b/src/routes/a/b/c/+page.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-b/src/routes/a/b/c/+page.svelte new file mode 100644 index 000000000..5d003dc7d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-b/src/routes/a/b/c/+page.svelte @@ -0,0 +1 @@ +__delete; diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-b/src/routes/a/b/c/+page@.svelte b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-b/src/routes/a/b/c/+page@.svelte new file mode 100644 index 000000000..232c276f8 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/app-b/src/routes/a/b/c/+page@.svelte @@ -0,0 +1 @@ +

    c

    diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/meta.json b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/meta.json new file mode 100644 index 000000000..7fbfd5b4f --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/05-breaking-out-of-layouts/meta.json @@ -0,0 +1,5 @@ +{ + "editing_constraints": { + "create": ["/src/routes/a/b/c/+page@b.svelte", "/src/routes/a/b/c/+page@a.svelte"] + } +} diff --git a/content/tutorial/04-advanced-sveltekit/03-advanced-routing/meta.json b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/meta.json new file mode 100644 index 000000000..79b00249d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/03-advanced-routing/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Advanced routing" +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/README.md b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/README.md new file mode 100644 index 000000000..f622d5a1e --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/README.md @@ -0,0 +1,40 @@ +--- +title: Using parent data +--- + +As we saw in the introduction to [layout data](/tutorial/layout-data), `+page.svelte` and `+layout.svelte` components have access to everything returned from their parent `load` functions. + +Occasionally it's useful for the `load` functions themselves to access data from their parents. This can be done with `await parent()`. + +To show how it works, we'll sum two numbers that come from different `load` functions. First, return some data from `src/routes/+layout.server.js`: + +```js +/// file: src/routes/+layout.server.js +export function load() { + return { +++a: 1+++ }; +} +``` + +Then, get that data in `src/routes/sum/+layout.js`: + +```js +/// file: src/routes/sum/+layout.js +export async function load(+++{ parent }+++) { + +++const { a } = await parent();+++ + return { +++b: a + 1+++ }; +} +``` + +> Notice that a [universal](/tutorial/universal-load-functions) `load` function can get data from a parent _server_ `load` function. The reverse is not true — a server load function can only get parent data from another server load function. + +Finally, in `src/routes/sum/+page.js`, get parent data from both `load` functions: + +```js +/// file: src/sum/+page.js +export async function load(+++{ parent }+++) { + +++const { a, b } = await parent();+++ + return { +++c: a + b+++ }; +} +``` + +> Take care not to introduce waterfalls when using `await parent()`. If you can `fetch` other data that is not dependent on parent data, do that first. diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/+layout.server.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/+layout.server.js new file mode 100644 index 000000000..f2504d211 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/+layout.server.js @@ -0,0 +1,3 @@ +export async function load() { + return {}; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..982aed344 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/+page.svelte @@ -0,0 +1,2 @@ +

    if a = 1 and b = a + 1, what is a + b?

    +show answer diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+layout.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+layout.js new file mode 100644 index 000000000..f2504d211 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+layout.js @@ -0,0 +1,3 @@ +export async function load() { + return {}; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+page.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+page.js new file mode 100644 index 000000000..f2504d211 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+page.js @@ -0,0 +1,3 @@ +export async function load() { + return {}; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+page.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+page.svelte new file mode 100644 index 000000000..f3ebf3235 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-a/src/routes/sum/+page.svelte @@ -0,0 +1,6 @@ + + +

    {data.a} + {data.b} = {data.c}

    +

    home

    diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/+layout.server.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/+layout.server.js new file mode 100644 index 000000000..3ca592053 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/+layout.server.js @@ -0,0 +1,3 @@ +export async function load() { + return { a: 1 }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/sum/+layout.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/sum/+layout.js new file mode 100644 index 000000000..5fcf59af0 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/sum/+layout.js @@ -0,0 +1,4 @@ +export async function load({ parent }) { + const { a } = await parent(); + return { b: a + 1 }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/sum/+page.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/sum/+page.js new file mode 100644 index 000000000..1a2674480 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/01-await-parent/app-b/src/routes/sum/+page.js @@ -0,0 +1,4 @@ +export async function load({ parent }) { + const { a, b } = await parent(); + return { c: a + b }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/README.md b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/README.md new file mode 100644 index 000000000..6b7cf8443 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/README.md @@ -0,0 +1,25 @@ +--- +title: Using both load functions +--- + +Occasionally, you might need to use a server load function and a universal load function together. For example, you might need to return data from the server, but also return a value that can't be serialized as server data. + +In this example we want to return a different component from `load` depending on whether the data we got from `src/routes/+page.server.js` is `cool` or not. + +We can access server data in `src/routes/+page.js` via the `data` property: + +```js +/// file: src/routes/+page.js +export async function load(+++{ data }+++) { + const module = +++data.cool+++ + ? await import('./CoolComponent.svelte') + : await import('./BoringComponent.svelte'); + + return { + component: module.default, + message: +++data.message+++ + }; +} +``` + +> Note that the data isn't merged — we must explicitly return `message` from the universal `load` function. diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.js new file mode 100644 index 000000000..e3669c214 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.js @@ -0,0 +1,10 @@ +export async function load() { + const module = false + ? await import('./CoolComponent.svelte') + : await import('./BoringComponent.svelte'); + + return { + component: module.default, + message: 'TODO add a message' + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.server.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.server.js new file mode 100644 index 000000000..81cfcbeaf --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.server.js @@ -0,0 +1,6 @@ +export async function load() { + return { + message: 'this data came from the server', + cool: true + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..736bcaa2f --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/+page.svelte @@ -0,0 +1,5 @@ + + + diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/BoringComponent.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/BoringComponent.svelte new file mode 100644 index 000000000..2a1aeca6d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/BoringComponent.svelte @@ -0,0 +1,5 @@ + + +

    {message}

    diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/CoolComponent.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/CoolComponent.svelte new file mode 100644 index 000000000..5681fe375 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-a/src/routes/CoolComponent.svelte @@ -0,0 +1,14 @@ + + + +

    {message}

    +
    + + diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-b/src/routes/+page.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-b/src/routes/+page.js new file mode 100644 index 000000000..826cb1b4a --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/02-using-both-load-functions/app-b/src/routes/+page.js @@ -0,0 +1,10 @@ +export async function load({ data }) { + const module = data.cool + ? await import('./CoolComponent.svelte') + : await import('./BoringComponent.svelte'); + + return { + component: module.default, + message: data.message + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/README.md b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/README.md new file mode 100644 index 000000000..9925141c4 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/README.md @@ -0,0 +1,40 @@ +--- +title: Invalidation +--- + +When the user navigates from one page to another, SvelteKit calls your `load` functions, but only if it thinks something has changed. + +In this example, navigating between timezones causes the `load` function in `src/routes/[...timezone]/+page.js` to re-run because `params.timezone` is invalid. But the `load` function in `src/routes/+layout.js` does _not_ re-run, because as far as SvelteKit is concerned it wasn't invalidated by the navigation. + +We can fix that by manually invalidating it using the [`invalidate(...)`](https://kit.svelte.dev/docs/modules#$app-navigation-invalidate) function, which takes a URL and re-runs any `load` functions that depend on it. Because the `load` function in `src/routes/+layout.js` calls `fetch('https://github.com/api/now')`, it depends on `/api/now`. + +In `src/routes/[...timezone]/+page.svelte`, add an `onMount` callback that calls `invalidate('/api/now')` once a second: + +```svelte +/// file: src/routes/[...timezone]/+page.svelte + + +

    + {new Intl.DateTimeFormat([], { + timeStyle: 'full', + timeZone: data.timezone + }).format(new Date(data.now))} +

    +``` + +> You can also pass a function to `invalidate`, in case you want to invalidate based on a pattern and not specific URLs diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+layout.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+layout.js new file mode 100644 index 000000000..782e4759d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+layout.js @@ -0,0 +1,8 @@ +export async function load({ fetch }) { + const response = await fetch('https://github.com/api/now'); + const now = await response.json(); + + return { + now + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+layout.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+layout.svelte new file mode 100644 index 000000000..0e6e3f44b --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+layout.svelte @@ -0,0 +1,13 @@ + + + diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+page.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+page.js new file mode 100644 index 000000000..714ceb10d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/+page.js @@ -0,0 +1,5 @@ +import { redirect } from '@sveltejs/kit'; + +export async function load() { + throw redirect(307, '/Europe/London'); +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/[...timezone]/+page.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/[...timezone]/+page.js new file mode 100644 index 000000000..6aa85ca1b --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/[...timezone]/+page.js @@ -0,0 +1,5 @@ +export function load({ params }) { + return { + timezone: params.timezone + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/[...timezone]/+page.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/[...timezone]/+page.svelte new file mode 100644 index 000000000..22976ce1c --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/[...timezone]/+page.svelte @@ -0,0 +1,10 @@ + + +

    + {new Intl.DateTimeFormat([], { + timeStyle: 'full', + timeZone: data.timezone + }).format(new Date(data.now))} +

    diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/api/now/+server.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/api/now/+server.js new file mode 100644 index 000000000..cd8acc36d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-a/src/routes/api/now/+server.js @@ -0,0 +1,5 @@ +import { json } from '@sveltejs/kit'; + +export function GET() { + return json(Date.now()); +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-b/src/routes/[...timezone]/+page.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-b/src/routes/[...timezone]/+page.svelte new file mode 100644 index 000000000..6722ef9f0 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/03-invalidation/app-b/src/routes/[...timezone]/+page.svelte @@ -0,0 +1,23 @@ + + +

    + {new Intl.DateTimeFormat([], { + timeStyle: 'full', + timeZone: data.timezone + }).format(new Date(data.now))} +

    diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/README.md b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/README.md new file mode 100644 index 000000000..bb0503d66 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/README.md @@ -0,0 +1,42 @@ +--- +title: Custom dependencies +--- + +Calling `fetch(url)` inside a `load` function registers `url` as a dependency. Sometimes it's not appropriate to use `fetch`, in which case you can specify a dependency manually with the [`depends(url)`](https://kit.svelte.dev/docs/load#invalidation-manual-invalidation) function. + +Since any string that begins with an `[a-z]+:` pattern is a valid URL, we can create custom invalidation keys like `data:now`. + +Update `src/routes/+layout.js` to return a value directly rather than making a `fetch` call, and add the `depends`: + +```js +/// file: src/routes/+layout.js +export async function load({ +++depends+++ }) { + +++depends('data:now');+++ + + return { + now: +++Date.now()+++ + }; +} +``` + +Now, update the `invalidate` call in `src/routes/[...timezone]/+page.svelte`: + +```svelte +/// file: src/routes/[...timezone]/+page.svelte + +``` diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/app-b/src/routes/+layout.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/app-b/src/routes/+layout.js new file mode 100644 index 000000000..9c3bab4f6 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/app-b/src/routes/+layout.js @@ -0,0 +1,7 @@ +export async function load({ depends }) { + depends('data:now'); + + return { + now: Date.now() + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/app-b/src/routes/[...timezone]/+page.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/app-b/src/routes/[...timezone]/+page.svelte new file mode 100644 index 000000000..7fcdc2471 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/04-custom-dependencies/app-b/src/routes/[...timezone]/+page.svelte @@ -0,0 +1,23 @@ + + +

    + {new Intl.DateTimeFormat([], { + timeStyle: 'full', + timeZone: data.timezone + }).format(new Date(data.now))} +

    diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/README.md b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/README.md new file mode 100644 index 000000000..afd34b194 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/README.md @@ -0,0 +1,42 @@ +--- +title: invalidateAll +--- + +Finally, there's the nuclear option — `invalidateAll()`. This will indiscriminately re-run all `load` functions for the current page, regardless of what they depend on. + +Update `src/routes/[...timezone]/+page.svelte` from the previous exercise: + +```svelte +/// file: src/routes/[...timezone]/+page.svelte + +``` + +The `depends` call in `src/routes/+layout.js` is no longer necessary: + +```js +/// file: src/routes/+layout.js +export async function load(---{ depends }---) { + ---depends('data:now');--- + + return { + now: Date.now() + }; +} +``` + +> `invalidate(() => true)` and `invalidateAll` are _not_ the same. `invalidateAll` also re-runs `load` functions without any `url` dependencies, which `invalidate(() => true)` does not. diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/app-b/src/routes/+layout.js b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/app-b/src/routes/+layout.js new file mode 100644 index 000000000..6638f2246 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/app-b/src/routes/+layout.js @@ -0,0 +1,5 @@ +export async function load() { + return { + now: Date.now() + }; +} diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/app-b/src/routes/[...timezone]/+page.svelte b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/app-b/src/routes/[...timezone]/+page.svelte new file mode 100644 index 000000000..4276591f6 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/05-invalidate-all/app-b/src/routes/[...timezone]/+page.svelte @@ -0,0 +1,23 @@ + + +

    + {new Intl.DateTimeFormat([], { + timeStyle: 'full', + timeZone: data.timezone + }).format(new Date(data.now))} +

    diff --git a/content/tutorial/04-advanced-sveltekit/04-advanced-loading/meta.json b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/meta.json new file mode 100644 index 000000000..3c359db66 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/04-advanced-loading/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Advanced loading" +} diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/README.md b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/README.md new file mode 100644 index 000000000..be3a2abd7 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/README.md @@ -0,0 +1,91 @@ +--- +title: $env/static/private +--- + +Environment variables — like API keys and database credentials — can be added to a `.env` file, and they will be made available to your application. + +> You can also use `.env.local` or `.env.[mode]` files — see the [Vite documentation](https://vitejs.dev/guide/env-and-mode.html#env-files) for more information). Make sure you add any files containing sensitive information to your `.gitignore` file! + +In this exercise, we want to allow the user to enter the website if they know the correct passphrase, using an environment variable. + +First, in `.env`, add a new environment variable: + +```env +/// file: .env +PASSPHRASE=+++"open sesame"+++ +``` + +Open `src/routes/+page.server.js`. Import `PASSPHRASE` from `$env/static/private` and use it inside the [form action](/tutorial/the-form-element): + +```js +/// file: src/routes/+page.server.js +import { redirect, fail } from '@sveltejs/kit'; ++++import { PASSPHRASE } from '$env/static/private';+++ + +export function load({ cookies }) { + if (cookies.get('allowed')) { + throw redirect(307, '/welcome'); + } +} + +export const actions = { + default: async ({ request, cookies }) => { + const data = await request.formData(); + + if (data.get('passphrase') === +++PASSPHRASE+++) { + cookies.set('allowed', 'true', { + path: '/' + }); + + throw redirect(303, '/welcome'); + } + + return fail(403, { + incorrect: true + }); + } +}; +``` + +The website is now accessible to anyone who knows the correct passphrase. + +> Environment variables in `process.env` are also available via `$env/static/private`. + +## Keeping secrets + +It's important that sensitive data doesn't accidentally end up being sent to the browser, where it could easily be stolen by hackers and scoundrels. + +SvelteKit makes it easy to prevent this from happening. Notice what happens if we try to import `PASSPHRASE` into `src/routes/+page.svelte`: + +```svelte +/// file: src/routes/+page.svelte + +``` + +An error overlay pops up, telling us that `$env/static/private` cannot be imported into client-side code. It can only be imported into server modules: + +- `+page.server.js` +- `+layout.server.js` +- `+server.js` +- any modules ending with `.server.js` +- any modules inside `src/lib/server` + +In turn, these modules can only be imported by _other_ server modules. + +## Static vs dynamic + +The `static` in `$env/static/private` indicates that these values are known at build time, and can be _statically replaced_. This enables useful optimisations: + +```js +import { FEATURE_FLAG_X } from '$env/static/private'; + +if (FEATURE_FLAG_X === 'enabled') { + // code in here will be removed from the build output + // if FEATURE_FLAG_X is not enabled +} +``` + +In some cases you might need to refer to environment variables that are _dynamic_ — in other words, not known until we run the app. We'll cover this case in the next exercise. diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/.env b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/.env new file mode 100644 index 000000000..33ea5138a --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/.env @@ -0,0 +1 @@ +PASSPHRASE= \ No newline at end of file diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/+page.server.js b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/+page.server.js new file mode 100644 index 000000000..ebd2be099 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/+page.server.js @@ -0,0 +1,25 @@ +import { redirect, fail } from '@sveltejs/kit'; + +export function load({ cookies }) { + if (cookies.get('allowed')) { + throw redirect(307, '/welcome'); + } +} + +export const actions = { + default: async ({ request, cookies }) => { + const data = await request.formData(); + + if (data.get('passphrase') === 'TODO') { + cookies.set('allowed', 'true', { + path: '/' + }); + + throw redirect(303, '/welcome'); + } + + return fail(403, { + incorrect: true + }); + } +}; diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..a848d87bb --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/+page.svelte @@ -0,0 +1,20 @@ + + +
    + +
    + +{#if form?.incorrect} +

    wrong passphrase!

    +{/if} + + diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/welcome/+page.server.js b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/welcome/+page.server.js new file mode 100644 index 000000000..87b01cea1 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/welcome/+page.server.js @@ -0,0 +1,15 @@ +import { redirect } from '@sveltejs/kit'; +import { error } from '@sveltejs/kit'; + +export function load({ cookies }) { + if (!cookies.get('allowed')) { + throw error(403, 'Forbidden'); + } +} + +export const actions = { + default: ({ cookies }) => { + cookies.delete('allowed', { path: '/' }); + throw redirect(303, '/'); + } +}; diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/welcome/+page.svelte b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/welcome/+page.svelte new file mode 100644 index 000000000..3a1970178 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-a/src/routes/welcome/+page.svelte @@ -0,0 +1,5 @@ +

    welcome!

    + +
    + +
    diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-b/.env b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-b/.env new file mode 100644 index 000000000..f090472cc --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-b/.env @@ -0,0 +1 @@ +PASSPHRASE="open sesame" \ No newline at end of file diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-b/src/routes/+page.server.js b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..761edc1d0 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/01-env-static-private/app-b/src/routes/+page.server.js @@ -0,0 +1,26 @@ +import { redirect, fail } from '@sveltejs/kit'; +import { PASSPHRASE } from '$env/static/private'; + +export function load({ cookies }) { + if (cookies.get('allowed')) { + throw redirect(307, '/welcome'); + } +} + +export const actions = { + default: async ({ request, cookies }) => { + const data = await request.formData(); + + if (data.get('passphrase') === PASSPHRASE) { + cookies.set('allowed', 'true', { + path: '/' + }); + + throw redirect(303, '/welcome'); + } + + return fail(403, { + incorrect: true + }); + } +}; diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/02-env-dynamic-private/README.md b/content/tutorial/04-advanced-sveltekit/05-environment-variables/02-env-dynamic-private/README.md new file mode 100644 index 000000000..4f7051798 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/02-env-dynamic-private/README.md @@ -0,0 +1,36 @@ +--- +title: $env/dynamic/private +--- + +If you need to read the values of environment variables when the app runs, as opposed to when the app is built, you can use `$env/dynamic/private` instead of `$env/static/private`: + +```js +/// file: src/routes/+page.server.js +import { redirect, fail } from '@sveltejs/kit'; +import { +++env+++ } from '$env/+++dynamic+++/private'; + +export function load({ cookies }) { + if (cookies.get('allowed')) { + throw redirect(307, '/welcome'); + } +} + +export const actions = { + default: async ({ request, cookies }) => { + const data = await request.formData(); + + if (data.get('passphrase') === +++env.+++PASSPHRASE) { + cookies.set('allowed', 'true', { + path: '/' + }); + + throw redirect(303, '/welcome'); + } + + return fail(403, { + incorrect: true + }); + } +}; + +``` diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/02-env-dynamic-private/app-b/src/routes/+page.server.js b/content/tutorial/04-advanced-sveltekit/05-environment-variables/02-env-dynamic-private/app-b/src/routes/+page.server.js new file mode 100644 index 000000000..3339bff13 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/02-env-dynamic-private/app-b/src/routes/+page.server.js @@ -0,0 +1,26 @@ +import { redirect, fail } from '@sveltejs/kit'; +import { env } from '$env/dynamic/private'; + +export function load({ cookies }) { + if (cookies.get('allowed')) { + throw redirect(307, '/welcome'); + } +} + +export const actions = { + default: async ({ request, cookies }) => { + const data = await request.formData(); + + if (data.get('passphrase') === env.PASSPHRASE) { + cookies.set('allowed', 'true', { + path: '/' + }); + + throw redirect(303, '/welcome'); + } + + return fail(403, { + incorrect: true + }); + } +}; diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/README.md b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/README.md new file mode 100644 index 000000000..2f4e10d22 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/README.md @@ -0,0 +1,26 @@ +--- +title: $env/static/public +--- + +Some environment variables _can_ be safely exposed to the browser. These are distinguished from private environment variables with a `PUBLIC_` prefix. + +Add values to the two public environment variables in `.env`: + +```env +PUBLIC_THEME_BACKGROUND=+++"steelblue"+++ +PUBLIC_THEME_FOREGROUND=+++"bisque"+++ +``` + +Then, import them into `src/routes/+page.svelte`: + +```svelte +/// file: src/routes/+page.svelte + +``` diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-a/.env b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-a/.env new file mode 100644 index 000000000..598d2ba2c --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-a/.env @@ -0,0 +1,2 @@ +PUBLIC_THEME_BACKGROUND= +PUBLIC_THEME_FOREGROUND= \ No newline at end of file diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-a/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-a/src/routes/+page.svelte new file mode 100644 index 000000000..846ee5734 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-a/src/routes/+page.svelte @@ -0,0 +1,25 @@ + + +
    + {PUBLIC_THEME_FOREGROUND} on {PUBLIC_THEME_BACKGROUND} +
    + + diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-b/.env b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-b/.env new file mode 100644 index 000000000..b5880e0f0 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-b/.env @@ -0,0 +1,2 @@ +PUBLIC_THEME_BACKGROUND="steelblue" +PUBLIC_THEME_FOREGROUND="bisque" \ No newline at end of file diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-b/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..1b1eff3cb --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/03-env-static-public/app-b/src/routes/+page.svelte @@ -0,0 +1,27 @@ + + +
    + {PUBLIC_THEME_FOREGROUND} on {PUBLIC_THEME_BACKGROUND} +
    + + diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/04-env-dynamic-public/README.md b/content/tutorial/04-advanced-sveltekit/05-environment-variables/04-env-dynamic-public/README.md new file mode 100644 index 000000000..8f0bb8ee9 --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/04-env-dynamic-public/README.md @@ -0,0 +1,18 @@ +--- +title: $env/static/public +--- + +As with [private environment variables](/tutorial/env-static-private), it's preferable to use static values if possible, but if necessary we can use dynamic values instead: + +```svelte + + +
    + {+++env.+++PUBLIC_THEME_FOREGROUND} on {+++env.+++PUBLIC_THEME_BACKGROUND} +
    +``` diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/04-env-dynamic-public/app-b/src/routes/+page.svelte b/content/tutorial/04-advanced-sveltekit/05-environment-variables/04-env-dynamic-public/app-b/src/routes/+page.svelte new file mode 100644 index 000000000..f305b3b4d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/04-env-dynamic-public/app-b/src/routes/+page.svelte @@ -0,0 +1,24 @@ + + +
    + {env.PUBLIC_THEME_FOREGROUND} on {env.PUBLIC_THEME_BACKGROUND} +
    + + diff --git a/content/tutorial/04-advanced-sveltekit/05-environment-variables/meta.json b/content/tutorial/04-advanced-sveltekit/05-environment-variables/meta.json new file mode 100644 index 000000000..6f066bc4d --- /dev/null +++ b/content/tutorial/04-advanced-sveltekit/05-environment-variables/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Environment variables" +} diff --git a/content/tutorial/common/package-lock.json b/content/tutorial/common/package-lock.json new file mode 100644 index 000000000..b5bcfb4da --- /dev/null +++ b/content/tutorial/common/package-lock.json @@ -0,0 +1,1440 @@ +{ + "name": "~TODO~", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "~TODO~", + "version": "0.0.1", + "devDependencies": { + "@sveltejs/kit": "next", + "esbuild-wasm": "^0.16.4", + "svelte": "^3.54.0", + "vite": "^4.0.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.4.tgz", + "integrity": "sha512-rZzb7r22m20S1S7ufIc6DC6W659yxoOrl7sKP1nCYhuvUlnCFHVSbATG4keGUtV8rDz11sRRDbWkvQZpzPaHiw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.4.tgz", + "integrity": "sha512-VPuTzXFm/m2fcGfN6CiwZTlLzxrKsWbPkG7ArRFpuxyaHUm/XFHQPD4xNwZT6uUmpIHhnSjcaCmcla8COzmZ5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.4.tgz", + "integrity": "sha512-MW+B2O++BkcOfMWmuHXB15/l1i7wXhJFqbJhp82IBOais8RBEQv2vQz/jHrDEHaY2X0QY7Wfw86SBL2PbVOr0g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.4.tgz", + "integrity": "sha512-a28X1O//aOfxwJVZVs7ZfM8Tyih2Za4nKJrBwW5Wm4yKsnwBy9aiS/xwpxiiTRttw3EaTg4Srerhcm6z0bu9Wg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.4.tgz", + "integrity": "sha512-e3doCr6Ecfwd7VzlaQqEPrnbvvPjE9uoTpxG5pyLzr2rI2NMjDHmvY1E5EO81O/e9TUOLLkXA5m6T8lfjK9yAA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.4.tgz", + "integrity": "sha512-Oup3G/QxBgvvqnXWrBed7xxkFNwAwJVHZcklWyQt7YCAL5bfUkaa6FVWnR78rNQiM8MqqLiT6ZTZSdUFuVIg1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.4.tgz", + "integrity": "sha512-vAP+eYOxlN/Bpo/TZmzEQapNS8W1njECrqkTpNgvXskkkJC2AwOXwZWai/Kc2vEFZUXQttx6UJbj9grqjD/+9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.4.tgz", + "integrity": "sha512-A47ZmtpIPyERxkSvIv+zLd6kNIOtJH03XA0Hy7jaceRDdQaQVGSDt4mZqpWqJYgDk9rg96aglbF6kCRvPGDSUA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.4.tgz", + "integrity": "sha512-2zXoBhv4r5pZiyjBKrOdFP4CXOChxXiYD50LRUU+65DkdS5niPFHbboKZd/c81l0ezpw7AQnHeoCy5hFrzzs4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.4.tgz", + "integrity": "sha512-uxdSrpe9wFhz4yBwt2kl2TxS/NWEINYBUFIxQtaEVtglm1eECvsj1vEKI0KX2k2wCe17zDdQ3v+jVxfwVfvvjw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.4.tgz", + "integrity": "sha512-peDrrUuxbZ9Jw+DwLCh/9xmZAk0p0K1iY5d2IcwmnN+B87xw7kujOkig6ZRcZqgrXgeRGurRHn0ENMAjjD5DEg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.4.tgz", + "integrity": "sha512-sD9EEUoGtVhFjjsauWjflZklTNr57KdQ6xfloO4yH1u7vNQlOfAlhEzbyBKfgbJlW7rwXYBdl5/NcZ+Mg2XhQA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.4.tgz", + "integrity": "sha512-X1HSqHUX9D+d0l6/nIh4ZZJ94eQky8d8z6yxAptpZE3FxCWYWvTDd9X9ST84MGZEJx04VYUD/AGgciddwO0b8g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.4.tgz", + "integrity": "sha512-97ANpzyNp0GTXCt6SRdIx1ngwncpkV/z453ZuxbnBROCJ5p/55UjhbaG23UdHj88fGWLKPFtMoU4CBacz4j9FA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.4.tgz", + "integrity": "sha512-pUvPQLPmbEeJRPjP0DYTC1vjHyhrnCklQmCGYbipkep+oyfTn7GTBJXoPodR7ZS5upmEyc8lzAkn2o29wD786A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.4.tgz", + "integrity": "sha512-N55Q0mJs3Sl8+utPRPBrL6NLYZKBCLLx0bme/+RbjvMforTGGzFvsRl4xLTZMUBFC1poDzBEPTEu5nxizQ9Nlw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.4.tgz", + "integrity": "sha512-LHSJLit8jCObEQNYkgsDYBh2JrJT53oJO2HVdkSYLa6+zuLJh0lAr06brXIkljrlI+N7NNW1IAXGn/6IZPi3YQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.4.tgz", + "integrity": "sha512-nLgdc6tWEhcCFg/WVFaUxHcPK3AP/bh+KEwKtl69Ay5IBqUwKDaq/6Xk0E+fh/FGjnLwqFSsarsbPHeKM8t8Sw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.4.tgz", + "integrity": "sha512-08SluG24GjPO3tXKk95/85n9kpyZtXCVwURR2i4myhrOfi3jspClV0xQQ0W0PYWHioJj+LejFMt41q+PG3mlAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.4.tgz", + "integrity": "sha512-yYiRDQcqLYQSvNQcBKN7XogbrSvBE45FEQdH8fuXPl7cngzkCvpsG2H9Uey39IjQ6gqqc+Q4VXYHsQcKW0OMjQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.4.tgz", + "integrity": "sha512-5rabnGIqexekYkh9zXG5waotq8mrdlRoBqAktjx2W3kb0zsI83mdCwrcAeKYirnUaTGztR5TxXcXmQrEzny83w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.4.tgz", + "integrity": "sha512-sN/I8FMPtmtT2Yw+Dly8Ur5vQ5a/RmC8hW7jO9PtPSQUPkowxWpcUZnqOggU7VwyT3Xkj6vcXWd3V/qTXwultQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", + "dev": true + }, + "node_modules/@sveltejs/kit": { + "version": "1.0.0-next.584", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.584.tgz", + "integrity": "sha512-iBfrrwkza1szR1GVMorTjj1Yw3SXhDVB5MMdDzCMKqKcCwxCehQ3K6QnlmyXHtHg2qX5rfvz0cpkp0uGGmcxQw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@sveltejs/vite-plugin-svelte": "^2.0.0", + "@types/cookie": "^0.5.1", + "cookie": "^0.5.0", + "devalue": "^4.2.0", + "esm-env": "^1.0.0", + "kleur": "^4.1.5", + "magic-string": "^0.27.0", + "mime": "^3.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.5.1", + "sirv": "^2.0.2", + "tiny-glob": "^0.2.9", + "undici": "5.14.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "svelte": "^3.54.0", + "vite": "^4.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.0.2.tgz", + "integrity": "sha512-xCEan0/NNpQuL0l5aS42FjwQ6wwskdxC3pW1OeFtEKNZwRg7Evro9lac9HesGP6TdFsTv2xMes5ASQVKbCacxg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "deepmerge": "^4.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.27.0", + "svelte-hmr": "^0.15.1", + "vitefu": "^0.2.3" + }, + "engines": { + "node": "^14.18.0 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.54.0", + "vite": "^4.0.0" + } + }, + "node_modules/@types/cookie": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz", + "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", + "dev": true + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/devalue": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.2.0.tgz", + "integrity": "sha512-mbjoAaCL2qogBKgeFxFPOXAUsZchircF+B/79LD4sHH0+NHfYm8gZpQrskKDn5gENGt35+5OI1GUF7hLVnkPDw==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.4.tgz", + "integrity": "sha512-qQrPMQpPTWf8jHugLWHoGqZjApyx3OEm76dlTXobHwh/EBbavbRdjXdYi/GWr43GyN0sfpap14GPkb05NH3ROA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.4", + "@esbuild/android-arm64": "0.16.4", + "@esbuild/android-x64": "0.16.4", + "@esbuild/darwin-arm64": "0.16.4", + "@esbuild/darwin-x64": "0.16.4", + "@esbuild/freebsd-arm64": "0.16.4", + "@esbuild/freebsd-x64": "0.16.4", + "@esbuild/linux-arm": "0.16.4", + "@esbuild/linux-arm64": "0.16.4", + "@esbuild/linux-ia32": "0.16.4", + "@esbuild/linux-loong64": "0.16.4", + "@esbuild/linux-mips64el": "0.16.4", + "@esbuild/linux-ppc64": "0.16.4", + "@esbuild/linux-riscv64": "0.16.4", + "@esbuild/linux-s390x": "0.16.4", + "@esbuild/linux-x64": "0.16.4", + "@esbuild/netbsd-x64": "0.16.4", + "@esbuild/openbsd-x64": "0.16.4", + "@esbuild/sunos-x64": "0.16.4", + "@esbuild/win32-arm64": "0.16.4", + "@esbuild/win32-ia32": "0.16.4", + "@esbuild/win32-x64": "0.16.4" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.16.4.tgz", + "integrity": "sha512-Nh7aa9uazooaEIGubc8s0nQZFhnf035pJMTpMPBonzDchN6RPsQES5bojQo3zT2xSAuC9nEMg8Nxzc1iwigETw==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.3.tgz", + "integrity": "sha512-7e68MQbAWCX6mI4/0lG1WHd+NdNAlVamg0Zkd+8LZ/oXojligdGnCNyHlzXqXCZObyjs5FRc3AH0b17iJESGIQ==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz", + "integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "3.54.0", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.54.0.tgz", + "integrity": "sha512-tdrgeJU0hob0ZWAMoKXkhcxXA7dpTg6lZGxUeko5YqvPdJBiyRspGsCwV27kIrbrqPP2WUoSV9ca0gnLlw8YzQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/svelte-hmr": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.1.tgz", + "integrity": "sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==", + "dev": true, + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": ">=3.19.0" + } + }, + "node_modules/tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "dependencies": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "node_modules/totalist": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz", + "integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/undici": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=12.18" + } + }, + "node_modules/vite": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.0.tgz", + "integrity": "sha512-ynad+4kYs8Jcnn8J7SacS9vAbk7eMy0xWg6E7bAhS1s79TK+D7tVFGXVZ55S7RNLRROU1rxoKlvZ/qjaB41DGA==", + "dev": true, + "dependencies": { + "esbuild": "^0.16.3", + "postcss": "^8.4.19", + "resolve": "^1.22.1", + "rollup": "^3.7.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.3.tgz", + "integrity": "sha512-75l7TTuU8isAhz1QFtNKjDkqjxvndfMC1AfIMjJ0ZQ59ZD0Ow9QOIsJJX16Wv9PS8f+zMzp6fHy5cCbKG/yVUQ==", + "dev": true, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + } + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.4.tgz", + "integrity": "sha512-rZzb7r22m20S1S7ufIc6DC6W659yxoOrl7sKP1nCYhuvUlnCFHVSbATG4keGUtV8rDz11sRRDbWkvQZpzPaHiw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.4.tgz", + "integrity": "sha512-VPuTzXFm/m2fcGfN6CiwZTlLzxrKsWbPkG7ArRFpuxyaHUm/XFHQPD4xNwZT6uUmpIHhnSjcaCmcla8COzmZ5Q==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.4.tgz", + "integrity": "sha512-MW+B2O++BkcOfMWmuHXB15/l1i7wXhJFqbJhp82IBOais8RBEQv2vQz/jHrDEHaY2X0QY7Wfw86SBL2PbVOr0g==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.4.tgz", + "integrity": "sha512-a28X1O//aOfxwJVZVs7ZfM8Tyih2Za4nKJrBwW5Wm4yKsnwBy9aiS/xwpxiiTRttw3EaTg4Srerhcm6z0bu9Wg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.4.tgz", + "integrity": "sha512-e3doCr6Ecfwd7VzlaQqEPrnbvvPjE9uoTpxG5pyLzr2rI2NMjDHmvY1E5EO81O/e9TUOLLkXA5m6T8lfjK9yAA==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.4.tgz", + "integrity": "sha512-Oup3G/QxBgvvqnXWrBed7xxkFNwAwJVHZcklWyQt7YCAL5bfUkaa6FVWnR78rNQiM8MqqLiT6ZTZSdUFuVIg1w==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.4.tgz", + "integrity": "sha512-vAP+eYOxlN/Bpo/TZmzEQapNS8W1njECrqkTpNgvXskkkJC2AwOXwZWai/Kc2vEFZUXQttx6UJbj9grqjD/+9Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.4.tgz", + "integrity": "sha512-A47ZmtpIPyERxkSvIv+zLd6kNIOtJH03XA0Hy7jaceRDdQaQVGSDt4mZqpWqJYgDk9rg96aglbF6kCRvPGDSUA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.4.tgz", + "integrity": "sha512-2zXoBhv4r5pZiyjBKrOdFP4CXOChxXiYD50LRUU+65DkdS5niPFHbboKZd/c81l0ezpw7AQnHeoCy5hFrzzs4g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.4.tgz", + "integrity": "sha512-uxdSrpe9wFhz4yBwt2kl2TxS/NWEINYBUFIxQtaEVtglm1eECvsj1vEKI0KX2k2wCe17zDdQ3v+jVxfwVfvvjw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.4.tgz", + "integrity": "sha512-peDrrUuxbZ9Jw+DwLCh/9xmZAk0p0K1iY5d2IcwmnN+B87xw7kujOkig6ZRcZqgrXgeRGurRHn0ENMAjjD5DEg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.4.tgz", + "integrity": "sha512-sD9EEUoGtVhFjjsauWjflZklTNr57KdQ6xfloO4yH1u7vNQlOfAlhEzbyBKfgbJlW7rwXYBdl5/NcZ+Mg2XhQA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.4.tgz", + "integrity": "sha512-X1HSqHUX9D+d0l6/nIh4ZZJ94eQky8d8z6yxAptpZE3FxCWYWvTDd9X9ST84MGZEJx04VYUD/AGgciddwO0b8g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.4.tgz", + "integrity": "sha512-97ANpzyNp0GTXCt6SRdIx1ngwncpkV/z453ZuxbnBROCJ5p/55UjhbaG23UdHj88fGWLKPFtMoU4CBacz4j9FA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.4.tgz", + "integrity": "sha512-pUvPQLPmbEeJRPjP0DYTC1vjHyhrnCklQmCGYbipkep+oyfTn7GTBJXoPodR7ZS5upmEyc8lzAkn2o29wD786A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.4.tgz", + "integrity": "sha512-N55Q0mJs3Sl8+utPRPBrL6NLYZKBCLLx0bme/+RbjvMforTGGzFvsRl4xLTZMUBFC1poDzBEPTEu5nxizQ9Nlw==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.4.tgz", + "integrity": "sha512-LHSJLit8jCObEQNYkgsDYBh2JrJT53oJO2HVdkSYLa6+zuLJh0lAr06brXIkljrlI+N7NNW1IAXGn/6IZPi3YQ==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.4.tgz", + "integrity": "sha512-nLgdc6tWEhcCFg/WVFaUxHcPK3AP/bh+KEwKtl69Ay5IBqUwKDaq/6Xk0E+fh/FGjnLwqFSsarsbPHeKM8t8Sw==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.4.tgz", + "integrity": "sha512-08SluG24GjPO3tXKk95/85n9kpyZtXCVwURR2i4myhrOfi3jspClV0xQQ0W0PYWHioJj+LejFMt41q+PG3mlAQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.4.tgz", + "integrity": "sha512-yYiRDQcqLYQSvNQcBKN7XogbrSvBE45FEQdH8fuXPl7cngzkCvpsG2H9Uey39IjQ6gqqc+Q4VXYHsQcKW0OMjQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.4.tgz", + "integrity": "sha512-5rabnGIqexekYkh9zXG5waotq8mrdlRoBqAktjx2W3kb0zsI83mdCwrcAeKYirnUaTGztR5TxXcXmQrEzny83w==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.4.tgz", + "integrity": "sha512-sN/I8FMPtmtT2Yw+Dly8Ur5vQ5a/RmC8hW7jO9PtPSQUPkowxWpcUZnqOggU7VwyT3Xkj6vcXWd3V/qTXwultQ==", + "dev": true, + "optional": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", + "dev": true + }, + "@sveltejs/kit": { + "version": "1.0.0-next.584", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.584.tgz", + "integrity": "sha512-iBfrrwkza1szR1GVMorTjj1Yw3SXhDVB5MMdDzCMKqKcCwxCehQ3K6QnlmyXHtHg2qX5rfvz0cpkp0uGGmcxQw==", + "dev": true, + "requires": { + "@sveltejs/vite-plugin-svelte": "^2.0.0", + "@types/cookie": "^0.5.1", + "cookie": "^0.5.0", + "devalue": "^4.2.0", + "esm-env": "^1.0.0", + "kleur": "^4.1.5", + "magic-string": "^0.27.0", + "mime": "^3.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.5.1", + "sirv": "^2.0.2", + "tiny-glob": "^0.2.9", + "undici": "5.14.0" + } + }, + "@sveltejs/vite-plugin-svelte": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.0.2.tgz", + "integrity": "sha512-xCEan0/NNpQuL0l5aS42FjwQ6wwskdxC3pW1OeFtEKNZwRg7Evro9lac9HesGP6TdFsTv2xMes5ASQVKbCacxg==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "deepmerge": "^4.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.27.0", + "svelte-hmr": "^0.15.1", + "vitefu": "^0.2.3" + } + }, + "@types/cookie": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz", + "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", + "dev": true + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "requires": { + "streamsearch": "^1.1.0" + } + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "devalue": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.2.0.tgz", + "integrity": "sha512-mbjoAaCL2qogBKgeFxFPOXAUsZchircF+B/79LD4sHH0+NHfYm8gZpQrskKDn5gENGt35+5OI1GUF7hLVnkPDw==", + "dev": true + }, + "esbuild": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.4.tgz", + "integrity": "sha512-qQrPMQpPTWf8jHugLWHoGqZjApyx3OEm76dlTXobHwh/EBbavbRdjXdYi/GWr43GyN0sfpap14GPkb05NH3ROA==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.16.4", + "@esbuild/android-arm64": "0.16.4", + "@esbuild/android-x64": "0.16.4", + "@esbuild/darwin-arm64": "0.16.4", + "@esbuild/darwin-x64": "0.16.4", + "@esbuild/freebsd-arm64": "0.16.4", + "@esbuild/freebsd-x64": "0.16.4", + "@esbuild/linux-arm": "0.16.4", + "@esbuild/linux-arm64": "0.16.4", + "@esbuild/linux-ia32": "0.16.4", + "@esbuild/linux-loong64": "0.16.4", + "@esbuild/linux-mips64el": "0.16.4", + "@esbuild/linux-ppc64": "0.16.4", + "@esbuild/linux-riscv64": "0.16.4", + "@esbuild/linux-s390x": "0.16.4", + "@esbuild/linux-x64": "0.16.4", + "@esbuild/netbsd-x64": "0.16.4", + "@esbuild/openbsd-x64": "0.16.4", + "@esbuild/sunos-x64": "0.16.4", + "@esbuild/win32-arm64": "0.16.4", + "@esbuild/win32-ia32": "0.16.4", + "@esbuild/win32-x64": "0.16.4" + } + }, + "esbuild-wasm": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.16.4.tgz", + "integrity": "sha512-Nh7aa9uazooaEIGubc8s0nQZFhnf035pJMTpMPBonzDchN6RPsQES5bojQo3zT2xSAuC9nEMg8Nxzc1iwigETw==", + "dev": true + }, + "esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true + }, + "magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true + }, + "mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "postcss": { + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "rollup": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.3.tgz", + "integrity": "sha512-7e68MQbAWCX6mI4/0lG1WHd+NdNAlVamg0Zkd+8LZ/oXojligdGnCNyHlzXqXCZObyjs5FRc3AH0b17iJESGIQ==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "requires": { + "mri": "^1.1.0" + } + }, + "set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==", + "dev": true + }, + "sirv": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz", + "integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + } + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "svelte": { + "version": "3.54.0", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.54.0.tgz", + "integrity": "sha512-tdrgeJU0hob0ZWAMoKXkhcxXA7dpTg6lZGxUeko5YqvPdJBiyRspGsCwV27kIrbrqPP2WUoSV9ca0gnLlw8YzQ==", + "dev": true + }, + "svelte-hmr": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.1.tgz", + "integrity": "sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==", + "dev": true, + "requires": {} + }, + "tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "requires": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "totalist": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz", + "integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==", + "dev": true + }, + "undici": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "dev": true, + "requires": { + "busboy": "^1.6.0" + } + }, + "vite": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.0.tgz", + "integrity": "sha512-ynad+4kYs8Jcnn8J7SacS9vAbk7eMy0xWg6E7bAhS1s79TK+D7tVFGXVZ55S7RNLRROU1rxoKlvZ/qjaB41DGA==", + "dev": true, + "requires": { + "esbuild": "^0.16.3", + "fsevents": "~2.3.2", + "postcss": "^8.4.19", + "resolve": "^1.22.1", + "rollup": "^3.7.0" + } + }, + "vitefu": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.3.tgz", + "integrity": "sha512-75l7TTuU8isAhz1QFtNKjDkqjxvndfMC1AfIMjJ0ZQ59ZD0Ow9QOIsJJX16Wv9PS8f+zMzp6fHy5cCbKG/yVUQ==", + "dev": true, + "requires": {} + } + } +} diff --git a/content/tutorial/common/package.json b/content/tutorial/common/package.json index 01bd06954..7243df8c4 100644 --- a/content/tutorial/common/package.json +++ b/content/tutorial/common/package.json @@ -8,9 +8,9 @@ }, "devDependencies": { "@sveltejs/kit": "next", - "esbuild-wasm": "^0.14.43", - "svelte": "^3.53.1", - "vite": "^3.2.5" + "esbuild-wasm": "^0.16.4", + "svelte": "^3.54.0", + "vite": "^4.0.0" }, "type": "module" } diff --git a/content/tutorial/common/src/__client.js b/content/tutorial/common/src/__client.js index 1dc7420e9..7bb766697 100644 --- a/content/tutorial/common/src/__client.js +++ b/content/tutorial/common/src/__client.js @@ -15,7 +15,10 @@ window.addEventListener('message', async (e) => { const css_files = []; for (const { name, code } of transformed) { - if (name.endsWith('.svelte') && code.includes('svelte&type=style&lang.css')) { + if ( + name.endsWith('.svelte') && + code.includes('svelte&type=style&lang.css') + ) { css_files.push(name + '?svelte&type=style&lang.css'); } } @@ -56,7 +59,7 @@ function ping() { ); } -setInterval(ping, 200); +setInterval(ping, 50); ping(); if (import.meta.hot) { diff --git a/content/tutorial/common/src/app.html b/content/tutorial/common/src/app.html index 2f8367462..a81dfbad1 100644 --- a/content/tutorial/common/src/app.html +++ b/content/tutorial/common/src/app.html @@ -5,8 +5,56 @@ %sveltekit.head% + + -
    %sveltekit.body%
    +
    %sveltekit.body%
    diff --git a/content/tutorial/common/svelte.config.js b/content/tutorial/common/svelte.config.js index 821c14379..29ce35b4b 100644 --- a/content/tutorial/common/svelte.config.js +++ b/content/tutorial/common/svelte.config.js @@ -1,6 +1,11 @@ /** @type {import('@sveltejs/kit').Config} */ const config = { - kit: {} + kit: { + // For the tutorial, we need to disable CSRF protection. + // Don't do this in your own apps unless you know what you're doing! + // See https://kit.svelte.dev/docs/configuration#csrf for more info. + csrf: false + } }; export default config; diff --git a/package.json b/package.json index a62154932..7f1af822f 100644 --- a/package.json +++ b/package.json @@ -11,18 +11,23 @@ "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ." }, "devDependencies": { - "@sveltejs/adapter-auto": "next", + "@sveltejs/adapter-auto": "1.0.0-next.90", + "@sveltejs/adapter-vercel": "1.0.0-next.85", "@sveltejs/kit": "next", "@sveltejs/site-kit": "^2.1.2", + "@types/diff": "^5.0.2", + "@types/marked": "^4.0.8", + "@types/prismjs": "^1.26.0", + "@types/ws": "^8.5.3", "diff": "^5.1.0", "esbuild": "^0.14.43", "prettier": "^2.6.2", "prettier-plugin-svelte": "^2.7.0", - "svelte": "^3.48.0", + "svelte": "^3.54.0", "svelte-check": "^2.7.2", "tiny-glob": "^0.2.9", "typescript": "~4.6.4", - "vite": "^3.2.4" + "vite": "^4.0.0" }, "type": "module", "dependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5af8c41f..f6f13197d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,9 +2,14 @@ lockfileVersion: 5.4 specifiers: '@fontsource/roboto-mono': ^4.5.7 - '@sveltejs/adapter-auto': next + '@sveltejs/adapter-auto': 1.0.0-next.90 + '@sveltejs/adapter-vercel': 1.0.0-next.85 '@sveltejs/kit': next '@sveltejs/site-kit': ^2.1.2 + '@types/diff': ^5.0.2 + '@types/marked': ^4.0.8 + '@types/prismjs': ^1.26.0 + '@types/ws': ^8.5.3 '@webcontainer/api': ^0.0.8 adm-zip: ^0.5.9 base64-js: ^1.5.1 @@ -17,334 +22,561 @@ specifiers: prettier-plugin-svelte: ^2.7.0 prism-svelte: ^0.5.0 prismjs: ^1.28.0 - svelte: ^3.48.0 + svelte: ^3.54.0 svelte-check: ^2.7.2 tiny-glob: ^0.2.9 typescript: ~4.6.4 - vite: ^3.2.4 + vite: ^4.0.0 ws: ^8.8.0 dependencies: - '@fontsource/roboto-mono': 4.5.7 + '@fontsource/roboto-mono': 4.5.8 '@webcontainer/api': 0.0.8 adm-zip: 0.5.9 base64-js: 1.5.1 - marked: 4.0.16 + marked: 4.2.4 monaco-editor: 0.33.0 port-authority: 2.0.1 prism-svelte: 0.5.0 - prismjs: 1.28.0 - ws: 8.8.0 + prismjs: 1.29.0 + ws: 8.11.0 devDependencies: '@sveltejs/adapter-auto': 1.0.0-next.90 - '@sveltejs/kit': 1.0.0-next.572_svelte@3.48.0+vite@3.2.4 - '@sveltejs/site-kit': 2.1.2 + '@sveltejs/adapter-vercel': 1.0.0-next.85 + '@sveltejs/kit': 1.0.0-next.583_svelte@3.54.0+vite@4.0.0 + '@sveltejs/site-kit': 2.1.4 + '@types/diff': 5.0.2 + '@types/marked': 4.0.8 + '@types/prismjs': 1.26.0 + '@types/ws': 8.5.3 diff: 5.1.0 - esbuild: 0.14.43 - prettier: 2.6.2 - prettier-plugin-svelte: 2.7.0_kkjbqzpydplecjtkxrgomroeru - svelte: 3.48.0 - svelte-check: 2.7.2_svelte@3.48.0 + esbuild: 0.14.54 + prettier: 2.8.1 + prettier-plugin-svelte: 2.9.0_sro2v6ld777payjtkjtiuogcxi + svelte: 3.54.0 + svelte-check: 2.10.2_svelte@3.54.0 tiny-glob: 0.2.9 typescript: 4.6.4 - vite: 3.2.4 + vite: 4.0.0 packages: - /@esbuild/android-arm/0.15.14: - resolution: - { - integrity: sha512-+Rb20XXxRGisNu2WmNKk+scpanb7nL5yhuI1KR9wQFiC43ddPj/V1fmNyzlFC9bKiG4mYzxW7egtoHVcynr+OA== - } - engines: { node: '>=12' } + + /@esbuild/android-arm/0.16.4: + resolution: {integrity: sha512-rZzb7r22m20S1S7ufIc6DC6W659yxoOrl7sKP1nCYhuvUlnCFHVSbATG4keGUtV8rDz11sRRDbWkvQZpzPaHiw==} + engines: {node: '>=12'} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@esbuild/linux-loong64/0.15.14: - resolution: - { - integrity: sha512-eQi9rosGNVQFJyJWV0HCA5WZae/qWIQME7s8/j8DMvnylfBv62Pbu+zJ2eUDqNf2O4u3WB+OEXyfkpBoe194sg== - } - engines: { node: '>=12' } + /@esbuild/android-arm64/0.16.4: + resolution: {integrity: sha512-VPuTzXFm/m2fcGfN6CiwZTlLzxrKsWbPkG7ArRFpuxyaHUm/XFHQPD4xNwZT6uUmpIHhnSjcaCmcla8COzmZ5Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.16.4: + resolution: {integrity: sha512-MW+B2O++BkcOfMWmuHXB15/l1i7wXhJFqbJhp82IBOais8RBEQv2vQz/jHrDEHaY2X0QY7Wfw86SBL2PbVOr0g==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.16.4: + resolution: {integrity: sha512-a28X1O//aOfxwJVZVs7ZfM8Tyih2Za4nKJrBwW5Wm4yKsnwBy9aiS/xwpxiiTRttw3EaTg4Srerhcm6z0bu9Wg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.16.4: + resolution: {integrity: sha512-e3doCr6Ecfwd7VzlaQqEPrnbvvPjE9uoTpxG5pyLzr2rI2NMjDHmvY1E5EO81O/e9TUOLLkXA5m6T8lfjK9yAA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.16.4: + resolution: {integrity: sha512-Oup3G/QxBgvvqnXWrBed7xxkFNwAwJVHZcklWyQt7YCAL5bfUkaa6FVWnR78rNQiM8MqqLiT6ZTZSdUFuVIg1w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.16.4: + resolution: {integrity: sha512-vAP+eYOxlN/Bpo/TZmzEQapNS8W1njECrqkTpNgvXskkkJC2AwOXwZWai/Kc2vEFZUXQttx6UJbj9grqjD/+9Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.16.4: + resolution: {integrity: sha512-A47ZmtpIPyERxkSvIv+zLd6kNIOtJH03XA0Hy7jaceRDdQaQVGSDt4mZqpWqJYgDk9rg96aglbF6kCRvPGDSUA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.16.4: + resolution: {integrity: sha512-2zXoBhv4r5pZiyjBKrOdFP4CXOChxXiYD50LRUU+65DkdS5niPFHbboKZd/c81l0ezpw7AQnHeoCy5hFrzzs4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.16.4: + resolution: {integrity: sha512-uxdSrpe9wFhz4yBwt2kl2TxS/NWEINYBUFIxQtaEVtglm1eECvsj1vEKI0KX2k2wCe17zDdQ3v+jVxfwVfvvjw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.14.54: + resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.16.4: + resolution: {integrity: sha512-peDrrUuxbZ9Jw+DwLCh/9xmZAk0p0K1iY5d2IcwmnN+B87xw7kujOkig6ZRcZqgrXgeRGurRHn0ENMAjjD5DEg==} + engines: {node: '>=12'} cpu: [loong64] os: [linux] requiresBuild: true dev: true optional: true - /@fontsource/roboto-mono/4.5.7: - resolution: - { - integrity: sha512-1uBjM95BEz7zJlmmnpNAM5afMvIxx0wqr86eA76vRqZw8OF5wmsRqYfF3caHuVarBH9/AGN7t9h+3UXK8fjq/Q== - } + /@esbuild/linux-mips64el/0.16.4: + resolution: {integrity: sha512-sD9EEUoGtVhFjjsauWjflZklTNr57KdQ6xfloO4yH1u7vNQlOfAlhEzbyBKfgbJlW7rwXYBdl5/NcZ+Mg2XhQA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.16.4: + resolution: {integrity: sha512-X1HSqHUX9D+d0l6/nIh4ZZJ94eQky8d8z6yxAptpZE3FxCWYWvTDd9X9ST84MGZEJx04VYUD/AGgciddwO0b8g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.16.4: + resolution: {integrity: sha512-97ANpzyNp0GTXCt6SRdIx1ngwncpkV/z453ZuxbnBROCJ5p/55UjhbaG23UdHj88fGWLKPFtMoU4CBacz4j9FA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.16.4: + resolution: {integrity: sha512-pUvPQLPmbEeJRPjP0DYTC1vjHyhrnCklQmCGYbipkep+oyfTn7GTBJXoPodR7ZS5upmEyc8lzAkn2o29wD786A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.16.4: + resolution: {integrity: sha512-N55Q0mJs3Sl8+utPRPBrL6NLYZKBCLLx0bme/+RbjvMforTGGzFvsRl4xLTZMUBFC1poDzBEPTEu5nxizQ9Nlw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.16.4: + resolution: {integrity: sha512-LHSJLit8jCObEQNYkgsDYBh2JrJT53oJO2HVdkSYLa6+zuLJh0lAr06brXIkljrlI+N7NNW1IAXGn/6IZPi3YQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.16.4: + resolution: {integrity: sha512-nLgdc6tWEhcCFg/WVFaUxHcPK3AP/bh+KEwKtl69Ay5IBqUwKDaq/6Xk0E+fh/FGjnLwqFSsarsbPHeKM8t8Sw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.16.4: + resolution: {integrity: sha512-08SluG24GjPO3tXKk95/85n9kpyZtXCVwURR2i4myhrOfi3jspClV0xQQ0W0PYWHioJj+LejFMt41q+PG3mlAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64/0.16.4: + resolution: {integrity: sha512-yYiRDQcqLYQSvNQcBKN7XogbrSvBE45FEQdH8fuXPl7cngzkCvpsG2H9Uey39IjQ6gqqc+Q4VXYHsQcKW0OMjQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32/0.16.4: + resolution: {integrity: sha512-5rabnGIqexekYkh9zXG5waotq8mrdlRoBqAktjx2W3kb0zsI83mdCwrcAeKYirnUaTGztR5TxXcXmQrEzny83w==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64/0.16.4: + resolution: {integrity: sha512-sN/I8FMPtmtT2Yw+Dly8Ur5vQ5a/RmC8hW7jO9PtPSQUPkowxWpcUZnqOggU7VwyT3Xkj6vcXWd3V/qTXwultQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@fontsource/roboto-mono/4.5.8: + resolution: {integrity: sha512-AW44UkbQD0w1CT5mzDbsvhGZ6/bb0YmZzoELj6Sx8vcVEzcbYGUdt2Dtl5zqlOuYMWQFY1mniwWyVv+Bm/lVxw==} dev: false - /@jridgewell/resolve-uri/3.0.7: - resolution: - { - integrity: sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== - } - engines: { node: '>=6.0.0' } + /@jridgewell/resolve-uri/3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} dev: true - /@jridgewell/sourcemap-codec/1.4.13: - resolution: - { - integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== - } + /@jridgewell/sourcemap-codec/1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} dev: true - /@jridgewell/trace-mapping/0.3.13: - resolution: - { - integrity: sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== - } + /@jridgewell/trace-mapping/0.3.17: + resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} dependencies: - '@jridgewell/resolve-uri': 3.0.7 - '@jridgewell/sourcemap-codec': 1.4.13 + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + + /@mapbox/node-pre-gyp/1.0.10: + resolution: {integrity: sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==} + hasBin: true + dependencies: + detect-libc: 2.0.1 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.6.7 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.3.8 + tar: 6.1.13 + transitivePeerDependencies: + - encoding + - supports-color dev: true /@nodelib/fs.scandir/2.1.5: - resolution: - { - integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 dev: true /@nodelib/fs.stat/2.0.5: - resolution: - { - integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} dev: true /@nodelib/fs.walk/1.2.8: - resolution: - { - integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.13.0 + fastq: 1.14.0 dev: true /@polka/url/1.0.0-next.21: - resolution: - { - integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== - } + resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} + dev: true + + /@rollup/pluginutils/4.2.1: + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 dev: true /@sveltejs/adapter-auto/1.0.0-next.90: - resolution: - { - integrity: sha512-qxH46Oqqn40998wTmnbffONI0HcW/kiZ3OIjZoysjONne+LU4uEsG425MZ2RHDxmR04zxhsdjCAsn6B4du8D7w== - } + resolution: {integrity: sha512-qxH46Oqqn40998wTmnbffONI0HcW/kiZ3OIjZoysjONne+LU4uEsG425MZ2RHDxmR04zxhsdjCAsn6B4du8D7w==} dependencies: import-meta-resolve: 2.2.0 dev: true - /@sveltejs/kit/1.0.0-next.572_svelte@3.48.0+vite@3.2.4: - resolution: - { - integrity: sha512-PiKEr55L/uJyMKvDPdyoa5MlAYQwdgs8HLMbr28YcCBmhw/v6V7gutKOKdqeXc3YwKEFVS3z7TvW6c7eDokJdQ== - } - engines: { node: '>=16.14' } + /@sveltejs/adapter-vercel/1.0.0-next.85: + resolution: {integrity: sha512-vTR/PcJaYI3DQmYtrY49VfBmLC1kqXn7tKXj9tzUaiuKZ/r625P7cvm4pBoEbyTYmNwlW71hObqtkESUIMIZOg==} + dependencies: + '@vercel/nft': 0.22.5 + esbuild: 0.16.4 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + + /@sveltejs/kit/1.0.0-next.583_svelte@3.54.0+vite@4.0.0: + resolution: {integrity: sha512-LrVhaJ161VVa4YANvTBlS8NICvIipp5w/PtS5f+XuGv4y1nltY5FnN+PUCG3qlySNC8BQDTqR0xDp7gDVFL7qw==} + engines: {node: '>=16.14'} hasBin: true requiresBuild: true peerDependencies: - svelte: ^3.44.0 - vite: ^3.2.0 + svelte: ^3.54.0 + vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 1.4.0_svelte@3.48.0+vite@3.2.4 + '@sveltejs/vite-plugin-svelte': 2.0.2_svelte@3.54.0+vite@4.0.0 '@types/cookie': 0.5.1 cookie: 0.5.0 devalue: 4.2.0 + esm-env: 1.0.0 kleur: 4.1.5 magic-string: 0.27.0 mime: 3.0.0 sade: 1.8.1 set-cookie-parser: 2.5.1 sirv: 2.0.2 - svelte: 3.48.0 + svelte: 3.54.0 tiny-glob: 0.2.9 - undici: 5.13.0 - vite: 3.2.4 + undici: 5.14.0 + vite: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /@sveltejs/site-kit/2.1.2: - resolution: - { - integrity: sha512-VB5JhdvO1299lgR0ZU1MUdKNPb0TZMq4ck8cxg7p/o3TXFTLwbgwF/aV4ei9I/p11bpWFh9FKGzGUUGxWgJxSg== - } + /@sveltejs/site-kit/2.1.4: + resolution: {integrity: sha512-PxpbiCWYXJ320abc6ucp3AXhh6YCggf6ea+EVA6W+wCBe45UFoChfoeQYeD6sQxPZN25XntoS4clZeYnt9H93Q==} dependencies: golden-fleece: 1.0.9 dev: true - /@sveltejs/vite-plugin-svelte/1.4.0_svelte@3.48.0+vite@3.2.4: - resolution: - { - integrity: sha512-6QupI/jemMfK+yI2pMtJcu5iO2gtgTfcBdGwMZZt+lgbFELhszbDl6Qjh000HgAV8+XUA+8EY8DusOFk8WhOIg== - } - engines: { node: ^14.18.0 || >= 16 } + /@sveltejs/vite-plugin-svelte/2.0.2_svelte@3.54.0+vite@4.0.0: + resolution: {integrity: sha512-xCEan0/NNpQuL0l5aS42FjwQ6wwskdxC3pW1OeFtEKNZwRg7Evro9lac9HesGP6TdFsTv2xMes5ASQVKbCacxg==} + engines: {node: ^14.18.0 || >= 16} peerDependencies: - svelte: ^3.44.0 - vite: ^3.0.0 + svelte: ^3.54.0 + vite: ^4.0.0 dependencies: debug: 4.3.4 deepmerge: 4.2.2 kleur: 4.1.5 - magic-string: 0.26.7 - svelte: 3.48.0 - svelte-hmr: 0.15.1_svelte@3.48.0 - vite: 3.2.4 - vitefu: 0.2.2_vite@3.2.4 + magic-string: 0.27.0 + svelte: 3.54.0 + svelte-hmr: 0.15.1_svelte@3.54.0 + vite: 4.0.0 + vitefu: 0.2.3_vite@4.0.0 transitivePeerDependencies: - supports-color dev: true /@types/cookie/0.5.1: - resolution: - { - integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g== - } + resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==} + dev: true + + /@types/diff/5.0.2: + resolution: {integrity: sha512-uw8eYMIReOwstQ0QKF0sICefSy8cNO/v7gOTiIy9SbwuHyEecJUm7qlgueOO5S1udZ5I/irVydHVwMchgzbKTg==} dev: true - /@types/node/17.0.41: - resolution: - { - integrity: sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw== - } + /@types/marked/4.0.8: + resolution: {integrity: sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==} + dev: true + + /@types/node/18.11.13: + resolution: {integrity: sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w==} + dev: true + + /@types/prismjs/1.26.0: + resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==} dev: true /@types/pug/2.0.6: - resolution: - { - integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg== - } + resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==} dev: true /@types/sass/1.43.1: - resolution: - { - integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g== - } + resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==} + dependencies: + '@types/node': 18.11.13 + dev: true + + /@types/ws/8.5.3: + resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==} dependencies: - '@types/node': 17.0.41 + '@types/node': 18.11.13 + dev: true + + /@vercel/nft/0.22.5: + resolution: {integrity: sha512-mug57Wd1BL7GMj9gXMgMeKUjdqO0e4u+0QLPYMFE1rwdJ+55oPy6lp3nIBCS8gOvigT62UI4QKUL2sGqcoW4Hw==} + engines: {node: '>=14'} + hasBin: true + dependencies: + '@mapbox/node-pre-gyp': 1.0.10 + '@rollup/pluginutils': 4.2.1 + acorn: 8.8.1 + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 7.2.3 + graceful-fs: 4.2.10 + micromatch: 4.0.5 + node-gyp-build: 4.5.0 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - supports-color dev: true /@webcontainer/api/0.0.8: - resolution: - { - integrity: sha512-t285UFNMzz8mmJlfAP/mloJlN+rHuu5jmFCNW05WGT3FzJ0sNseU6WN5+TiTtWIfjiUfLPtJI6ndsgiTujkXAw== - } + resolution: {integrity: sha512-t285UFNMzz8mmJlfAP/mloJlN+rHuu5jmFCNW05WGT3FzJ0sNseU6WN5+TiTtWIfjiUfLPtJI6ndsgiTujkXAw==} dev: false + /abbrev/1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true + + /acorn/8.8.1: + resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /adm-zip/0.5.9: - resolution: - { - integrity: sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg== - } - engines: { node: '>=6.0' } + resolution: {integrity: sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==} + engines: {node: '>=6.0'} dev: false - /anymatch/3.1.2: - resolution: - { - integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - } - engines: { node: '>= 8' } + /agent-base/6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /anymatch/3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 dev: true + /aproba/2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: true + + /are-we-there-yet/2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.0 + dev: true + + /async-sema/3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + dev: true + /balanced-match/1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - } + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true /base64-js/1.5.1: - resolution: - { - integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - } + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: false /binary-extensions/2.2.0: - resolution: - { - integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bindings/1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + dependencies: + file-uri-to-path: 1.0.0 dev: true /brace-expansion/1.1.11: - resolution: - { - integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - } + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 dev: true /braces/3.0.2: - resolution: - { - integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} dependencies: fill-range: 7.0.1 dev: true /buffer-crc32/0.2.13: - resolution: - { - integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== - } + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} dev: true /busboy/1.6.0: - resolution: - { - integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - } - engines: { node: '>=10.16.0' } + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} dependencies: streamsearch: 1.1.0 dev: true /callsites/3.1.0: - resolution: - { - integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} dev: true /chokidar/3.5.3: - resolution: - { - integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - } - engines: { node: '>= 8.10.0' } + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} dependencies: - anymatch: 3.1.2 + anymatch: 3.1.3 braces: 3.0.2 glob-parent: 5.1.2 is-binary-path: 2.1.0 @@ -355,24 +587,32 @@ packages: fsevents: 2.3.2 dev: true + /chownr/2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + dev: true + + /color-support/1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: true + /concat-map/0.0.1: - resolution: { integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= } + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + dev: true + + /console-control-strings/1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} dev: true /cookie/0.5.0: - resolution: - { - integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - } - engines: { node: '>= 0.6' } + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} dev: true /debug/4.3.4: - resolution: - { - integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - } - engines: { node: '>=6.0' } + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: @@ -383,593 +623,291 @@ packages: dev: true /deepmerge/4.2.2: - resolution: - { - integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} + engines: {node: '>=0.10.0'} + dev: true + + /delegates/1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} dev: true /detect-indent/6.1.0: - resolution: - { - integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + dev: true + + /detect-libc/2.0.1: + resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} + engines: {node: '>=8'} dev: true /devalue/4.2.0: - resolution: - { - integrity: sha512-mbjoAaCL2qogBKgeFxFPOXAUsZchircF+B/79LD4sHH0+NHfYm8gZpQrskKDn5gENGt35+5OI1GUF7hLVnkPDw== - } + resolution: {integrity: sha512-mbjoAaCL2qogBKgeFxFPOXAUsZchircF+B/79LD4sHH0+NHfYm8gZpQrskKDn5gENGt35+5OI1GUF7hLVnkPDw==} dev: true /diff/5.1.0: - resolution: - { - integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== - } - engines: { node: '>=0.3.1' } + resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} + engines: {node: '>=0.3.1'} dev: true - /es6-promise/3.3.1: - resolution: - { - integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg== - } - dev: true - - /esbuild-android-64/0.14.43: - resolution: - { - integrity: sha512-kqFXAS72K6cNrB6RiM7YJ5lNvmWRDSlpi7ZuRZ1hu1S3w0zlwcoCxWAyM23LQUyZSs1PbjHgdbbfYAN8IGh6xg== - } - engines: { node: '>=12' } - cpu: [x64] - os: [android] - requiresBuild: true + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true - optional: true - /esbuild-android-64/0.15.14: - resolution: - { - integrity: sha512-HuilVIb4rk9abT4U6bcFdU35UHOzcWVGLSjEmC58OVr96q5UiRqzDtWjPlCMugjhgUGKEs8Zf4ueIvYbOStbIg== - } - engines: { node: '>=12' } - cpu: [x64] - os: [android] - requiresBuild: true + /es6-promise/3.3.1: + resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} dev: true - optional: true - /esbuild-android-arm64/0.14.43: - resolution: - { - integrity: sha512-bKS2BBFh+7XZY9rpjiHGRNA7LvWYbZWP87pLehggTG7tTaCDvj8qQGOU/OZSjCSKDYbgY7Q+oDw8RlYQ2Jt2BA== - } - engines: { node: '>=12' } - cpu: [arm64] + /esbuild-android-64/0.14.54: + resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} + engines: {node: '>=12'} + cpu: [x64] os: [android] requiresBuild: true dev: true optional: true - /esbuild-android-arm64/0.15.14: - resolution: - { - integrity: sha512-/QnxRVxsR2Vtf3XottAHj7hENAMW2wCs6S+OZcAbc/8nlhbAL/bCQRCVD78VtI5mdwqWkVi3wMqM94kScQCgqg== - } - engines: { node: '>=12' } + /esbuild-android-arm64/0.14.54: + resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} + engines: {node: '>=12'} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /esbuild-darwin-64/0.14.43: - resolution: - { - integrity: sha512-/3PSilx011ttoieRGkSZ0XV8zjBf2C9enV4ScMMbCT4dpx0mFhMOpFnCHkOK0pWGB8LklykFyHrWk2z6DENVUg== - } - engines: { node: '>=12' } - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-64/0.15.14: - resolution: - { - integrity: sha512-ToNuf1uifu8hhwWvoZJGCdLIX/1zpo8cOGnT0XAhDQXiKOKYaotVNx7pOVB1f+wHoWwTLInrOmh3EmA7Fd+8Vg== - } - engines: { node: '>=12' } + /esbuild-darwin-64/0.14.54: + resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} + engines: {node: '>=12'} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /esbuild-darwin-arm64/0.14.43: - resolution: - { - integrity: sha512-1HyFUKs8DMCBOvw1Qxpr5Vv/ThNcVIFb5xgXWK3pyT40WPvgYIiRTwJCvNs4l8i5qWF8/CK5bQxJVDjQvtv0Yw== - } - engines: { node: '>=12' } - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-arm64/0.15.14: - resolution: - { - integrity: sha512-KgGP+y77GszfYJgceO0Wi/PiRtYo5y2Xo9rhBUpxTPaBgWDJ14gqYN0+NMbu+qC2fykxXaipHxN4Scaj9tUS1A== - } - engines: { node: '>=12' } + /esbuild-darwin-arm64/0.14.54: + resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} + engines: {node: '>=12'} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /esbuild-freebsd-64/0.14.43: - resolution: - { - integrity: sha512-FNWc05TPHYgaXjbPZO5/rJKSBslfG6BeMSs8GhwnqAKP56eEhvmzwnIz1QcC9cRVyO+IKqWNfmHFkCa1WJTULA== - } - engines: { node: '>=12' } + /esbuild-freebsd-64/0.14.54: + resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} + engines: {node: '>=12'} cpu: [x64] os: [freebsd] requiresBuild: true dev: true optional: true - /esbuild-freebsd-64/0.15.14: - resolution: - { - integrity: sha512-xr0E2n5lyWw3uFSwwUXHc0EcaBDtsal/iIfLioflHdhAe10KSctV978Te7YsfnsMKzcoGeS366+tqbCXdqDHQA== - } - engines: { node: '>=12' } - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-arm64/0.14.43: - resolution: - { - integrity: sha512-amrYopclz3VohqisOPR6hA3GOWA3LZC1WDLnp21RhNmoERmJ/vLnOpnrG2P/Zao+/erKTCUqmrCIPVtj58DRoA== - } - engines: { node: '>=12' } - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-arm64/0.15.14: - resolution: - { - integrity: sha512-8XH96sOQ4b1LhMlO10eEWOjEngmZ2oyw3pW4o8kvBcpF6pULr56eeYVP5radtgw54g3T8nKHDHYEI5AItvskZg== - } - engines: { node: '>=12' } + /esbuild-freebsd-arm64/0.14.54: + resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} + engines: {node: '>=12'} cpu: [arm64] os: [freebsd] requiresBuild: true dev: true optional: true - /esbuild-linux-32/0.14.43: - resolution: - { - integrity: sha512-KoxoEra+9O3AKVvgDFvDkiuddCds6q71owSQEYwjtqRV7RwbPzKxJa6+uyzUulHcyGVq0g15K0oKG5CFBcvYDw== - } - engines: { node: '>=12' } - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-32/0.15.14: - resolution: - { - integrity: sha512-6ssnvwaTAi8AzKN8By2V0nS+WF5jTP7SfuK6sStGnDP7MCJo/4zHgM9oE1eQTS2jPmo3D673rckuCzRlig+HMA== - } - engines: { node: '>=12' } + /esbuild-linux-32/0.14.54: + resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} + engines: {node: '>=12'} cpu: [ia32] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-64/0.14.43: - resolution: - { - integrity: sha512-EwINwGMyiJMgBby5/SbMqKcUhS5AYAZ2CpEBzSowsJPNBJEdhkCTtEjk757TN/wxgbu3QklqDM6KghY660QCUw== - } - engines: { node: '>=12' } + /esbuild-linux-64/0.14.54: + resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} + engines: {node: '>=12'} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-64/0.15.14: - resolution: - { - integrity: sha512-ONySx3U0wAJOJuxGUlXBWxVKFVpWv88JEv0NZ6NlHknmDd1yCbf4AEdClSgLrqKQDXYywmw4gYDvdLsS6z0hcw== - } - engines: { node: '>=12' } - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm/0.14.43: - resolution: - { - integrity: sha512-e6YzQUoDxxtyamuF12eVzzRC7bbEFSZohJ6igQB9tBqnNmIQY3fI6Cns3z2wxtbZ3f2o6idkD2fQnlvs2902Dg== - } - engines: { node: '>=12' } + /esbuild-linux-arm/0.14.54: + resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} + engines: {node: '>=12'} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-arm/0.15.14: - resolution: - { - integrity: sha512-D2LImAIV3QzL7lHURyCHBkycVFbKwkDb1XEUWan+2fb4qfW7qAeUtul7ZIcIwFKZgPcl+6gKZmvLgPSj26RQ2Q== - } - engines: { node: '>=12' } - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm64/0.14.43: - resolution: - { - integrity: sha512-UlSpjMWllAc70zYbHxWuDS3FJytyuR/gHJYBr8BICcTNb/TSOYVBg6U7b3jZ3mILTrgzwJUHwhEwK18FZDouUQ== - } - engines: { node: '>=12' } - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm64/0.15.14: - resolution: - { - integrity: sha512-kle2Ov6a1e5AjlHlMQl1e+c4myGTeggrRzArQFmWp6O6JoqqB9hT+B28EW4tjFWgV/NxUq46pWYpgaWXsXRPAg== - } - engines: { node: '>=12' } + /esbuild-linux-arm64/0.14.54: + resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} + engines: {node: '>=12'} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-mips64le/0.14.43: - resolution: - { - integrity: sha512-f+v8cInPEL1/SDP//CfSYzcDNgE4CY3xgDV81DWm3KAPWzhvxARrKxB1Pstf5mB56yAslJDxu7ryBUPX207EZA== - } - engines: { node: '>=12' } + /esbuild-linux-mips64le/0.14.54: + resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} + engines: {node: '>=12'} cpu: [mips64el] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-mips64le/0.15.14: - resolution: - { - integrity: sha512-FVdMYIzOLXUq+OE7XYKesuEAqZhmAIV6qOoYahvUp93oXy0MOVTP370ECbPfGXXUdlvc0TNgkJa3YhEwyZ6MRA== - } - engines: { node: '>=12' } - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-ppc64le/0.14.43: - resolution: - { - integrity: sha512-5wZYMDGAL/K2pqkdIsW+I4IR41kyfHr/QshJcNpUfK3RjB3VQcPWOaZmc+74rm4ZjVirYrtz+jWw0SgxtxRanA== - } - engines: { node: '>=12' } - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-ppc64le/0.15.14: - resolution: - { - integrity: sha512-2NzH+iuzMDA+jjtPjuIz/OhRDf8tzbQ1tRZJI//aT25o1HKc0reMMXxKIYq/8nSHXiJSnYV4ODzTiv45s+h73w== - } - engines: { node: '>=12' } + /esbuild-linux-ppc64le/0.14.54: + resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} + engines: {node: '>=12'} cpu: [ppc64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-riscv64/0.14.43: - resolution: - { - integrity: sha512-lYcAOUxp85hC7lSjycJUVSmj4/9oEfSyXjb/ua9bNl8afonaduuqtw7hvKMoKuYnVwOCDw4RSfKpcnIRDWq+Bw== - } - engines: { node: '>=12' } - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-riscv64/0.15.14: - resolution: - { - integrity: sha512-VqxvutZNlQxmUNS7Ac+aczttLEoHBJ9e3OYGqnULrfipRvG97qLrAv9EUY9iSrRKBqeEbSvS9bSfstZqwz0T4Q== - } - engines: { node: '>=12' } + /esbuild-linux-riscv64/0.14.54: + resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} + engines: {node: '>=12'} cpu: [riscv64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-s390x/0.14.43: - resolution: - { - integrity: sha512-27e43ZhHvhFE4nM7HqtUbMRu37I/4eNSUbb8FGZWszV+uLzMIsHDwLoBiJmw7G9N+hrehNPeQ4F5Ujad0DrUKQ== - } - engines: { node: '>=12' } + /esbuild-linux-s390x/0.14.54: + resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} + engines: {node: '>=12'} cpu: [s390x] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-s390x/0.15.14: - resolution: - { - integrity: sha512-+KVHEUshX5n6VP6Vp/AKv9fZIl5kr2ph8EUFmQUJnDpHwcfTSn2AQgYYm0HTBR2Mr4d0Wlr0FxF/Cs5pbFgiOw== - } - engines: { node: '>=12' } - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-netbsd-64/0.14.43: - resolution: - { - integrity: sha512-2mH4QF6hHBn5zzAfxEI/2eBC0mspVsZ6UVo821LpAJKMvLJPBk3XJO5xwg7paDqSqpl7p6IRrAenW999AEfJhQ== - } - engines: { node: '>=12' } + /esbuild-netbsd-64/0.14.54: + resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} + engines: {node: '>=12'} cpu: [x64] os: [netbsd] requiresBuild: true dev: true optional: true - /esbuild-netbsd-64/0.15.14: - resolution: - { - integrity: sha512-6D/dr17piEgevIm1xJfZP2SjB9Z+g8ERhNnBdlZPBWZl+KSPUKLGF13AbvC+nzGh8IxOH2TyTIdRMvKMP0nEzQ== - } - engines: { node: '>=12' } - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-openbsd-64/0.14.43: - resolution: - { - integrity: sha512-ZhQpiZjvqCqO8jKdGp9+8k9E/EHSA+zIWOg+grwZasI9RoblqJ1QiZqqi7jfd6ZrrG1UFBNGe4m0NFxCFbMVbg== - } - engines: { node: '>=12' } + /esbuild-openbsd-64/0.14.54: + resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} + engines: {node: '>=12'} cpu: [x64] os: [openbsd] requiresBuild: true dev: true optional: true - /esbuild-openbsd-64/0.15.14: - resolution: - { - integrity: sha512-rREQBIlMibBetgr2E9Lywt2Qxv2ZdpmYahR4IUlAQ1Efv/A5gYdO0/VIN3iowDbCNTLxp0bb57Vf0LFcffD6kA== - } - engines: { node: '>=12' } - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-sunos-64/0.14.43: - resolution: - { - integrity: sha512-DgxSi9DaHReL9gYuul2rrQCAapgnCJkh3LSHPKsY26zytYppG0HgkgVF80zjIlvEsUbGBP/GHQzBtrezj/Zq1Q== - } - engines: { node: '>=12' } - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /esbuild-sunos-64/0.15.14: - resolution: - { - integrity: sha512-DNVjSp/BY4IfwtdUAvWGIDaIjJXY5KI4uD82+15v6k/w7px9dnaDaJJ2R6Mu+KCgr5oklmFc0KjBjh311Gxl9Q== - } - engines: { node: '>=12' } + /esbuild-sunos-64/0.14.54: + resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} + engines: {node: '>=12'} cpu: [x64] os: [sunos] requiresBuild: true dev: true optional: true - /esbuild-windows-32/0.14.43: - resolution: - { - integrity: sha512-Ih3+2O5oExiqm0mY6YYE5dR0o8+AspccQ3vIAtRodwFvhuyGLjb0Hbmzun/F3Lw19nuhPMu3sW2fqIJ5xBxByw== - } - engines: { node: '>=12' } - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-32/0.15.14: - resolution: - { - integrity: sha512-pHBWrcA+/oLgvViuG9FO3kNPO635gkoVrRQwe6ZY1S0jdET07xe2toUvQoJQ8KT3/OkxqUasIty5hpuKFLD+eg== - } - engines: { node: '>=12' } + /esbuild-windows-32/0.14.54: + resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} + engines: {node: '>=12'} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /esbuild-windows-64/0.14.43: - resolution: - { - integrity: sha512-8NsuNfI8xwFuJbrCuI+aBqNTYkrWErejFO5aYM+yHqyHuL8mmepLS9EPzAzk8rvfaJrhN0+RvKWAcymViHOKEw== - } - engines: { node: '>=12' } + /esbuild-windows-64/0.14.54: + resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} + engines: {node: '>=12'} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /esbuild-windows-64/0.15.14: - resolution: - { - integrity: sha512-CszIGQVk/P8FOS5UgAH4hKc9zOaFo69fe+k1rqgBHx3CSK3Opyk5lwYriIamaWOVjBt7IwEP6NALz+tkVWdFog== - } - engines: { node: '>=12' } - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-arm64/0.14.43: - resolution: - { - integrity: sha512-7ZlD7bo++kVRblJEoG+cepljkfP8bfuTPz5fIXzptwnPaFwGS6ahvfoYzY7WCf5v/1nX2X02HDraVItTgbHnKw== - } - engines: { node: '>=12' } + /esbuild-windows-arm64/0.14.54: + resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} + engines: {node: '>=12'} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /esbuild-windows-arm64/0.15.14: - resolution: - { - integrity: sha512-KW9W4psdZceaS9A7Jsgl4WialOznSURvqX/oHZk3gOP7KbjtHLSsnmSvNdzagGJfxbAe30UVGXRe8q8nDsOSQw== - } - engines: { node: '>=12' } - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild/0.14.43: - resolution: - { - integrity: sha512-Uf94+kQmy/5jsFwKWiQB4hfo/RkM9Dh7b79p8yqd1tshULdr25G2szLz631NoH3s2ujnKEKVD16RmOxvCNKRFA== - } - engines: { node: '>=12' } + /esbuild/0.14.54: + resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} + engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - esbuild-android-64: 0.14.43 - esbuild-android-arm64: 0.14.43 - esbuild-darwin-64: 0.14.43 - esbuild-darwin-arm64: 0.14.43 - esbuild-freebsd-64: 0.14.43 - esbuild-freebsd-arm64: 0.14.43 - esbuild-linux-32: 0.14.43 - esbuild-linux-64: 0.14.43 - esbuild-linux-arm: 0.14.43 - esbuild-linux-arm64: 0.14.43 - esbuild-linux-mips64le: 0.14.43 - esbuild-linux-ppc64le: 0.14.43 - esbuild-linux-riscv64: 0.14.43 - esbuild-linux-s390x: 0.14.43 - esbuild-netbsd-64: 0.14.43 - esbuild-openbsd-64: 0.14.43 - esbuild-sunos-64: 0.14.43 - esbuild-windows-32: 0.14.43 - esbuild-windows-64: 0.14.43 - esbuild-windows-arm64: 0.14.43 - dev: true - - /esbuild/0.15.14: - resolution: - { - integrity: sha512-pJN8j42fvWLFWwSMG4luuupl2Me7mxciUOsMegKvwCmhEbJ2covUdFnihxm0FMIBV+cbwbtMoHgMCCI+pj1btQ== - } - engines: { node: '>=12' } + '@esbuild/linux-loong64': 0.14.54 + esbuild-android-64: 0.14.54 + esbuild-android-arm64: 0.14.54 + esbuild-darwin-64: 0.14.54 + esbuild-darwin-arm64: 0.14.54 + esbuild-freebsd-64: 0.14.54 + esbuild-freebsd-arm64: 0.14.54 + esbuild-linux-32: 0.14.54 + esbuild-linux-64: 0.14.54 + esbuild-linux-arm: 0.14.54 + esbuild-linux-arm64: 0.14.54 + esbuild-linux-mips64le: 0.14.54 + esbuild-linux-ppc64le: 0.14.54 + esbuild-linux-riscv64: 0.14.54 + esbuild-linux-s390x: 0.14.54 + esbuild-netbsd-64: 0.14.54 + esbuild-openbsd-64: 0.14.54 + esbuild-sunos-64: 0.14.54 + esbuild-windows-32: 0.14.54 + esbuild-windows-64: 0.14.54 + esbuild-windows-arm64: 0.14.54 + dev: true + + /esbuild/0.16.4: + resolution: {integrity: sha512-qQrPMQpPTWf8jHugLWHoGqZjApyx3OEm76dlTXobHwh/EBbavbRdjXdYi/GWr43GyN0sfpap14GPkb05NH3ROA==} + engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.15.14 - '@esbuild/linux-loong64': 0.15.14 - esbuild-android-64: 0.15.14 - esbuild-android-arm64: 0.15.14 - esbuild-darwin-64: 0.15.14 - esbuild-darwin-arm64: 0.15.14 - esbuild-freebsd-64: 0.15.14 - esbuild-freebsd-arm64: 0.15.14 - esbuild-linux-32: 0.15.14 - esbuild-linux-64: 0.15.14 - esbuild-linux-arm: 0.15.14 - esbuild-linux-arm64: 0.15.14 - esbuild-linux-mips64le: 0.15.14 - esbuild-linux-ppc64le: 0.15.14 - esbuild-linux-riscv64: 0.15.14 - esbuild-linux-s390x: 0.15.14 - esbuild-netbsd-64: 0.15.14 - esbuild-openbsd-64: 0.15.14 - esbuild-sunos-64: 0.15.14 - esbuild-windows-32: 0.15.14 - esbuild-windows-64: 0.15.14 - esbuild-windows-arm64: 0.15.14 - dev: true - - /fast-glob/3.2.11: - resolution: - { - integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - } - engines: { node: '>=8.6.0' } + '@esbuild/android-arm': 0.16.4 + '@esbuild/android-arm64': 0.16.4 + '@esbuild/android-x64': 0.16.4 + '@esbuild/darwin-arm64': 0.16.4 + '@esbuild/darwin-x64': 0.16.4 + '@esbuild/freebsd-arm64': 0.16.4 + '@esbuild/freebsd-x64': 0.16.4 + '@esbuild/linux-arm': 0.16.4 + '@esbuild/linux-arm64': 0.16.4 + '@esbuild/linux-ia32': 0.16.4 + '@esbuild/linux-loong64': 0.16.4 + '@esbuild/linux-mips64el': 0.16.4 + '@esbuild/linux-ppc64': 0.16.4 + '@esbuild/linux-riscv64': 0.16.4 + '@esbuild/linux-s390x': 0.16.4 + '@esbuild/linux-x64': 0.16.4 + '@esbuild/netbsd-x64': 0.16.4 + '@esbuild/openbsd-x64': 0.16.4 + '@esbuild/sunos-x64': 0.16.4 + '@esbuild/win32-arm64': 0.16.4 + '@esbuild/win32-ia32': 0.16.4 + '@esbuild/win32-x64': 0.16.4 + dev: true + + /esm-env/1.0.0: + resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} + dev: true + + /estree-walker/2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + + /fast-glob/3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 @@ -978,65 +916,70 @@ packages: micromatch: 4.0.5 dev: true - /fastq/1.13.0: - resolution: - { - integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - } + /fastq/1.14.0: + resolution: {integrity: sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==} dependencies: reusify: 1.0.4 dev: true + /file-uri-to-path/1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + dev: true + /fill-range/7.0.1: - resolution: - { - integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 dev: true + /fs-minipass/2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: true + /fs.realpath/1.0.0: - resolution: - { - integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - } + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true /fsevents/2.3.2: - resolution: - { - integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - } - engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true dev: true optional: true /function-bind/1.1.1: - resolution: - { - integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - } + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + + /gauge/3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 dev: true /glob-parent/5.1.2: - resolution: - { - integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - } - engines: { node: '>= 6' } + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 dev: true /glob/7.2.3: - resolution: - { - integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - } + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -1047,473 +990,429 @@ packages: dev: true /globalyzer/0.1.0: - resolution: - { - integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q== - } + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} dev: true /globrex/0.1.2: - resolution: - { - integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== - } + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} dev: true /golden-fleece/1.0.9: - resolution: - { - integrity: sha512-YSwLaGMOgSBx9roJlNLL12c+FRiw7VECphinc6mGucphc/ZxTHgdEz6gmJqH6NOzYEd/yr64hwjom5pZ+tJVpg== - } + resolution: {integrity: sha512-YSwLaGMOgSBx9roJlNLL12c+FRiw7VECphinc6mGucphc/ZxTHgdEz6gmJqH6NOzYEd/yr64hwjom5pZ+tJVpg==} dev: true /graceful-fs/4.2.10: - resolution: - { - integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - } + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + dev: true + + /has-unicode/2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} dev: true /has/1.0.3: - resolution: - { - integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - } - engines: { node: '>= 0.4.0' } + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 dev: true + /https-proxy-agent/5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /import-fresh/3.3.0: - resolution: - { - integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 dev: true /import-meta-resolve/2.2.0: - resolution: - { - integrity: sha512-CpPOtiCHxP9HdtDM5F45tNiAe66Cqlv3f5uHoJjt+KlaLrUh9/Wz9vepADZ78SlqEo62aDWZtj9ydMGXV+CPnw== - } + resolution: {integrity: sha512-CpPOtiCHxP9HdtDM5F45tNiAe66Cqlv3f5uHoJjt+KlaLrUh9/Wz9vepADZ78SlqEo62aDWZtj9ydMGXV+CPnw==} dev: true /inflight/1.0.6: - resolution: - { - integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - } + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: once: 1.4.0 wrappy: 1.0.2 dev: true /inherits/2.0.4: - resolution: - { - integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - } + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true /is-binary-path/2.1.0: - resolution: - { - integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 dev: true - /is-core-module/2.9.0: - resolution: - { - integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== - } + /is-core-module/2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} dependencies: has: 1.0.3 dev: true /is-extglob/2.1.1: - resolution: - { - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} dev: true /is-glob/4.0.3: - resolution: - { - integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 dev: true /is-number/7.0.0: - resolution: - { - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - } - engines: { node: '>=0.12.0' } + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} dev: true /kleur/4.1.5: - resolution: - { - integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} dev: true - /magic-string/0.25.9: - resolution: - { - integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== - } + /lru-cache/6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} dependencies: - sourcemap-codec: 1.4.8 + yallist: 4.0.0 dev: true - /magic-string/0.26.7: - resolution: - { - integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow== - } - engines: { node: '>=12' } + /magic-string/0.25.9: + resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} dependencies: sourcemap-codec: 1.4.8 dev: true /magic-string/0.27.0: - resolution: - { - integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA== - } - engines: { node: '>=12' } + resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} + engines: {node: '>=12'} dependencies: - '@jridgewell/sourcemap-codec': 1.4.13 + '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /marked/4.0.16: - resolution: - { - integrity: sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA== - } - engines: { node: '>= 12' } + /make-dir/3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.0 + dev: true + + /marked/4.2.4: + resolution: {integrity: sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==} + engines: {node: '>= 12'} hasBin: true dev: false /merge2/1.4.1: - resolution: - { - integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - } - engines: { node: '>= 8' } + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} dev: true /micromatch/4.0.5: - resolution: - { - integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} dependencies: braces: 3.0.2 picomatch: 2.3.1 dev: true /mime/3.0.0: - resolution: - { - integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== - } - engines: { node: '>=10.0.0' } + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} hasBin: true dev: true /min-indent/1.0.1: - resolution: - { - integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - } - engines: { node: '>=4' } + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} dev: true /minimatch/3.1.2: - resolution: - { - integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - } + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 dev: true - /minimist/1.2.6: - resolution: - { - integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - } + /minimist/1.2.7: + resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} + dev: true + + /minipass/3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: true + + /minipass/4.0.0: + resolution: {integrity: sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: true + + /minizlib/2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 dev: true /mkdirp/0.5.6: - resolution: - { - integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== - } + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true dependencies: - minimist: 1.2.6 + minimist: 1.2.7 + dev: true + + /mkdirp/1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true dev: true /monaco-editor/0.33.0: - resolution: - { - integrity: sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw== - } + resolution: {integrity: sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw==} dev: false /mri/1.2.0: - resolution: - { - integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== - } - engines: { node: '>=4' } + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} dev: true /mrmime/1.0.1: - resolution: - { - integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== - } - engines: { node: '>=10' } + resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} + engines: {node: '>=10'} dev: true /ms/2.1.2: - resolution: - { - integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - } + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true /nanoid/3.3.4: - resolution: - { - integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== - } - engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /node-fetch/2.6.7: + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + + /node-gyp-build/4.5.0: + resolution: {integrity: sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==} hasBin: true dev: true + /nopt/5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: true + /normalize-path/3.0.0: - resolution: - { - integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npmlog/5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + dev: true + + /object-assign/4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} dev: true /once/1.4.0: - resolution: - { - integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - } + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 dev: true /parent-module/1.0.1: - resolution: - { - integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} dependencies: callsites: 3.1.0 dev: true /path-is-absolute/1.0.1: - resolution: - { - integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} dev: true /path-parse/1.0.7: - resolution: - { - integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - } + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true /picocolors/1.0.0: - resolution: - { - integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - } + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true /picomatch/2.3.1: - resolution: - { - integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} dev: true /port-authority/2.0.1: - resolution: - { - integrity: sha512-Hz/WvSNt5+7x+Rq1Cn6DetJOZxKtLDehJ1mLCYge6ju4QvSF/PHvRgy94e1SKJVI96AJTcqEdNwkkaAFad+TXQ== - } + resolution: {integrity: sha512-Hz/WvSNt5+7x+Rq1Cn6DetJOZxKtLDehJ1mLCYge6ju4QvSF/PHvRgy94e1SKJVI96AJTcqEdNwkkaAFad+TXQ==} dev: false /postcss/8.4.19: - resolution: - { - integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== - } - engines: { node: ^10 || ^12 || >=14 } + resolution: {integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==} + engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 dev: true - /prettier-plugin-svelte/2.7.0_kkjbqzpydplecjtkxrgomroeru: - resolution: - { - integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA== - } + /prettier-plugin-svelte/2.9.0_sro2v6ld777payjtkjtiuogcxi: + resolution: {integrity: sha512-3doBi5NO4IVgaNPtwewvrgPpqAcvNv0NwJNflr76PIGgi9nf1oguQV1Hpdm9TI2ALIQVn/9iIwLpBO5UcD2Jiw==} peerDependencies: prettier: ^1.16.4 || ^2.0.0 svelte: ^3.2.0 dependencies: - prettier: 2.6.2 - svelte: 3.48.0 + prettier: 2.8.1 + svelte: 3.54.0 dev: true - /prettier/2.6.2: - resolution: - { - integrity: sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== - } - engines: { node: '>=10.13.0' } + /prettier/2.8.1: + resolution: {integrity: sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==} + engines: {node: '>=10.13.0'} hasBin: true dev: true /prism-svelte/0.5.0: - resolution: - { - integrity: sha512-db91Bf3pRGKDPz1lAqLFSJXeW13mulUJxhycysFpfXV5MIK7RgWWK2E5aPAa71s8TCzQUXxF5JOV42/iOs6QkA== - } + resolution: {integrity: sha512-db91Bf3pRGKDPz1lAqLFSJXeW13mulUJxhycysFpfXV5MIK7RgWWK2E5aPAa71s8TCzQUXxF5JOV42/iOs6QkA==} dev: false - /prismjs/1.28.0: - resolution: - { - integrity: sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw== - } - engines: { node: '>=6' } + /prismjs/1.29.0: + resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} + engines: {node: '>=6'} dev: false /queue-microtask/1.2.3: - resolution: - { - integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - } + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /readable-stream/3.6.0: + resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 dev: true /readdirp/3.6.0: - resolution: - { - integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - } - engines: { node: '>=8.10.0' } + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 dev: true /resolve-from/4.0.0: - resolution: - { - integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - } - engines: { node: '>=4' } + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from/5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} dev: true /resolve/1.22.1: - resolution: - { - integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - } + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true dependencies: - is-core-module: 2.9.0 + is-core-module: 2.11.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true /reusify/1.0.4: - resolution: - { - integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - } - engines: { iojs: '>=1.0.0', node: '>=0.10.0' } + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true /rimraf/2.7.1: - resolution: - { - integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - } + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} hasBin: true dependencies: glob: 7.2.3 dev: true - /rollup/2.79.1: - resolution: - { - integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== - } - engines: { node: '>=10.0.0' } + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup/3.7.3: + resolution: {integrity: sha512-7e68MQbAWCX6mI4/0lG1WHd+NdNAlVamg0Zkd+8LZ/oXojligdGnCNyHlzXqXCZObyjs5FRc3AH0b17iJESGIQ==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: fsevents: 2.3.2 dev: true /run-parallel/1.2.0: - resolution: - { - integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - } + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 dev: true /sade/1.8.1: - resolution: - { - integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} dependencies: mri: 1.2.0 dev: true + /safe-buffer/5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + /sander/0.5.1: - resolution: - { - integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA== - } + resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} dependencies: es6-promise: 3.3.1 graceful-fs: 4.2.10 @@ -1521,19 +1420,34 @@ packages: rimraf: 2.7.1 dev: true + /semver/6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: true + + /semver/7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /set-blocking/2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: true + /set-cookie-parser/2.5.1: - resolution: - { - integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ== - } + resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==} + dev: true + + /signal-exit/3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true /sirv/2.0.2: - resolution: - { - integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==} + engines: {node: '>= 10'} dependencies: '@polka/url': 1.0.0-next.21 mrmime: 1.0.1 @@ -1541,77 +1455,78 @@ packages: dev: true /sorcery/0.10.0: - resolution: - { - integrity: sha512-R5ocFmKZQFfSTstfOtHjJuAwbpGyf9qjQa1egyhvXSbM7emjrtLXtGdZsDJDABC85YBfVvrOiGWKSYXPKdvP1g== - } + resolution: {integrity: sha512-R5ocFmKZQFfSTstfOtHjJuAwbpGyf9qjQa1egyhvXSbM7emjrtLXtGdZsDJDABC85YBfVvrOiGWKSYXPKdvP1g==} hasBin: true dependencies: buffer-crc32: 0.2.13 - minimist: 1.2.6 + minimist: 1.2.7 sander: 0.5.1 sourcemap-codec: 1.4.8 dev: true /source-map-js/1.0.2: - resolution: - { - integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} dev: true /sourcemap-codec/1.4.8: - resolution: - { - integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - } + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead dev: true /streamsearch/1.1.0: - resolution: - { - integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - } - engines: { node: '>=10.0.0' } + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + dev: true + + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 dev: true /strip-indent/3.0.0: - resolution: - { - integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} dependencies: min-indent: 1.0.1 dev: true /supports-preserve-symlinks-flag/1.0.0: - resolution: - { - integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - } - engines: { node: '>= 0.4' } - dev: true - - /svelte-check/2.7.2_svelte@3.48.0: - resolution: - { - integrity: sha512-TuVX4YtXHbRM8sVuK5Jk+mKWdm3f0d6hvAC6qCTp8yUszGZewpEBCo2V5fRWZCiz+0J4OCiDHOS+DFMxv39rJA== - } + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /svelte-check/2.10.2_svelte@3.54.0: + resolution: {integrity: sha512-h1Tuiir0m8J5yqN+Vx6qgKKk1L871e6a9o7rMwVWfu8Qs6Wg7x2R+wcxS3SO3VpW5JCxCat90rxPsZMYgz+HaQ==} hasBin: true peerDependencies: svelte: ^3.24.0 dependencies: - '@jridgewell/trace-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.17 chokidar: 3.5.3 - fast-glob: 3.2.11 + fast-glob: 3.2.12 import-fresh: 3.3.0 picocolors: 1.0.0 sade: 1.8.1 - svelte: 3.48.0 - svelte-preprocess: 4.10.7_wwvk7nlptlrqo2czohjtk6eiqm + svelte: 3.54.0 + svelte-preprocess: 4.10.7_gk4i2giaum4t5l5a23coockzlu typescript: 4.6.4 transitivePeerDependencies: - '@babel/core' @@ -1626,24 +1541,18 @@ packages: - sugarss dev: true - /svelte-hmr/0.15.1_svelte@3.48.0: - resolution: - { - integrity: sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA== - } - engines: { node: ^12.20 || ^14.13.1 || >= 16 } + /svelte-hmr/0.15.1_svelte@3.54.0: + resolution: {integrity: sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==} + engines: {node: ^12.20 || ^14.13.1 || >= 16} peerDependencies: svelte: '>=3.19.0' dependencies: - svelte: 3.48.0 + svelte: 3.54.0 dev: true - /svelte-preprocess/4.10.7_wwvk7nlptlrqo2czohjtk6eiqm: - resolution: - { - integrity: sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw== - } - engines: { node: '>= 9.11.2' } + /svelte-preprocess/4.10.7_gk4i2giaum4t5l5a23coockzlu: + resolution: {integrity: sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==} + engines: {node: '>= 9.11.2'} requiresBuild: true peerDependencies: '@babel/core': ^7.10.2 @@ -1688,71 +1597,70 @@ packages: magic-string: 0.25.9 sorcery: 0.10.0 strip-indent: 3.0.0 - svelte: 3.48.0 + svelte: 3.54.0 typescript: 4.6.4 dev: true - /svelte/3.48.0: - resolution: - { - integrity: sha512-fN2YRm/bGumvjUpu6yI3BpvZnpIm9I6A7HR4oUNYd7ggYyIwSA/BX7DJ+UXXffLp6XNcUijyLvttbPVCYa/3xQ== - } - engines: { node: '>= 8' } + /svelte/3.54.0: + resolution: {integrity: sha512-tdrgeJU0hob0ZWAMoKXkhcxXA7dpTg6lZGxUeko5YqvPdJBiyRspGsCwV27kIrbrqPP2WUoSV9ca0gnLlw8YzQ==} + engines: {node: '>= 8'} + dev: true + + /tar/6.1.13: + resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==} + engines: {node: '>=10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 4.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 dev: true /tiny-glob/0.2.9: - resolution: - { - integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg== - } + resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} dependencies: globalyzer: 0.1.0 globrex: 0.1.2 dev: true /to-regex-range/5.0.1: - resolution: - { - integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - } - engines: { node: '>=8.0' } + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 dev: true /totalist/3.0.0: - resolution: - { - integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==} + engines: {node: '>=6'} + dev: true + + /tr46/0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: true /typescript/4.6.4: - resolution: - { - integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg== - } - engines: { node: '>=4.2.0' } + resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==} + engines: {node: '>=4.2.0'} hasBin: true dev: true - /undici/5.13.0: - resolution: - { - integrity: sha512-UDZKtwb2k7KRsK4SdXWG7ErXiL7yTGgLWvk2AXO1JMjgjh404nFo6tWSCM2xMpJwMPx3J8i/vfqEh1zOqvj82Q== - } - engines: { node: '>=12.18' } + /undici/5.14.0: + resolution: {integrity: sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==} + engines: {node: '>=12.18'} dependencies: busboy: 1.6.0 dev: true - /vite/3.2.4: - resolution: - { - integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw== - } - engines: { node: ^14.18.0 || >=16.0.0 } + /util-deprecate/1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /vite/4.0.0: + resolution: {integrity: sha512-ynad+4kYs8Jcnn8J7SacS9vAbk7eMy0xWg6E7bAhS1s79TK+D7tVFGXVZ55S7RNLRROU1rxoKlvZ/qjaB41DGA==} + engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: '@types/node': '>= 14' @@ -1775,38 +1683,49 @@ packages: terser: optional: true dependencies: - esbuild: 0.15.14 + esbuild: 0.16.4 postcss: 8.4.19 resolve: 1.22.1 - rollup: 2.79.1 + rollup: 3.7.3 optionalDependencies: fsevents: 2.3.2 dev: true - /vitefu/0.2.2_vite@3.2.4: - resolution: - { - integrity: sha512-8CKEIWPm4B4DUDN+h+hVJa9pyNi7rzc5MYmbxhs1wcMakueGFNWB5/DL30USm9qU3xUPnL4/rrLEAwwFiD1tag== - } + /vitefu/0.2.3_vite@4.0.0: + resolution: {integrity: sha512-75l7TTuU8isAhz1QFtNKjDkqjxvndfMC1AfIMjJ0ZQ59ZD0Ow9QOIsJJX16Wv9PS8f+zMzp6fHy5cCbKG/yVUQ==} peerDependencies: - vite: ^3.0.0 + vite: ^3.0.0 || ^4.0.0 peerDependenciesMeta: vite: optional: true dependencies: - vite: 3.2.4 + vite: 4.0.0 + dev: true + + /webidl-conversions/3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true + + /whatwg-url/5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true + + /wide-align/1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + dependencies: + string-width: 4.2.3 dev: true /wrappy/1.0.2: - resolution: { integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= } + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /ws/8.8.0: - resolution: - { - integrity: sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== - } - engines: { node: '>=10.0.0' } + /ws/8.11.0: + resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -1816,3 +1735,7 @@ packages: utf-8-validate: optional: true dev: false + + /yallist/4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true diff --git a/scripts/create-common-bundle/index.js b/scripts/create-common-bundle/index.js index 696d6e7ae..9352a5467 100644 --- a/scripts/create-common-bundle/index.js +++ b/scripts/create-common-bundle/index.js @@ -8,7 +8,7 @@ import { execSync } from 'child_process'; const cwd = 'content/tutorial/common'; if (!fs.existsSync(`${cwd}/node_modules`)) { - execSync('npm install', { cwd }); + execSync('npm ci', { cwd }); } const zip = new AdmZip(); @@ -19,11 +19,7 @@ const ignored_basenames = ['.DS_Store', 'LICENSE']; const ignored_extensions = ['.d.ts', '.map']; const ignored_directories = ['.svelte-kit', 'node_modules/.bin', 'node_modules/rollup/dist/shared']; -const ignored_files = new Set([ - 'node_modules/rollup/dist/es/rollup.browser.js', - 'node_modules/rollup/dist/rollup.browser.js', - 'node_modules/svelte/compiler.js' -]); +const ignored_files = new Set(['node_modules/svelte/compiler.js']); for (const file of glob('**', { cwd, filesOnly: true, dot: true }).map((file) => file.replaceAll('\\', '/') @@ -44,7 +40,7 @@ for (const file of glob('**', { cwd, filesOnly: true, dot: true }).map((file) => fs.readFileSync(`${cwd}/${file}`) ); continue; - } else if (file.startsWith('node_modules/esbuild')) { + } else if (file.startsWith('node_modules/esbuild') || file.startsWith('node_modules/@esbuild')) { continue; } diff --git a/src/lib/client/adapters/webcontainer/index.js b/src/lib/client/adapters/webcontainer/index.js index 2bbd172c7..b5fc7f3d3 100644 --- a/src/lib/client/adapters/webcontainer/index.js +++ b/src/lib/client/adapters/webcontainer/index.js @@ -1,5 +1,6 @@ import { load } from '@webcontainer/api'; import base64 from 'base64-js'; +import { get_depth } from '../../../utils.js'; import { ready } from '../common/index.js'; /** @type {import('@webcontainer/api').WebContainer} Web container singleton */ @@ -276,7 +277,7 @@ function convert_stubs_to_tree(stubs, depth = 1) { const tree = {}; for (const stub of stubs) { - if (stub.depth === depth) { + if (get_depth(stub.name) === depth) { if (stub.type === 'directory') { const children = stubs.filter((child) => child.name.startsWith(stub.name)); diff --git a/src/lib/components/Modal.svelte b/src/lib/components/Modal.svelte index e105d4e7b..0dbb0baf9 100644 --- a/src/lib/components/Modal.svelte +++ b/src/lib/components/Modal.svelte @@ -7,7 +7,7 @@ onMount(() => { const selection = window.getSelection(); - const active = document.activeElement; + const active = /** @type {HTMLElement} */ (document.activeElement); const sfnsp = selection?.focusNode?.parentElement; if (modal.showModal) modal.showModal(); diff --git a/src/lib/components/SplitPane.svelte b/src/lib/components/SplitPane.svelte index acf078769..04fcc9b7e 100644 --- a/src/lib/components/SplitPane.svelte +++ b/src/lib/components/SplitPane.svelte @@ -68,7 +68,7 @@ function drag(node, callback) { /** @param {MouseEvent} event */ const mousedown = (event) => { - if (event.which !== 1) return; + if (event.button !== 0) return; event.preventDefault(); diff --git a/src/routes/tutorial/[slug]/ContextMenu.svelte b/src/lib/components/filetree/ContextMenu.svelte similarity index 64% rename from src/routes/tutorial/[slug]/ContextMenu.svelte rename to src/lib/components/filetree/ContextMenu.svelte index 62d303f02..7458fcd4b 100644 --- a/src/routes/tutorial/[slug]/ContextMenu.svelte +++ b/src/lib/components/filetree/ContextMenu.svelte @@ -5,21 +5,23 @@ import { writable } from 'svelte/store'; /** - * @typedef {Array<{ name: string, action: () => void }>} MenuItems + * @typedef {{ icon: string; label: string; fn: () => void }} MenuItem */ /** - * @type {import("svelte/store").Writable<{x: number; y: number; items: MenuItems} | null>} + * @type {import("svelte/store").Writable<{x: number; y: number; items: MenuItem[]} | null>} */ let menu_items = writable(null); /** * @param {number} x * @param {number} y - * @param {MenuItems} items + * @param {MenuItem[]} items */ export function open(x, y, items) { - menu_items.set({ x, y, items }); + if (items.length > 0) { + menu_items.set({ x, y, items }); + } } @@ -29,7 +31,7 @@
      {#each $menu_items.items as item}
    • - +
    • {/each}
    @@ -42,31 +44,43 @@ diff --git a/src/lib/components/filetree/File.svelte b/src/lib/components/filetree/File.svelte new file mode 100644 index 000000000..b51f35117 --- /dev/null +++ b/src/lib/components/filetree/File.svelte @@ -0,0 +1,72 @@ + + +
    + select(file)} + on:edit={() => { + state = 'renaming'; + }} + on:rename={(e) => { + rename(file, e.detail.basename); + }} + on:cancel={() => { + state = 'idle'; + }} + /> +
    + + diff --git a/src/lib/components/filetree/Filetree.svelte b/src/lib/components/filetree/Filetree.svelte new file mode 100644 index 000000000..c06131ba6 --- /dev/null +++ b/src/lib/components/filetree/Filetree.svelte @@ -0,0 +1,252 @@ + + +
    + !hidden.has(stub.basename))} + expanded + /> +
    + +{#if modal_text} + (modal_text = '')}> + + +{/if} + + diff --git a/src/lib/components/filetree/Folder.svelte b/src/lib/components/filetree/Folder.svelte new file mode 100644 index 000000000..a28928604 --- /dev/null +++ b/src/lib/components/filetree/Folder.svelte @@ -0,0 +1,205 @@ + + +
    + { + expanded = !expanded; + }} + on:edit={() => { + state = 'renaming'; + }} + on:rename={(e) => { + rename(directory, e.detail.basename); + }} + on:cancel={() => { + state = 'idle'; + }} + /> +
    + +{#if expanded} +
      + {#if state === 'add_directory'} +
    • +
      + { + add(prefix + e.detail.basename, 'directory'); + }} + on:cancel={() => { + state = 'idle'; + }} + /> +
      +
    • + {/if} + + {#each child_directories as directory} +
    • + +
    • + {/each} + + {#if state === 'add_file'} +
    • +
      + { + add(prefix + e.detail.basename, 'file'); + }} + on:cancel={() => { + state = 'idle'; + }} + /> +
      +
    • + {/if} + + {#each child_files as file} +
    • + {/each} +
    +{/if} + + diff --git a/src/lib/components/filetree/Item.svelte b/src/lib/components/filetree/Item.svelte new file mode 100644 index 000000000..6249a516e --- /dev/null +++ b/src/lib/components/filetree/Item.svelte @@ -0,0 +1,158 @@ + + +{#if renaming} + + { + if (!cancelling) return; + commit(e); + }} + on:keyup={(e) => { + if (e.key === 'Enter') { + commit(e); + } + + if (e.key === 'Escape') { + cancel(); + } + }} + /> +{:else} + + + {#if actions.length > 0} +
    + {#each actions as action} +
    + {/if} +{/if} + + diff --git a/src/lib/components/filetree/context.js b/src/lib/components/filetree/context.js new file mode 100644 index 000000000..94f00316f --- /dev/null +++ b/src/lib/components/filetree/context.js @@ -0,0 +1,25 @@ +import { setContext, getContext } from 'svelte'; + +/** + * @typedef {{ + * endstate: import('svelte/store').Writable>; + * files: import('svelte/store').Writable; + * selected: import('svelte/store').Writable; + * readonly: import('svelte/store').Writable; + * select: (file: import('$lib/types').FileStub) => void; + * add: (name: string, type: 'file' | 'directory') => Promise; + * rename: (stub: import('$lib/types').Stub, name: string) => Promise; + * remove: (stub: import('$lib/types').Stub) => Promise; + * }} FileTreeContext + */ + +const key = {}; + +/** @param {FileTreeContext} context */ +export function set(context) { + setContext(key, context); +} + +export function get() { + return /** @type {FileTreeContext} */ (getContext(key)); +} diff --git a/src/routes/tutorial/[slug]/delete.svg b/src/lib/icons/delete.svg similarity index 100% rename from src/routes/tutorial/[slug]/delete.svg rename to src/lib/icons/delete.svg diff --git a/src/routes/tutorial/[slug]/file-edit.svg b/src/lib/icons/file-edit.svg similarity index 100% rename from src/routes/tutorial/[slug]/file-edit.svg rename to src/lib/icons/file-edit.svg diff --git a/src/routes/tutorial/[slug]/file-new.svg b/src/lib/icons/file-new.svg similarity index 100% rename from src/routes/tutorial/[slug]/file-new.svg rename to src/lib/icons/file-new.svg diff --git a/src/routes/tutorial/[slug]/folder-new.svg b/src/lib/icons/folder-new.svg similarity index 100% rename from src/routes/tutorial/[slug]/folder-new.svg rename to src/lib/icons/folder-new.svg diff --git a/src/routes/tutorial/[slug]/folder-open.svg b/src/lib/icons/folder-open.svg similarity index 100% rename from src/routes/tutorial/[slug]/folder-open.svg rename to src/lib/icons/folder-open.svg diff --git a/src/routes/tutorial/[slug]/folder.svg b/src/lib/icons/folder.svg similarity index 100% rename from src/routes/tutorial/[slug]/folder.svg rename to src/lib/icons/folder.svg diff --git a/src/routes/tutorial/[slug]/rename.svg b/src/lib/icons/rename.svg similarity index 100% rename from src/routes/tutorial/[slug]/rename.svg rename to src/lib/icons/rename.svg diff --git a/src/lib/server/content.js b/src/lib/server/content.js index 233b2ba88..5fd5c905e 100644 --- a/src/lib/server/content.js +++ b/src/lib/server/content.js @@ -11,7 +11,8 @@ const text_files = new Set([ '.css', '.svg', '.html', - '.md' + '.md', + '.env' ]); const excluded = new Set(['.DS_Store', '.gitkeep', '.svelte-kit', 'package-lock.json']); @@ -24,8 +25,11 @@ function json(file) { export function get_index() { const parts = []; - /** @type {import('$lib/types').SectionRaw | null} */ - let last_section = null; + /** @type {import('$lib/types').ExerciseRaw | null} */ + let last_exercise = null; + + let last_part_meta = null; + let last_chapter_meta = null; for (const part of fs.readdirSync('content/tutorial')) { if (!/^\d{2}-/.test(part)) continue; @@ -45,30 +49,46 @@ export function get_index() { slug: chapter }; - const sections = []; + const exercises = []; + + for (const exercise of fs.readdirSync(`content/tutorial/${part}/${chapter}`)) { + if (!/^\d{2}-/.test(exercise)) continue; - for (const section of fs.readdirSync(`content/tutorial/${part}/${chapter}`)) { - const dir = `content/tutorial/${part}/${chapter}/${section}`; + const dir = `content/tutorial/${part}/${chapter}/${exercise}`; if (!fs.statSync(dir).isDirectory()) continue; const text = fs.readFileSync(`${dir}/README.md`, 'utf-8'); const { frontmatter, markdown } = extract_frontmatter(text, dir); const { title } = frontmatter; - - const slug = section.slice(3); - - if (last_section) last_section.next = { slug, title }; - - sections.push( - (last_section = { - slug: section.slice(3), + const slug = exercise.slice(3); + const meta = fs.existsSync(`${dir}/meta.json`) ? json(`${dir}/meta.json`) : {}; + + if (last_exercise) { + last_exercise.next = { + slug, + title: + last_part_meta !== part_meta + ? part_meta.title + : last_chapter_meta !== chapter_meta + ? chapter_meta.title + : title, + }; + } + + exercises.push( + (last_exercise = { + slug: exercise.slice(3), title: frontmatter.title, markdown, dir, - prev: last_section ? { slug: last_section.slug, title: last_section.title } : null, + prev: last_exercise ? { slug: last_exercise.slug } : null, + meta, next: null }) ); + + last_chapter_meta = chapter_meta; + last_part_meta = part_meta; } chapters.push({ @@ -76,7 +96,7 @@ export function get_index() { ...part_meta, ...chapter_meta }, - sections + exercises }); } @@ -92,58 +112,78 @@ export function get_index() { /** * @param {string} slug - * @returns {import('$lib/types').Section | undefined} + * @returns {import('$lib/types').Exercise | undefined} */ -export function get_section(slug) { +export function get_exercise(slug) { const index = get_index(); + for (let i = 0; i < index.length; i += 1) { const part = index[i]; - for (const chapter of part.chapters) { - for (const section of chapter.sections) { - if (section.slug !== slug) continue; - - const a = { - ...walk('content/tutorial/common', { exclude: ['node_modules'] }), - ...walk(`content/tutorial/${part.slug}/common`), - ...walk(`${section.dir}/app-a`) - }; - - const b = walk(`${section.dir}/app-b`); - - const scope = chapter.meta.scope ?? part.meta.scope; - const filenames = new Set( - Object.keys(a) - .filter((filename) => filename.startsWith(scope.prefix)) - .map((filename) => filename.slice(scope.prefix.length)) - ); + /** @type {string[]} */ + const chain = []; - return { - part: { - slug: part.meta.slug, - title: part.meta.title, - index: i - }, - chapter: { - slug: chapter.meta.slug, - title: chapter.meta.title - }, - scope, - focus: chapter.meta.focus ?? part.meta.focus, - title: section.title, - slug: section.slug, - prev: section.prev, - next: section.next, - dir: section.dir, - html: transform(section.markdown, { - codespan: (text) => - filenames.size > 1 && filenames.has(text) - ? `${text}` - : `${text}` - }), - a, - b - }; + for (const chapter of part.chapters) { + for (const exercise of chapter.exercises) { + if (fs.existsSync(`${exercise.dir}/app-a`)) { + chain.length = 0; + chain.push(`${exercise.dir}/app-a`); + } + + if (exercise.slug === slug) { + const a = { + ...walk('content/tutorial/common', { exclude: ['node_modules'] }), + ...walk(`content/tutorial/${part.slug}/common`) + }; + + for (const dir of chain) { + Object.assign(a, walk(dir)); + } + + const b = walk(`${exercise.dir}/app-b`); + + const scope = chapter.meta.scope ?? part.meta.scope; + const filenames = new Set( + Object.keys(a) + .filter( + (filename) => filename.startsWith(scope.prefix) && a[filename].type === 'file' + ) + .map((filename) => filename.slice(scope.prefix.length)) + ); + + return { + part: { + slug: part.meta.slug, + title: part.meta.title, + index: i + }, + chapter: { + slug: chapter.meta.slug, + title: chapter.meta.title + }, + scope, + focus: chapter.meta.focus ?? part.meta.focus, + title: exercise.title, + slug: exercise.slug, + prev: exercise.prev, + next: exercise.next, + dir: exercise.dir, + editing_constraints: { + create: exercise.meta.editing_constraints?.create ?? [], + remove: exercise.meta.editing_constraints?.remove ?? [], + }, + html: transform(exercise.markdown, { + codespan: (text) => + filenames.size > 1 && filenames.has(text) + ? `${text}` + : `${text}` + }), + a, + b + }; + } + + chain.push(`${exercise.dir}/app-b`); } } } @@ -205,13 +245,12 @@ export function walk(cwd, options = {}) { result[name] = { type: 'directory', name, - basename, - depth + basename }; walk_dir(name + '/', depth + 1); } else { - const text = text_files.has(path.extname(name)); + const text = text_files.has(path.extname(name) || path.basename(name)); const contents = fs.readFileSync(resolved, text ? 'utf-8' : 'base64'); result[name] = { @@ -219,8 +258,7 @@ export function walk(cwd, options = {}) { name, basename, text, - contents, - depth + contents }; } } diff --git a/src/lib/server/markdown.js b/src/lib/server/markdown.js index 5b6d55880..af1ab577d 100644 --- a/src/lib/server/markdown.js +++ b/src/lib/server/markdown.js @@ -46,15 +46,16 @@ function highlight_spans(content, classname) { // }); } +/** @type {Partial} */ const default_renderer = { - code: (source, language, current) => { + code: (source, language = '') => { /** @type {Record} */ const options = {}; let html = ''; source = source - .replace(/\/\/\/ (.+?): (.+)\n/gm, (match, key, value) => { + .replace(/\/\/\/ (.+?): (.+)\n/gm, (_, key, value) => { options[key] = value; return ''; }) @@ -68,7 +69,7 @@ const default_renderer = { } return prefix + tabs; }) - .replace(/(\+\+\+|---|:::)/g, (_, delimiter) => { + .replace(/(\+\+\+|---|:::)/g, (_, /** @type {keyof delimiter_substitutes} */ delimiter) => { return delimiter_substitutes[delimiter]; }) .replace(/\*\\\//g, '*/'); @@ -94,7 +95,8 @@ const default_renderer = { }) .join('')}`; } else { - const plang = languages[language]; + const lang = /** @type {keyof languages} */ (language); + const plang = languages[lang]; const highlighted = plang ? PrismJS.highlight(source, PrismJS.languages[plang], language) : escape(source); @@ -115,12 +117,10 @@ const default_renderer = { return highlight_spans(content, 'highlight'); }); } -} +}; marked.use({ - renderer: { - - } + renderer: {} }); /** diff --git a/src/lib/types/index.d.ts b/src/lib/types/index.d.ts index 2ece8624c..80910f3d1 100644 --- a/src/lib/types/index.d.ts +++ b/src/lib/types/index.d.ts @@ -6,14 +6,12 @@ export interface FileStub { basename: string; contents: string; text: boolean; - depth: number; } export interface DirectoryStub { type: 'directory'; name: string; basename: string; - depth: number; } export type Stub = FileStub | DirectoryStub; @@ -26,7 +24,7 @@ export interface Adapter { destroy(): Promise; } -export interface Section { +export interface Exercise { part: { slug: string; title: string; @@ -44,34 +42,39 @@ export interface Section { focus: string; title: string; slug: string; - prev: { slug: string; title: string } | null; + prev: { slug: string } | null; next: { slug: string; title: string } | null; html: string; dir: string; + editing_constraints: { + create: string[]; + remove: string[]; + } a: Record; b: Record; } -export interface SectionRaw { +export interface ExerciseRaw { title: string; slug: string; - prev: { slug: string; title: string } | null; + prev: { slug: string } | null; next: { slug: string; title: string } | null; + meta: any; markdown: string; dir: string; } -export interface SectionStub { +export interface ExerciseStub { title: string; slug: string; - prev: { slug: string; title: string } | null; + prev: { slug: string } | null; next: { slug: string; title: string } | null; } export interface ChapterStub { slug: string; title: string; - sections: SectionStub[]; + exercises: ExerciseStub[]; } export interface PartStub { diff --git a/src/lib/utils.js b/src/lib/utils.js new file mode 100644 index 000000000..66fe9b35f --- /dev/null +++ b/src/lib/utils.js @@ -0,0 +1,4 @@ +/** @type {string} name */ +export function get_depth(name) { + return name.split('/').length - 1; +} diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte index bcdc1a287..ecc8d4d57 100644 --- a/src/routes/+error.svelte +++ b/src/routes/+error.svelte @@ -1,5 +1,6 @@ - {data.section.chapter.title} / {data.section.title} • Svelte Tutorial + {data.exercise.chapter.title} / {data.exercise.title} • Svelte Tutorial -{#if modal_text} - (modal_text = '')}> - - -{/if} - -
    +
    { - select(/** @type {import('$lib/types').FileStub} */ (data.section.a[e.detail.file])); + selected.set( + /** @type {import('$lib/types').FileStub} */ (data.exercise.a[e.detail.file]) + ); }} />
    -
    +
    @@ -602,27 +462,10 @@ color: white; } - .navigator button.completed { + .navigator button:not(:disabled).completed { background: var(--second); } - .filetree { - flex: 1; - overflow-y: auto; - overflow-x: hidden; - padding: 2rem; - } - - .filetree::before { - content: ''; - position: absolute; - width: 0; - height: 100%; - top: 0; - right: 0; - border-right: 1px solid var(--border-color); - } - .preview { display: flex; flex-direction: column; @@ -650,19 +493,4 @@ .hidden { display: none; } - - .modal-contents p { - white-space: pre-line; - } - - .modal-contents button { - display: block; - background: var(--prime); - color: white; - padding: 1rem; - width: 10em; - margin: 1em 0 0 0; - border-radius: var(--border-r); - line-height: 1; - } diff --git a/src/routes/tutorial/[slug]/File.svelte b/src/routes/tutorial/[slug]/File.svelte deleted file mode 100644 index 507a5772a..000000000 --- a/src/routes/tutorial/[slug]/File.svelte +++ /dev/null @@ -1,186 +0,0 @@ - - -{#if !editing} -
    -
    - -
    - {#if can_create && can_remove} -
    -
    -{:else} - - -{/if} - - diff --git a/src/routes/tutorial/[slug]/Folder.svelte b/src/routes/tutorial/[slug]/Folder.svelte deleted file mode 100644 index 4a03d49fa..000000000 --- a/src/routes/tutorial/[slug]/Folder.svelte +++ /dev/null @@ -1,302 +0,0 @@ - - -{#if state !== 'edit_folder'} -
    -
    - -
    - {#if can_create} -
    -
    -{/if} - -{#if state === 'edit_folder'} - - -{/if} - -{#if expanded} -
      - {#if state === 'add_file' || state === 'add_folder'} - - - {/if} - {#each child_directories as directory} -
    • - -
    • - {/each} - - {#each child_files as file} -
    • - -
    • - {/each} -
    -{/if} - - diff --git a/src/routes/tutorial/[slug]/Menu.svelte b/src/routes/tutorial/[slug]/Menu.svelte index 45fce7892..b009ffecf 100644 --- a/src/routes/tutorial/[slug]/Menu.svelte +++ b/src/routes/tutorial/[slug]/Menu.svelte @@ -10,14 +10,19 @@ /** @type {import('$lib/types').PartStub[]}*/ export let index; - /** @type {import('$lib/types').Section} */ + /** @type {import('$lib/types').Exercise} */ export let current; let is_open = false; let search = ''; - let expanded_part = current.part.slug; - let expanded_chapter = current.chapter.slug; + let expanded_part = ''; + let expanded_chapter = ''; + + $: if (is_open) { + expanded_part = current.part.slug; + expanded_chapter = current.chapter.slug; + } const duration = browser && matchMedia('(prefers-reduced-motion: reduce)').matches ? 0 : 200; @@ -29,15 +34,15 @@ .map((chapter, i) => ({ ...chapter, label: String.fromCharCode(97 + i), - first: chapter.sections[0].slug, - sections: chapter.sections.filter((section) => regex.test(section.title)) + first: chapter.exercises[0].slug, + exercises: chapter.exercises.filter((exercise) => regex.test(exercise.title)) })) - .filter((chapter) => chapter.sections.length > 0 || regex.test(chapter.title)); + .filter((chapter) => chapter.exercises.length > 0 || regex.test(chapter.title)); return { ...part, label: i + 1, - first: part.chapters[0].sections[0].slug, + first: part.chapters[0].exercises[0].slug, chapters }; }) @@ -78,7 +83,7 @@
    -