From 18f00434e1faa4c5853f312a31cdc918a88ab0ce Mon Sep 17 00:00:00 2001 From: Vincent Liao Date: Mon, 21 Mar 2022 13:03:54 +0700 Subject: [PATCH] to sveltekit --- .svelte-kit/generated/client-manifest.js | 11 + .svelte-kit/generated/client-matchers.js | 1 + .svelte-kit/generated/root.svelte | 56 + .svelte-kit/runtime/app/env.js | 20 + .svelte-kit/runtime/app/navigation.js | 24 + .svelte-kit/runtime/app/paths.js | 1 + .svelte-kit/runtime/app/stores.js | 97 + .svelte-kit/runtime/client/singletons.js | 13 + .svelte-kit/runtime/client/start.js | 1650 ++++++++++ .svelte-kit/runtime/components/error.svelte | 29 + .svelte-kit/runtime/components/layout.svelte | 1 + .svelte-kit/runtime/env.js | 8 + .svelte-kit/runtime/paths.js | 13 + .svelte-kit/runtime/server/index.js | 2845 ++++++++++++++++++ .svelte-kit/tsconfig.json | 43 + .svelte-kit/types/src/routes/__layout.d.ts | 7 + .svelte-kit/types/src/routes/index.d.ts | 7 + README.md | 42 +- jsconfig.json | 3 + package.json | 55 +- postcss.config.cjs | 13 + postcss.config.js | 6 - public/app.css | 583 ---- public/global.css | 0 public/index.html | 19 - public/tailwind.css | 3 - rollup.config.js | 76 - scripts/setupTypeScript.js | 121 - src/Activity.svelte | 41 - src/App.svelte | 160 - src/Count.svelte | 20 - src/Dots.svelte | 6 - src/Kind.svelte | 37 - src/Relay.svelte | 21 - src/Tweet.svelte | 24 - src/app.css | 4 + src/app.d.ts | 10 + src/app.html | 13 + src/main.js | 10 - src/routes/__layout.svelte | 5 + src/routes/index.svelte | 4 + static/favicon.png | Bin 0 -> 1571 bytes svelte.config.js | 17 + tailwind.config.cjs | 11 + tailwind.config.js | 7 - yarn.lock | 1340 ++++++--- 46 files changed, 5813 insertions(+), 1664 deletions(-) create mode 100644 .svelte-kit/generated/client-manifest.js create mode 100644 .svelte-kit/generated/client-matchers.js create mode 100644 .svelte-kit/generated/root.svelte create mode 100644 .svelte-kit/runtime/app/env.js create mode 100644 .svelte-kit/runtime/app/navigation.js create mode 100644 .svelte-kit/runtime/app/paths.js create mode 100644 .svelte-kit/runtime/app/stores.js create mode 100644 .svelte-kit/runtime/client/singletons.js create mode 100644 .svelte-kit/runtime/client/start.js create mode 100644 .svelte-kit/runtime/components/error.svelte create mode 100644 .svelte-kit/runtime/components/layout.svelte create mode 100644 .svelte-kit/runtime/env.js create mode 100644 .svelte-kit/runtime/paths.js create mode 100644 .svelte-kit/runtime/server/index.js create mode 100644 .svelte-kit/tsconfig.json create mode 100644 .svelte-kit/types/src/routes/__layout.d.ts create mode 100644 .svelte-kit/types/src/routes/index.d.ts create mode 100644 jsconfig.json create mode 100644 postcss.config.cjs delete mode 100644 postcss.config.js delete mode 100644 public/app.css delete mode 100644 public/global.css delete mode 100644 public/index.html delete mode 100644 public/tailwind.css delete mode 100644 rollup.config.js delete mode 100644 scripts/setupTypeScript.js delete mode 100644 src/Activity.svelte delete mode 100644 src/App.svelte delete mode 100644 src/Count.svelte delete mode 100644 src/Dots.svelte delete mode 100644 src/Kind.svelte delete mode 100644 src/Relay.svelte delete mode 100644 src/Tweet.svelte create mode 100644 src/app.css create mode 100644 src/app.d.ts create mode 100644 src/app.html delete mode 100644 src/main.js create mode 100644 src/routes/__layout.svelte create mode 100644 src/routes/index.svelte create mode 100644 static/favicon.png create mode 100644 svelte.config.js create mode 100644 tailwind.config.cjs delete mode 100644 tailwind.config.js diff --git a/.svelte-kit/generated/client-manifest.js b/.svelte-kit/generated/client-manifest.js new file mode 100644 index 0000000..8635adf --- /dev/null +++ b/.svelte-kit/generated/client-manifest.js @@ -0,0 +1,11 @@ +export { matchers } from './client-matchers.js'; + +export const components = [ + () => import("../../src/routes/__layout.svelte"), + () => import("../runtime/components/error.svelte"), + () => import("../../src/routes/index.svelte") +]; + +export const dictionary = { + "": [[0, 2], [1]] +}; \ No newline at end of file diff --git a/.svelte-kit/generated/client-matchers.js b/.svelte-kit/generated/client-matchers.js new file mode 100644 index 0000000..f6bd30a --- /dev/null +++ b/.svelte-kit/generated/client-matchers.js @@ -0,0 +1 @@ +export const matchers = {}; \ No newline at end of file diff --git a/.svelte-kit/generated/root.svelte b/.svelte-kit/generated/root.svelte new file mode 100644 index 0000000..d07e155 --- /dev/null +++ b/.svelte-kit/generated/root.svelte @@ -0,0 +1,56 @@ + + + +{#if components[1]} + + {#if components[2]} + + + + {:else} + + {/if} + +{:else} + +{/if} + +{#if mounted} +
+ {#if navigated} + {title} + {/if} +
+{/if} \ No newline at end of file diff --git a/.svelte-kit/runtime/app/env.js b/.svelte-kit/runtime/app/env.js new file mode 100644 index 0000000..d2299cb --- /dev/null +++ b/.svelte-kit/runtime/app/env.js @@ -0,0 +1,20 @@ +export { prerendering } from '../env.js'; + +/** + * @type {import('$app/env').browser} + */ +const browser = !import.meta.env.SSR; +/** + * @type {import('$app/env').dev} + */ +const dev = !!import.meta.env.DEV; +/** + * @type {import('$app/env').mode} + */ +const mode = import.meta.env.MODE; +/** + * @type {import('$app/env').amp} + */ +const amp = !!import.meta.env.VITE_SVELTEKIT_AMP; + +export { amp, browser, dev, mode }; diff --git a/.svelte-kit/runtime/app/navigation.js b/.svelte-kit/runtime/app/navigation.js new file mode 100644 index 0000000..14f1f9a --- /dev/null +++ b/.svelte-kit/runtime/app/navigation.js @@ -0,0 +1,24 @@ +import { client } from '../client/singletons.js'; + +/** + * @param {string} name + */ +function guard(name) { + return () => { + throw new Error(`Cannot call ${name}(...) on the server`); + }; +} + +const ssr = import.meta.env.SSR; + +const disableScrollHandling = ssr + ? guard('disableScrollHandling') + : client.disable_scroll_handling; +const goto = ssr ? guard('goto') : client.goto; +const invalidate = ssr ? guard('invalidate') : client.invalidate; +const prefetch = ssr ? guard('prefetch') : client.prefetch; +const prefetchRoutes = ssr ? guard('prefetchRoutes') : client.prefetch_routes; +const beforeNavigate = ssr ? () => {} : client.before_navigate; +const afterNavigate = ssr ? () => {} : client.after_navigate; + +export { afterNavigate, beforeNavigate, disableScrollHandling, goto, invalidate, prefetch, prefetchRoutes }; diff --git a/.svelte-kit/runtime/app/paths.js b/.svelte-kit/runtime/app/paths.js new file mode 100644 index 0000000..7ed4fff --- /dev/null +++ b/.svelte-kit/runtime/app/paths.js @@ -0,0 +1 @@ +export { assets, base } from '../paths.js'; diff --git a/.svelte-kit/runtime/app/stores.js b/.svelte-kit/runtime/app/stores.js new file mode 100644 index 0000000..9c66bab --- /dev/null +++ b/.svelte-kit/runtime/app/stores.js @@ -0,0 +1,97 @@ +import { getContext } from 'svelte'; +import { browser } from './env.js'; +import '../env.js'; + +// TODO remove this (for 1.0? after 1.0?) +let warned = false; +function stores() { + if (!warned) { + console.error('stores() is deprecated; use getStores() instead'); + warned = true; + } + return getStores(); +} + +/** + * @type {import('$app/stores').getStores} + */ +const getStores = () => { + const stores = getContext('__svelte__'); + + return { + page: { + subscribe: stores.page.subscribe + }, + navigating: { + subscribe: stores.navigating.subscribe + }, + // TODO remove this (for 1.0? after 1.0?) + // @ts-expect-error - deprecated, not part of type definitions, but still callable + get preloading() { + console.error('stores.preloading is deprecated; use stores.navigating instead'); + return { + subscribe: stores.navigating.subscribe + }; + }, + session: stores.session, + updated: stores.updated + }; +}; + +/** @type {typeof import('$app/stores').page} */ +const page = { + /** @param {(value: any) => void} fn */ + subscribe(fn) { + const store = getStores().page; + return store.subscribe(fn); + } +}; + +/** @type {typeof import('$app/stores').navigating} */ +const navigating = { + subscribe(fn) { + const store = getStores().navigating; + return store.subscribe(fn); + } +}; + +/** @param {string} verb */ +const throw_error = (verb) => { + throw new Error( + browser + ? `Cannot ${verb} session store before subscribing` + : `Can only ${verb} session store in browser` + ); +}; + +/** @type {typeof import('$app/stores').session} */ +const session = { + subscribe(fn) { + const store = getStores().session; + + if (browser) { + session.set = store.set; + session.update = store.update; + } + + return store.subscribe(fn); + }, + set: () => throw_error('set'), + update: () => throw_error('update') +}; + +/** @type {typeof import('$app/stores').updated} */ +const updated = { + subscribe(fn) { + const store = getStores().updated; + + if (browser) { + updated.check = store.check; + } + + return store.subscribe(fn); + }, + check: () => throw_error('check') +}; + +export { getStores, navigating, page, session, stores, updated }; diff --git a/.svelte-kit/runtime/client/singletons.js b/.svelte-kit/runtime/client/singletons.js new file mode 100644 index 0000000..cd43f65 --- /dev/null +++ b/.svelte-kit/runtime/client/singletons.js @@ -0,0 +1,13 @@ +/** @type {import('./types').Client} */ +let client; + +/** + * @param {{ + * client: import('./types').Client; + * }} opts + */ +function init(opts) { + client = opts.client; +} + +export { client, init }; diff --git a/.svelte-kit/runtime/client/start.js b/.svelte-kit/runtime/client/start.js new file mode 100644 index 0000000..807e1fc --- /dev/null +++ b/.svelte-kit/runtime/client/start.js @@ -0,0 +1,1650 @@ +import { onMount, tick } from 'svelte'; +import { writable } from 'svelte/store'; +import { assets, set_paths } from '../paths.js'; +import Root from '__GENERATED__/root.svelte'; +import { components, dictionary, matchers } from '__GENERATED__/client-manifest.js'; +import { init } from './singletons.js'; + +/** + * @param {unknown} err + * @return {Error} + */ +function coalesce_to_error(err) { + return err instanceof Error || + (err && /** @type {any} */ (err).name && /** @type {any} */ (err).message) + ? /** @type {Error} */ (err) + : new Error(JSON.stringify(err)); +} + +/** + * @param {import('types').LoadOutput} loaded + * @returns {import('types').NormalizedLoadOutput} + */ +function normalize(loaded) { + const has_error_status = + loaded.status && loaded.status >= 400 && loaded.status <= 599 && !loaded.redirect; + if (loaded.error || has_error_status) { + const status = loaded.status; + + if (!loaded.error && has_error_status) { + return { + status: status || 500, + error: new Error() + }; + } + + const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error; + + if (!(error instanceof Error)) { + return { + status: 500, + error: new Error( + `"error" property returned from load() must be a string or instance of Error, received type "${typeof error}"` + ) + }; + } + + if (!status || status < 400 || status > 599) { + console.warn('"error" returned from load() without a valid status code — defaulting to 500'); + return { status: 500, error }; + } + + return { status, error }; + } + + if (loaded.redirect) { + if (!loaded.status || Math.floor(loaded.status / 100) !== 3) { + return { + status: 500, + error: new Error( + '"redirect" property returned from load() must be accompanied by a 3xx status code' + ) + }; + } + + if (typeof loaded.redirect !== 'string') { + return { + status: 500, + error: new Error('"redirect" property returned from load() must be a string') + }; + } + } + + // TODO remove before 1.0 + if (/** @type {any} */ (loaded).context) { + throw new Error( + 'You are returning "context" from a load function. ' + + '"context" was renamed to "stuff", please adjust your code accordingly.' + ); + } + + return /** @type {import('types').NormalizedLoadOutput} */ (loaded); +} + +/** + * @param {string} path + * @param {import('types').TrailingSlash} trailing_slash + */ +function normalize_path(path, trailing_slash) { + if (path === '/' || trailing_slash === 'ignore') return path; + + if (trailing_slash === 'never') { + return path.endsWith('/') ? path.slice(0, -1) : path; + } else if (trailing_slash === 'always' && /\/[^./]+$/.test(path)) { + return path + '/'; + } + + return path; +} + +/** + * Hash using djb2 + * @param {import('types').StrictBody} value + */ +function hash(value) { + let hash = 5381; + let i = value.length; + + if (typeof value === 'string') { + while (i) hash = (hash * 33) ^ value.charCodeAt(--i); + } else { + while (i) hash = (hash * 33) ^ value[--i]; + } + + return (hash >>> 0).toString(36); +} + +/** @param {HTMLDocument} doc */ +function get_base_uri(doc) { + let baseURI = doc.baseURI; + + if (!baseURI) { + const baseTags = doc.getElementsByTagName('base'); + baseURI = baseTags.length ? baseTags[0].href : doc.URL; + } + + return baseURI; +} + +function scroll_state() { + return { + x: pageXOffset, + y: pageYOffset + }; +} + +/** @param {Event} event */ +function find_anchor(event) { + const node = event + .composedPath() + .find((e) => e instanceof Node && e.nodeName.toUpperCase() === 'A'); // SVG elements have a lowercase name + return /** @type {HTMLAnchorElement | SVGAElement | undefined} */ (node); +} + +/** @param {HTMLAnchorElement | SVGAElement} node */ +function get_href(node) { + return node instanceof SVGAElement + ? new URL(node.href.baseVal, document.baseURI) + : new URL(node.href); +} + +/** @param {any} value */ +function notifiable_store(value) { + const store = writable(value); + let ready = true; + + function notify() { + ready = true; + store.update((val) => val); + } + + /** @param {any} new_value */ + function set(new_value) { + ready = false; + store.set(new_value); + } + + /** @param {(value: any) => void} run */ + function subscribe(run) { + /** @type {any} */ + let old_value; + return store.subscribe((new_value) => { + if (old_value === undefined || (ready && new_value !== old_value)) { + run((old_value = new_value)); + } + }); + } + + return { notify, set, subscribe }; +} + +function create_updated_store() { + const { set, subscribe } = writable(false); + + const interval = +( + /** @type {string} */ (import.meta.env.VITE_SVELTEKIT_APP_VERSION_POLL_INTERVAL) + ); + const initial = import.meta.env.VITE_SVELTEKIT_APP_VERSION; + + /** @type {NodeJS.Timeout} */ + let timeout; + + async function check() { + if (import.meta.env.DEV || import.meta.env.SSR) return false; + + clearTimeout(timeout); + + if (interval) timeout = setTimeout(check, interval); + + const file = import.meta.env.VITE_SVELTEKIT_APP_VERSION_FILE; + + const res = await fetch(`${assets}/${file}`, { + headers: { + pragma: 'no-cache', + 'cache-control': 'no-cache' + } + }); + + if (res.ok) { + const { version } = await res.json(); + const updated = version !== initial; + + if (updated) { + set(true); + clearTimeout(timeout); + } + + return updated; + } else { + throw new Error(`Version check failed: ${res.status}`); + } + } + + if (interval) timeout = setTimeout(check, interval); + + return { + subscribe, + check + }; +} + +/** + * @param {RequestInfo} resource + * @param {RequestInit} [opts] + */ +function initial_fetch(resource, opts) { + const url = JSON.stringify(typeof resource === 'string' ? resource : resource.url); + + let selector = `script[sveltekit\\:data-type="data"][sveltekit\\:data-url=${url}]`; + + if (opts && typeof opts.body === 'string') { + selector += `[sveltekit\\:data-body="${hash(opts.body)}"]`; + } + + const script = document.querySelector(selector); + if (script && script.textContent) { + const { body, ...init } = JSON.parse(script.textContent); + return Promise.resolve(new Response(body, init)); + } + + return fetch(resource, opts); +} + +const param_pattern = /^(\.\.\.)?(\w+)(?:=(\w+))?$/; + +/** @param {string} id */ +function parse_route_id(id) { + /** @type {string[]} */ + const names = []; + + /** @type {string[]} */ + const types = []; + + // `/foo` should get an optional trailing slash, `/foo.json` should not + // const add_trailing_slash = !/\.[a-z]+$/.test(key); + let add_trailing_slash = true; + + const pattern = + id === '' + ? /^\/$/ + : new RegExp( + `^${decodeURIComponent(id) + .split('/') + .map((segment, i, segments) => { + // special case — /[...rest]/ could contain zero segments + const match = /^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(segment); + if (match) { + names.push(match[1]); + types.push(match[2]); + return '(?:/(.*))?'; + } + + const is_last = i === segments.length - 1; + + return ( + '/' + + segment + .split(/\[(.+?)\]/) + .map((content, i) => { + if (i % 2) { + const [, rest, name, type] = /** @type {RegExpMatchArray} */ ( + param_pattern.exec(content) + ); + names.push(name); + types.push(type); + return rest ? '(.*?)' : '([^/]+?)'; + } + + if (is_last && content.includes('.')) add_trailing_slash = false; + + return ( + content // allow users to specify characters on the file system in an encoded manner + .normalize() + // We use [ and ] to denote parameters, so users must encode these on the file + // system to match against them. We don't decode all characters since others + // can already be epressed and so that '%' can be easily used directly in filenames + .replace(/%5[Bb]/g, '[') + .replace(/%5[Dd]/g, ']') + // '#', '/', and '?' can only appear in URL path segments in an encoded manner. + // They will not be touched by decodeURI so need to be encoded here, so + // that we can match against them. + // We skip '/' since you can't create a file with it on any OS + .replace(/#/g, '%23') + .replace(/\?/g, '%3F') + // escape characters that have special meaning in regex + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ); // TODO handle encoding + }) + .join('') + ); + }) + .join('')}${add_trailing_slash ? '/?' : ''}$` + ); + + return { pattern, names, types }; +} + +/** + * @param {RegExpMatchArray} match + * @param {string[]} names + * @param {string[]} types + * @param {Record} matchers + */ +function exec(match, names, types, matchers) { + /** @type {Record} */ + const params = {}; + + for (let i = 0; i < names.length; i += 1) { + const name = names[i]; + const type = types[i]; + const value = match[i + 1] || ''; + + if (type) { + const matcher = matchers[type]; + if (!matcher) throw new Error(`Missing "${type}" param matcher`); // TODO do this ahead of time? + + if (!matcher(value)) return; + } + + params[name] = value; + } + + return params; +} + +/** + * @param {import('types').CSRComponentLoader[]} components + * @param {Record} dictionary + * @param {Record boolean>} matchers + * @returns {import('types').CSRRoute[]} + */ +function parse(components, dictionary, matchers) { + const routes = Object.entries(dictionary).map(([id, [a, b, has_shadow]]) => { + const { pattern, names, types } = parse_route_id(id); + + return { + id, + /** @param {string} path */ + exec: (path) => { + const match = pattern.exec(path); + if (match) return exec(match, names, types, matchers); + }, + a: a.map((n) => components[n]), + b: b.map((n) => components[n]), + has_shadow: !!has_shadow + }; + }); + + return routes; +} + +const SCROLL_KEY = 'sveltekit:scroll'; +const INDEX_KEY = 'sveltekit:index'; + +const routes = parse(components, dictionary, matchers); + +// we import the root layout/error components eagerly, so that +// connectivity errors after initialisation don't nuke the app +const default_layout = components[0](); +const default_error = components[1](); + +// We track the scroll position associated with each history entry in sessionStorage, +// rather than on history.state itself, because when navigation is driven by +// popstate it's too late to update the scroll position associated with the +// state we're navigating from + +/** @typedef {{ x: number, y: number }} ScrollPosition */ +/** @type {Record} */ +let scroll_positions = {}; +try { + scroll_positions = JSON.parse(sessionStorage[SCROLL_KEY]); +} catch { + // do nothing +} + +/** @param {number} index */ +function update_scroll_positions(index) { + scroll_positions[index] = scroll_state(); +} + +/** + * @param {{ + * target: Element; + * session: App.Session; + * base: string; + * trailing_slash: import('types').TrailingSlash; + * }} opts + * @returns {import('./types').Client} + */ +function create_client({ target, session, base, trailing_slash }) { + /** @type {Map} */ + const cache = new Map(); + + /** @type {Set} */ + const invalidated = new Set(); + + const stores = { + url: notifiable_store({}), + page: notifiable_store({}), + navigating: writable(/** @type {import('types').Navigation | null} */ (null)), + session: writable(session), + updated: create_updated_store() + }; + + /** @type {{id: string | null, promise: Promise | null}} */ + const load_cache = { + id: null, + promise: null + }; + + const callbacks = { + /** @type {Array<(opts: { from: URL, to: URL | null, cancel: () => void }) => void>} */ + before_navigate: [], + + /** @type {Array<(opts: { from: URL | null, to: URL }) => void>} */ + after_navigate: [] + }; + + /** @type {import('./types').NavigationState} */ + let current = { + // @ts-ignore - we need the initial value to be null + url: null, + session_id: 0, + branch: [] + }; + + let started = false; + let autoscroll = true; + let updating = false; + let session_id = 1; + + /** @type {Promise | null} */ + let invalidating = null; + + /** @type {import('svelte').SvelteComponent} */ + let root; + + /** @type {App.Session} */ + let $session; + + let ready = false; + stores.session.subscribe(async (value) => { + $session = value; + + if (!ready) return; + session_id += 1; + + update(new URL(location.href), [], true); + }); + ready = true; + + /** Keeps tracks of multiple navigations caused by redirects during rendering */ + let navigating = 0; + + let router_enabled = true; + + // keeping track of the history index in order to prevent popstate navigation events if needed + let current_history_index = history.state?.[INDEX_KEY] ?? 0; + + if (current_history_index === 0) { + // create initial history entry, so we can return here + history.replaceState({ ...history.state, [INDEX_KEY]: 0 }, '', location.href); + } + + // if we reload the page, or Cmd-Shift-T back to it, + // recover scroll position + const scroll = scroll_positions[current_history_index]; + if (scroll) scrollTo(scroll.x, scroll.y); + + let hash_navigating = false; + + /** @type {import('types').Page} */ + let page; + + /** @type {{}} */ + let token; + + /** @type {{}} */ + let navigating_token; + + /** + * @param {string} href + * @param {{ noscroll?: boolean; replaceState?: boolean; keepfocus?: boolean; state?: any }} opts + * @param {string[]} redirect_chain + */ + async function goto( + href, + { noscroll = false, replaceState = false, keepfocus = false, state = {} }, + redirect_chain + ) { + const url = new URL(href, get_base_uri(document)); + + if (router_enabled) { + return navigate({ + url, + scroll: noscroll ? scroll_state() : null, + keepfocus, + redirect_chain, + details: { + state, + replaceState + }, + accepted: () => {}, + blocked: () => {} + }); + } + + await native_navigation(url); + } + + /** @param {URL} url */ + async function prefetch(url) { + const intent = get_navigation_intent(url); + + if (!intent) { + throw new Error('Attempted to prefetch a URL that does not belong to this app'); + } + + load_cache.promise = load_route(intent, false); + load_cache.id = intent.id; + + return load_cache.promise; + } + + /** + * @param {URL} url + * @param {string[]} redirect_chain + * @param {boolean} no_cache + * @param {{hash?: string, scroll: { x: number, y: number } | null, keepfocus: boolean, details: { replaceState: boolean, state: any } | null}} [opts] + */ + async function update(url, redirect_chain, no_cache, opts) { + const intent = get_navigation_intent(url); + + const current_token = (token = {}); + let navigation_result = intent && (await load_route(intent, no_cache)); + + if (!navigation_result && url.pathname === location.pathname) { + // this could happen in SPA fallback mode if the user navigated to + // `/non-existent-page`. if we fall back to reloading the page, it + // will create an infinite loop. so whereas we normally handle + // unknown routes by going to the server, in this special case + // we render a client-side error page instead + navigation_result = await load_root_error_page({ + status: 404, + error: new Error(`Not found: ${url.pathname}`), + url, + routeId: null + }); + } + + if (!navigation_result) { + await native_navigation(url); + return; // unnecessary, but TypeScript prefers it this way + } + + // abort if user navigated during update + if (token !== current_token) return; + + invalidated.clear(); + + if (navigation_result.redirect) { + if (redirect_chain.length > 10 || redirect_chain.includes(url.pathname)) { + navigation_result = await load_root_error_page({ + status: 500, + error: new Error('Redirect loop'), + url, + routeId: null + }); + } else { + if (router_enabled) { + goto(new URL(navigation_result.redirect, url).href, {}, [ + ...redirect_chain, + url.pathname + ]); + } else { + await native_navigation(new URL(navigation_result.redirect, location.href)); + } + + return; + } + } else if (navigation_result.props?.page?.status >= 400) { + const updated = await stores.updated.check(); + if (updated) { + await native_navigation(url); + } + } + + updating = true; + + if (opts && opts.details) { + const { details } = opts; + const change = details.replaceState ? 0 : 1; + details.state[INDEX_KEY] = current_history_index += change; + history[details.replaceState ? 'replaceState' : 'pushState'](details.state, '', url); + } + + if (started) { + current = navigation_result.state; + + root.$set(navigation_result.props); + } else { + initialize(navigation_result); + } + + // opts must be passed if we're navigating + if (opts) { + const { scroll, keepfocus } = opts; + + if (!keepfocus) { + // Reset page selection and focus + // We try to mimic browsers' behaviour as closely as possible by targeting the + // first scrollable region, but unfortunately it's not a perfect match — e.g. + // shift-tabbing won't immediately cycle up from the end of the page on Chromium + // See https://html.spec.whatwg.org/multipage/interaction.html#get-the-focusable-area + const root = document.body; + const tabindex = root.getAttribute('tabindex'); + + getSelection()?.removeAllRanges(); + root.tabIndex = -1; + root.focus(); + + // restore `tabindex` as to prevent `root` from stealing input from elements + if (tabindex !== null) { + root.setAttribute('tabindex', tabindex); + } else { + root.removeAttribute('tabindex'); + } + } + + // need to render the DOM before we can scroll to the rendered elements + await tick(); + + if (autoscroll) { + const deep_linked = url.hash && document.getElementById(url.hash.slice(1)); + if (scroll) { + scrollTo(scroll.x, scroll.y); + } else if (deep_linked) { + // Here we use `scrollIntoView` on the element instead of `scrollTo` + // because it natively supports the `scroll-margin` and `scroll-behavior` + // CSS properties. + deep_linked.scrollIntoView(); + } else { + scrollTo(0, 0); + } + } + } else { + // in this case we're simply invalidating + await tick(); + } + + load_cache.promise = null; + load_cache.id = null; + autoscroll = true; + updating = false; + + if (navigation_result.props.page) { + page = navigation_result.props.page; + } + + const leaf_node = navigation_result.state.branch[navigation_result.state.branch.length - 1]; + router_enabled = leaf_node?.module.router !== false; + } + + /** @param {import('./types').NavigationResult} result */ + function initialize(result) { + current = result.state; + + const style = document.querySelector('style[data-svelte]'); + if (style) style.remove(); + + page = result.props.page; + + root = new Root({ + target, + props: { ...result.props, stores }, + hydrate: true + }); + + started = true; + + if (router_enabled) { + const navigation = { from: null, to: new URL(location.href) }; + callbacks.after_navigate.forEach((fn) => fn(navigation)); + } + } + + /** + * + * @param {{ + * url: URL; + * params: Record; + * stuff: Record; + * branch: Array; + * status: number; + * error?: Error; + * routeId: string | null; + * }} opts + */ + async function get_navigation_result_from_branch({ + url, + params, + stuff, + branch, + status, + error, + routeId + }) { + const filtered = /** @type {import('./types').BranchNode[] } */ (branch.filter(Boolean)); + const redirect = filtered.find((f) => f.loaded?.redirect); + + /** @type {import('./types').NavigationResult} */ + const result = { + redirect: redirect?.loaded?.redirect, + state: { + url, + params, + branch, + session_id + }, + props: { + components: filtered.map((node) => node.module.default) + } + }; + + for (let i = 0; i < filtered.length; i += 1) { + const loaded = filtered[i].loaded; + result.props[`props_${i}`] = loaded ? await loaded.props : null; + } + + if (!current.url || url.href !== current.url.href) { + result.props.page = { error, params, routeId, status, stuff, url }; + + // TODO remove this for 1.0 + /** + * @param {string} property + * @param {string} replacement + */ + const print_error = (property, replacement) => { + Object.defineProperty(result.props.page, property, { + get: () => { + throw new Error(`$page.${property} has been replaced by $page.url.${replacement}`); + } + }); + }; + + print_error('origin', 'origin'); + print_error('path', 'pathname'); + print_error('query', 'searchParams'); + } + + const leaf = filtered[filtered.length - 1]; + const maxage = leaf.loaded && leaf.loaded.maxage; + + if (maxage) { + const key = url.pathname + url.search; // omit hash + let ready = false; + + const clear = () => { + if (cache.get(key) === result) { + cache.delete(key); + } + + unsubscribe(); + clearTimeout(timeout); + }; + + const timeout = setTimeout(clear, maxage * 1000); + + const unsubscribe = stores.session.subscribe(() => { + if (ready) clear(); + }); + + ready = true; + + cache.set(key, result); + } + + return result; + } + + /** + * @param {{ + * status?: number; + * error?: Error; + * module: import('types').CSRComponent; + * url: URL; + * params: Record; + * stuff: Record; + * props?: Record; + * routeId: string | null; + * }} options + */ + async function load_node({ status, error, module, url, params, stuff, props, routeId }) { + /** @type {import('./types').BranchNode} */ + const node = { + module, + uses: { + params: new Set(), + url: false, + session: false, + stuff: false, + dependencies: new Set() + }, + loaded: null, + stuff + }; + + if (props) { + // shadow endpoint props means we need to mark this URL as a dependency of itself + node.uses.dependencies.add(url.href); + } + + /** @type {Record} */ + const uses_params = {}; + for (const key in params) { + Object.defineProperty(uses_params, key, { + get() { + node.uses.params.add(key); + return params[key]; + }, + enumerable: true + }); + } + + const session = $session; + + if (module.load) { + /** @type {import('types').LoadInput | import('types').ErrorLoadInput} */ + const load_input = { + routeId, + params: uses_params, + props: props || {}, + get url() { + node.uses.url = true; + return url; + }, + get session() { + node.uses.session = true; + return session; + }, + get stuff() { + node.uses.stuff = true; + return { ...stuff }; + }, + fetch(resource, info) { + const requested = typeof resource === 'string' ? resource : resource.url; + const { href } = new URL(requested, url); + node.uses.dependencies.add(href); + + return started ? fetch(resource, info) : initial_fetch(resource, info); + } + }; + + if (import.meta.env.DEV) { + // TODO remove this for 1.0 + Object.defineProperty(load_input, 'page', { + get: () => { + throw new Error('`page` in `load` functions has been replaced by `url` and `params`'); + } + }); + } + + if (error) { + /** @type {import('types').ErrorLoadInput} */ (load_input).status = status; + /** @type {import('types').ErrorLoadInput} */ (load_input).error = error; + } + + const loaded = await module.load.call(null, load_input); + + if (!loaded) { + throw new Error('load function must return a value'); + } + + node.loaded = normalize(loaded); + if (node.loaded.stuff) node.stuff = node.loaded.stuff; + } else if (props) { + node.loaded = normalize({ props }); + } + + return node; + } + + /** + * @param {import('./types').NavigationIntent} intent + * @param {boolean} no_cache + */ + async function load_route({ id, url, params, route }, no_cache) { + if (load_cache.id === id && load_cache.promise) { + return load_cache.promise; + } + + if (!no_cache) { + const cached = cache.get(id); + if (cached) return cached; + } + + const { a, b, has_shadow } = route; + + const changed = current.url && { + url: id !== current.url.pathname + current.url.search, + params: Object.keys(params).filter((key) => current.params[key] !== params[key]), + session: session_id !== current.session_id + }; + + /** @type {Array} */ + let branch = []; + + /** @type {Record} */ + let stuff = {}; + let stuff_changed = false; + + /** @type {number | undefined} */ + let status = 200; + + /** @type {Error | undefined} */ + let error; + + // preload modules + a.forEach((loader) => loader()); + + load: for (let i = 0; i < a.length; i += 1) { + /** @type {import('./types').BranchNode | undefined} */ + let node; + + try { + if (!a[i]) continue; + + const module = await a[i](); + const previous = current.branch[i]; + + const changed_since_last_render = + !previous || + module !== previous.module || + (changed.url && previous.uses.url) || + changed.params.some((param) => previous.uses.params.has(param)) || + (changed.session && previous.uses.session) || + Array.from(previous.uses.dependencies).some((dep) => invalidated.has(dep)) || + (stuff_changed && previous.uses.stuff); + + if (changed_since_last_render) { + /** @type {Record} */ + let props = {}; + + const is_shadow_page = has_shadow && i === a.length - 1; + + if (is_shadow_page) { + const res = await fetch( + `${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}`, + { + headers: { + 'x-sveltekit-load': 'true' + } + } + ); + + if (res.ok) { + const redirect = res.headers.get('x-sveltekit-location'); + + if (redirect) { + return { + redirect, + props: {}, + state: current + }; + } + + props = res.status === 204 ? {} : await res.json(); + } else { + status = res.status; + error = new Error('Failed to load data'); + } + } + + if (!error) { + node = await load_node({ + module, + url, + params, + props, + stuff, + routeId: route.id + }); + } + + if (node) { + if (is_shadow_page) { + node.uses.url = true; + } + + if (node.loaded) { + // TODO remove for 1.0 + // @ts-expect-error + if (node.loaded.fallthrough) { + throw new Error( + 'fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-validation' + ); + } + + if (node.loaded.error) { + status = node.loaded.status; + error = node.loaded.error; + } + + if (node.loaded.redirect) { + return { + redirect: node.loaded.redirect, + props: {}, + state: current + }; + } + + if (node.loaded.stuff) { + stuff_changed = true; + } + } + } + } else { + node = previous; + } + } catch (e) { + status = 500; + error = coalesce_to_error(e); + } + + if (error) { + while (i--) { + if (b[i]) { + let error_loaded; + + /** @type {import('./types').BranchNode | undefined} */ + let node_loaded; + let j = i; + while (!(node_loaded = branch[j])) { + j -= 1; + } + + try { + error_loaded = await load_node({ + status, + error, + module: await b[i](), + url, + params, + stuff: node_loaded.stuff, + routeId: route.id + }); + + if (error_loaded?.loaded?.error) { + continue; + } + + if (error_loaded?.loaded?.stuff) { + stuff = { + ...stuff, + ...error_loaded.loaded.stuff + }; + } + + branch = branch.slice(0, j + 1).concat(error_loaded); + break load; + } catch (e) { + continue; + } + } + } + + return await load_root_error_page({ + status, + error, + url, + routeId: route.id + }); + } else { + if (node?.loaded?.stuff) { + stuff = { + ...stuff, + ...node.loaded.stuff + }; + } + + branch.push(node); + } + } + + return await get_navigation_result_from_branch({ + url, + params, + stuff, + branch, + status, + error, + routeId: route.id + }); + } + + /** + * @param {{ + * status: number; + * error: Error; + * url: URL; + * routeId: string | null + * }} opts + */ + async function load_root_error_page({ status, error, url, routeId }) { + /** @type {Record} */ + const params = {}; // error page does not have params + + const root_layout = await load_node({ + module: await default_layout, + url, + params, + stuff: {}, + routeId + }); + + const root_error = await load_node({ + status, + error, + module: await default_error, + url, + params, + stuff: (root_layout && root_layout.loaded && root_layout.loaded.stuff) || {}, + routeId + }); + + return await get_navigation_result_from_branch({ + url, + params, + stuff: { + ...root_layout?.loaded?.stuff, + ...root_error?.loaded?.stuff + }, + branch: [root_layout, root_error], + status, + error, + routeId + }); + } + + /** @param {URL} url */ + function get_navigation_intent(url) { + if (url.origin !== location.origin || !url.pathname.startsWith(base)) return; + + const path = decodeURI(url.pathname.slice(base.length) || '/'); + + for (const route of routes) { + const params = route.exec(path); + + if (params) { + /** @type {import('./types').NavigationIntent} */ + const intent = { + id: url.pathname + url.search, + route, + params, + url + }; + + return intent; + } + } + } + + /** + * @param {{ + * url: URL; + * scroll: { x: number, y: number } | null; + * keepfocus: boolean; + * redirect_chain: string[]; + * details: { + * replaceState: boolean; + * state: any; + * } | null; + * accepted: () => void; + * blocked: () => void; + * }} opts + */ + async function navigate({ url, scroll, keepfocus, redirect_chain, details, accepted, blocked }) { + const from = current.url; + let should_block = false; + + const navigation = { + from, + to: url, + cancel: () => (should_block = true) + }; + + callbacks.before_navigate.forEach((fn) => fn(navigation)); + + if (should_block) { + blocked(); + return; + } + + const pathname = normalize_path(url.pathname, trailing_slash); + const normalized = new URL(url.origin + pathname + url.search + url.hash); + + update_scroll_positions(current_history_index); + + accepted(); + + navigating++; + + const current_navigating_token = (navigating_token = {}); + + if (started) { + stores.navigating.set({ + from: current.url, + to: normalized + }); + } + + await update(normalized, redirect_chain, false, { + scroll, + keepfocus, + details + }); + + navigating--; + + // navigation was aborted + if (navigating_token !== current_navigating_token) return; + + if (!navigating) { + const navigation = { from, to: normalized }; + callbacks.after_navigate.forEach((fn) => fn(navigation)); + + stores.navigating.set(null); + } + } + + /** + * Loads `href` the old-fashioned way, with a full page reload. + * Returns a `Promise` that never resolves (to prevent any + * subsequent work, e.g. history manipulation, from happening) + * @param {URL} url + */ + function native_navigation(url) { + location.href = url.href; + return new Promise(() => {}); + } + + return { + after_navigate: (fn) => { + onMount(() => { + callbacks.after_navigate.push(fn); + + return () => { + const i = callbacks.after_navigate.indexOf(fn); + callbacks.after_navigate.splice(i, 1); + }; + }); + }, + + before_navigate: (fn) => { + onMount(() => { + callbacks.before_navigate.push(fn); + + return () => { + const i = callbacks.before_navigate.indexOf(fn); + callbacks.before_navigate.splice(i, 1); + }; + }); + }, + + disable_scroll_handling: () => { + if (import.meta.env.DEV && started && !updating) { + throw new Error('Can only disable scroll handling during navigation'); + } + + if (updating || !started) { + autoscroll = false; + } + }, + + goto: (href, opts = {}) => goto(href, opts, []), + + invalidate: (resource) => { + const { href } = new URL(resource, location.href); + + invalidated.add(href); + + if (!invalidating) { + invalidating = Promise.resolve().then(async () => { + await update(new URL(location.href), [], true); + + invalidating = null; + }); + } + + return invalidating; + }, + + prefetch: async (href) => { + const url = new URL(href, get_base_uri(document)); + await prefetch(url); + }, + + // TODO rethink this API + prefetch_routes: async (pathnames) => { + const matching = pathnames + ? routes.filter((route) => pathnames.some((pathname) => route.exec(pathname))) + : routes; + + const promises = matching.map((r) => Promise.all(r.a.map((load) => load()))); + + await Promise.all(promises); + }, + + _start_router: () => { + history.scrollRestoration = 'manual'; + + // Adopted from Nuxt.js + // Reset scrollRestoration to auto when leaving page, allowing page reload + // and back-navigation from other pages to use the browser to restore the + // scrolling position. + addEventListener('beforeunload', (e) => { + let should_block = false; + + const navigation = { + from: current.url, + to: null, + cancel: () => (should_block = true) + }; + + callbacks.before_navigate.forEach((fn) => fn(navigation)); + + if (should_block) { + e.preventDefault(); + e.returnValue = ''; + } else { + history.scrollRestoration = 'auto'; + } + }); + + addEventListener('visibilitychange', () => { + if (document.visibilityState === 'hidden') { + update_scroll_positions(current_history_index); + + try { + sessionStorage[SCROLL_KEY] = JSON.stringify(scroll_positions); + } catch { + // do nothing + } + } + }); + + /** @param {Event} event */ + const trigger_prefetch = (event) => { + const a = find_anchor(event); + if (a && a.href && a.hasAttribute('sveltekit:prefetch')) { + prefetch(get_href(a)); + } + }; + + /** @type {NodeJS.Timeout} */ + let mousemove_timeout; + + /** @param {MouseEvent|TouchEvent} event */ + const handle_mousemove = (event) => { + clearTimeout(mousemove_timeout); + mousemove_timeout = setTimeout(() => { + // event.composedPath(), which is used in find_anchor, will be empty if the event is read in a timeout + // add a layer of indirection to address that + event.target?.dispatchEvent( + new CustomEvent('sveltekit:trigger_prefetch', { bubbles: true }) + ); + }, 20); + }; + + addEventListener('touchstart', trigger_prefetch); + addEventListener('mousemove', handle_mousemove); + addEventListener('sveltekit:trigger_prefetch', trigger_prefetch); + + /** @param {MouseEvent} event */ + addEventListener('click', (event) => { + if (!router_enabled) return; + + // Adapted from https://github.com/visionmedia/page.js + // MIT license https://github.com/visionmedia/page.js#license + if (event.button || event.which !== 1) return; + if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return; + if (event.defaultPrevented) return; + + const a = find_anchor(event); + if (!a) return; + + if (!a.href) return; + + const is_svg_a_element = a instanceof SVGAElement; + const url = get_href(a); + + // Ignore if url does not have origin (e.g. `mailto:`, `tel:`.) + // MEMO: Without this condition, firefox will open mailer twice. + // See: https://github.com/sveltejs/kit/issues/4045 + if (!is_svg_a_element && url.origin === 'null') return; + + // Ignore if tag has + // 1. 'download' attribute + // 2. 'rel' attribute includes external + const rel = (a.getAttribute('rel') || '').split(/\s+/); + + if (a.hasAttribute('download') || rel.includes('external')) { + return; + } + + // Ignore if has a target + if (is_svg_a_element ? a.target.baseVal : a.target) return; + + if (url.href === location.href) { + if (!location.hash) event.preventDefault(); + return; + } + + // Check if new url only differs by hash and use the browser default behavior in that case + // This will ensure the `hashchange` event is fired + // Removing the hash does a full page navigation in the browser, so make sure a hash is present + const [base, hash] = url.href.split('#'); + if (hash !== undefined && base === location.href.split('#')[0]) { + // set this flag to distinguish between navigations triggered by + // clicking a hash link and those triggered by popstate + hash_navigating = true; + + update_scroll_positions(current_history_index); + + stores.page.set({ ...page, url }); + stores.page.notify(); + + return; + } + + navigate({ + url, + scroll: a.hasAttribute('sveltekit:noscroll') ? scroll_state() : null, + keepfocus: false, + redirect_chain: [], + details: { + state: {}, + replaceState: false + }, + accepted: () => event.preventDefault(), + blocked: () => event.preventDefault() + }); + }); + + addEventListener('popstate', (event) => { + if (event.state && router_enabled) { + // if a popstate-driven navigation is cancelled, we need to counteract it + // with history.go, which means we end up back here, hence this check + if (event.state[INDEX_KEY] === current_history_index) return; + + navigate({ + url: new URL(location.href), + scroll: scroll_positions[event.state[INDEX_KEY]], + keepfocus: false, + redirect_chain: [], + details: null, + accepted: () => { + current_history_index = event.state[INDEX_KEY]; + }, + blocked: () => { + const delta = current_history_index - event.state[INDEX_KEY]; + history.go(delta); + } + }); + } + }); + + addEventListener('hashchange', () => { + // if the hashchange happened as a result of clicking on a link, + // we need to update history, otherwise we have to leave it alone + if (hash_navigating) { + hash_navigating = false; + history.replaceState( + { ...history.state, [INDEX_KEY]: ++current_history_index }, + '', + location.href + ); + } + }); + }, + + _hydrate: async ({ status, error, nodes, params, routeId }) => { + const url = new URL(location.href); + + /** @type {Array} */ + const branch = []; + + /** @type {Record} */ + let stuff = {}; + + /** @type {import('./types').NavigationResult | undefined} */ + let result; + + let error_args; + + try { + for (let i = 0; i < nodes.length; i += 1) { + const is_leaf = i === nodes.length - 1; + + let props; + + if (is_leaf) { + const serialized = document.querySelector('script[sveltekit\\:data-type="props"]'); + if (serialized) { + props = JSON.parse(/** @type {string} */ (serialized.textContent)); + } + } + + const node = await load_node({ + module: await nodes[i], + url, + params, + stuff, + status: is_leaf ? status : undefined, + error: is_leaf ? error : undefined, + props, + routeId + }); + + if (props) { + node.uses.dependencies.add(url.href); + node.uses.url = true; + } + + branch.push(node); + + if (node && node.loaded) { + if (node.loaded.error) { + if (error) throw node.loaded.error; + error_args = { + status: node.loaded.status, + error: node.loaded.error, + url, + routeId + }; + } else if (node.loaded.stuff) { + stuff = { + ...stuff, + ...node.loaded.stuff + }; + } + } + } + + result = error_args + ? await load_root_error_page(error_args) + : await get_navigation_result_from_branch({ + url, + params, + stuff, + branch, + status, + error, + routeId + }); + } catch (e) { + if (error) throw e; + + result = await load_root_error_page({ + status: 500, + error: coalesce_to_error(e), + url, + routeId + }); + } + + if (result.redirect) { + // this is a real edge case — `load` would need to return + // a redirect but only in the browser + await native_navigation(new URL(result.redirect, location.href)); + } + + initialize(result); + } + }; +} + +/** + * @param {{ + * paths: { + * assets: string; + * base: string; + * }, + * target: Element; + * session: any; + * route: boolean; + * spa: boolean; + * trailing_slash: import('types').TrailingSlash; + * hydrate: { + * status: number; + * error: Error; + * nodes: Array>; + * params: Record; + * routeId: string | null; + * }; + * }} opts + */ +async function start({ paths, target, session, route, spa, trailing_slash, hydrate }) { + const client = create_client({ + target, + session, + base: paths.base, + trailing_slash + }); + + init({ client }); + set_paths(paths); + + if (hydrate) { + await client._hydrate(hydrate); + } + + if (route) { + if (spa) client.goto(location.href, { replaceState: true }); + client._start_router(); + } + + dispatchEvent(new CustomEvent('sveltekit:start')); +} + +export { start }; diff --git a/.svelte-kit/runtime/components/error.svelte b/.svelte-kit/runtime/components/error.svelte new file mode 100644 index 0000000..8a66b8d --- /dev/null +++ b/.svelte-kit/runtime/components/error.svelte @@ -0,0 +1,29 @@ + + + + +

{status}

+ +
{error.message}
+ + + +{#if error.frame} +
{error.frame}
+{/if} +{#if error.stack} +
{error.stack}
+{/if} diff --git a/.svelte-kit/runtime/components/layout.svelte b/.svelte-kit/runtime/components/layout.svelte new file mode 100644 index 0000000..49aeb95 --- /dev/null +++ b/.svelte-kit/runtime/components/layout.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.svelte-kit/runtime/env.js b/.svelte-kit/runtime/env.js new file mode 100644 index 0000000..bbc86ed --- /dev/null +++ b/.svelte-kit/runtime/env.js @@ -0,0 +1,8 @@ +let prerendering = false; + +/** @param {boolean} value */ +function set_prerendering(value) { + prerendering = value; +} + +export { prerendering, set_prerendering }; diff --git a/.svelte-kit/runtime/paths.js b/.svelte-kit/runtime/paths.js new file mode 100644 index 0000000..64963b5 --- /dev/null +++ b/.svelte-kit/runtime/paths.js @@ -0,0 +1,13 @@ +/** @type {string} */ +let base = ''; + +/** @type {string} */ +let assets = ''; + +/** @param {{ base: string, assets: string }} paths */ +function set_paths(paths) { + base = paths.base; + assets = paths.assets || base; +} + +export { assets, base, set_paths }; diff --git a/.svelte-kit/runtime/server/index.js b/.svelte-kit/runtime/server/index.js new file mode 100644 index 0000000..9f7b15a --- /dev/null +++ b/.svelte-kit/runtime/server/index.js @@ -0,0 +1,2845 @@ +/** @param {Partial | undefined} object */ +function to_headers(object) { + const headers = new Headers(); + + if (object) { + for (const key in object) { + const value = object[key]; + if (!value) continue; + + if (Array.isArray(value)) { + value.forEach((value) => { + headers.append(key, /** @type {string} */ (value)); + }); + } else { + headers.set(key, /** @type {string} */ (value)); + } + } + } + + return headers; +} + +/** + * Hash using djb2 + * @param {import('types').StrictBody} value + */ +function hash(value) { + let hash = 5381; + let i = value.length; + + if (typeof value === 'string') { + while (i) hash = (hash * 33) ^ value.charCodeAt(--i); + } else { + while (i) hash = (hash * 33) ^ value[--i]; + } + + return (hash >>> 0).toString(36); +} + +/** @param {Record} obj */ +function lowercase_keys(obj) { + /** @type {Record} */ + const clone = {}; + + for (const key in obj) { + clone[key.toLowerCase()] = obj[key]; + } + + return clone; +} + +/** @param {Record} params */ +function decode_params(params) { + for (const key in params) { + // input has already been decoded by decodeURI + // now handle the rest that decodeURIComponent would do + params[key] = params[key] + .replace(/%23/g, '#') + .replace(/%3[Bb]/g, ';') + .replace(/%2[Cc]/g, ',') + .replace(/%2[Ff]/g, '/') + .replace(/%3[Ff]/g, '?') + .replace(/%3[Aa]/g, ':') + .replace(/%40/g, '@') + .replace(/%26/g, '&') + .replace(/%3[Dd]/g, '=') + .replace(/%2[Bb]/g, '+') + .replace(/%24/g, '$'); + } + + return params; +} + +/** @param {any} body */ +function is_pojo(body) { + if (typeof body !== 'object') return false; + + if (body) { + if (body instanceof Uint8Array) return false; + + // body could be a node Readable, but we don't want to import + // node built-ins, so we use duck typing + if (body._readableState && typeof body.pipe === 'function') return false; + + // similarly, it could be a web ReadableStream + if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) return false; + } + + return true; +} + +/** @param {import('types').RequestEvent} event */ +function normalize_request_method(event) { + const method = event.request.method.toLowerCase(); + return method === 'delete' ? 'del' : method; // 'delete' is a reserved word +} + +/** @param {string} body */ +function error(body) { + return new Response(body, { + status: 500 + }); +} + +/** @param {unknown} s */ +function is_string(s) { + return typeof s === 'string' || s instanceof String; +} + +const text_types = new Set([ + 'application/xml', + 'application/json', + 'application/x-www-form-urlencoded', + 'multipart/form-data' +]); + +/** + * Decides how the body should be parsed based on its mime type. Should match what's in parse_body + * + * @param {string | undefined | null} content_type The `content-type` header of a request/response. + * @returns {boolean} + */ +function is_text(content_type) { + if (!content_type) return true; // defaults to json + const type = content_type.split(';')[0].toLowerCase(); // get the mime type + + return type.startsWith('text/') || type.endsWith('+xml') || text_types.has(type); +} + +/** + * @param {import('types').RequestEvent} event + * @param {{ [method: string]: import('types').RequestHandler }} mod + * @returns {Promise} + */ +async function render_endpoint(event, mod) { + const method = normalize_request_method(event); + + /** @type {import('types').RequestHandler} */ + let handler = mod[method]; + + if (!handler && method === 'head') { + handler = mod.get; + } + + if (!handler) { + return event.request.headers.get('x-sveltekit-load') + ? // TODO would be nice to avoid these requests altogether, + // by noting whether or not page endpoints export `get` + new Response(undefined, { + status: 204 + }) + : new Response('Method not allowed', { + status: 405 + }); + } + + const response = await handler(event); + const preface = `Invalid response from route ${event.url.pathname}`; + + if (typeof response !== 'object') { + return error(`${preface}: expected an object, got ${typeof response}`); + } + + // TODO remove for 1.0 + // @ts-expect-error + if (response.fallthrough) { + throw new Error( + 'fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching' + ); + } + + const { status = 200, body = {} } = response; + const headers = + response.headers instanceof Headers + ? new Headers(response.headers) + : to_headers(response.headers); + + const type = headers.get('content-type'); + + if (!is_text(type) && !(body instanceof Uint8Array || is_string(body))) { + return error( + `${preface}: body must be an instance of string or Uint8Array if content-type is not a supported textual content-type` + ); + } + + /** @type {import('types').StrictBody} */ + let normalized_body; + + if (is_pojo(body) && (!type || type.startsWith('application/json'))) { + headers.set('content-type', 'application/json; charset=utf-8'); + normalized_body = JSON.stringify(body); + } else { + normalized_body = /** @type {import('types').StrictBody} */ (body); + } + + if ( + (typeof normalized_body === 'string' || normalized_body instanceof Uint8Array) && + !headers.has('etag') + ) { + const cache_control = headers.get('cache-control'); + if (!cache_control || !/(no-store|immutable)/.test(cache_control)) { + headers.set('etag', `"${hash(normalized_body)}"`); + } + } + + return new Response(method !== 'head' ? normalized_body : undefined, { + status, + headers + }); +} + +var chars$1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$'; +var unsafeChars = /[<>\b\f\n\r\t\0\u2028\u2029]/g; +var reserved = /^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/; +var escaped = { + '<': '\\u003C', + '>': '\\u003E', + '/': '\\u002F', + '\\': '\\\\', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + '\0': '\\0', + '\u2028': '\\u2028', + '\u2029': '\\u2029' +}; +var objectProtoOwnPropertyNames = Object.getOwnPropertyNames(Object.prototype).sort().join('\0'); +function devalue(value) { + var counts = new Map(); + function walk(thing) { + if (typeof thing === 'function') { + throw new Error("Cannot stringify a function"); + } + if (counts.has(thing)) { + counts.set(thing, counts.get(thing) + 1); + return; + } + counts.set(thing, 1); + if (!isPrimitive(thing)) { + var type = getType(thing); + switch (type) { + case 'Number': + case 'String': + case 'Boolean': + case 'Date': + case 'RegExp': + return; + case 'Array': + thing.forEach(walk); + break; + case 'Set': + case 'Map': + Array.from(thing).forEach(walk); + break; + default: + var proto = Object.getPrototypeOf(thing); + if (proto !== Object.prototype && + proto !== null && + Object.getOwnPropertyNames(proto).sort().join('\0') !== objectProtoOwnPropertyNames) { + throw new Error("Cannot stringify arbitrary non-POJOs"); + } + if (Object.getOwnPropertySymbols(thing).length > 0) { + throw new Error("Cannot stringify POJOs with symbolic keys"); + } + Object.keys(thing).forEach(function (key) { return walk(thing[key]); }); + } + } + } + walk(value); + var names = new Map(); + Array.from(counts) + .filter(function (entry) { return entry[1] > 1; }) + .sort(function (a, b) { return b[1] - a[1]; }) + .forEach(function (entry, i) { + names.set(entry[0], getName(i)); + }); + function stringify(thing) { + if (names.has(thing)) { + return names.get(thing); + } + if (isPrimitive(thing)) { + return stringifyPrimitive(thing); + } + var type = getType(thing); + switch (type) { + case 'Number': + case 'String': + case 'Boolean': + return "Object(" + stringify(thing.valueOf()) + ")"; + case 'RegExp': + return "new RegExp(" + stringifyString(thing.source) + ", \"" + thing.flags + "\")"; + case 'Date': + return "new Date(" + thing.getTime() + ")"; + case 'Array': + var members = thing.map(function (v, i) { return i in thing ? stringify(v) : ''; }); + var tail = thing.length === 0 || (thing.length - 1 in thing) ? '' : ','; + return "[" + members.join(',') + tail + "]"; + case 'Set': + case 'Map': + return "new " + type + "([" + Array.from(thing).map(stringify).join(',') + "])"; + default: + var obj = "{" + Object.keys(thing).map(function (key) { return safeKey(key) + ":" + stringify(thing[key]); }).join(',') + "}"; + var proto = Object.getPrototypeOf(thing); + if (proto === null) { + return Object.keys(thing).length > 0 + ? "Object.assign(Object.create(null)," + obj + ")" + : "Object.create(null)"; + } + return obj; + } + } + var str = stringify(value); + if (names.size) { + var params_1 = []; + var statements_1 = []; + var values_1 = []; + names.forEach(function (name, thing) { + params_1.push(name); + if (isPrimitive(thing)) { + values_1.push(stringifyPrimitive(thing)); + return; + } + var type = getType(thing); + switch (type) { + case 'Number': + case 'String': + case 'Boolean': + values_1.push("Object(" + stringify(thing.valueOf()) + ")"); + break; + case 'RegExp': + values_1.push(thing.toString()); + break; + case 'Date': + values_1.push("new Date(" + thing.getTime() + ")"); + break; + case 'Array': + values_1.push("Array(" + thing.length + ")"); + thing.forEach(function (v, i) { + statements_1.push(name + "[" + i + "]=" + stringify(v)); + }); + break; + case 'Set': + values_1.push("new Set"); + statements_1.push(name + "." + Array.from(thing).map(function (v) { return "add(" + stringify(v) + ")"; }).join('.')); + break; + case 'Map': + values_1.push("new Map"); + statements_1.push(name + "." + Array.from(thing).map(function (_a) { + var k = _a[0], v = _a[1]; + return "set(" + stringify(k) + ", " + stringify(v) + ")"; + }).join('.')); + break; + default: + values_1.push(Object.getPrototypeOf(thing) === null ? 'Object.create(null)' : '{}'); + Object.keys(thing).forEach(function (key) { + statements_1.push("" + name + safeProp(key) + "=" + stringify(thing[key])); + }); + } + }); + statements_1.push("return " + str); + return "(function(" + params_1.join(',') + "){" + statements_1.join(';') + "}(" + values_1.join(',') + "))"; + } + else { + return str; + } +} +function getName(num) { + var name = ''; + do { + name = chars$1[num % chars$1.length] + name; + num = ~~(num / chars$1.length) - 1; + } while (num >= 0); + return reserved.test(name) ? name + "_" : name; +} +function isPrimitive(thing) { + return Object(thing) !== thing; +} +function stringifyPrimitive(thing) { + if (typeof thing === 'string') + return stringifyString(thing); + if (thing === void 0) + return 'void 0'; + if (thing === 0 && 1 / thing < 0) + return '-0'; + var str = String(thing); + if (typeof thing === 'number') + return str.replace(/^(-)?0\./, '$1.'); + return str; +} +function getType(thing) { + return Object.prototype.toString.call(thing).slice(8, -1); +} +function escapeUnsafeChar(c) { + return escaped[c] || c; +} +function escapeUnsafeChars(str) { + return str.replace(unsafeChars, escapeUnsafeChar); +} +function safeKey(key) { + return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : escapeUnsafeChars(JSON.stringify(key)); +} +function safeProp(key) { + return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? "." + key : "[" + escapeUnsafeChars(JSON.stringify(key)) + "]"; +} +function stringifyString(str) { + var result = '"'; + for (var i = 0; i < str.length; i += 1) { + var char = str.charAt(i); + var code = char.charCodeAt(0); + if (char === '"') { + result += '\\"'; + } + else if (char in escaped) { + result += escaped[char]; + } + else if (code >= 0xd800 && code <= 0xdfff) { + var next = str.charCodeAt(i + 1); + // If this is the beginning of a [high, low] surrogate pair, + // add the next two characters, otherwise escape + if (code <= 0xdbff && (next >= 0xdc00 && next <= 0xdfff)) { + result += char + str[++i]; + } + else { + result += "\\u" + code.toString(16).toUpperCase(); + } + } + else { + result += char; + } + } + result += '"'; + return result; +} + +function noop() { } +function safe_not_equal(a, b) { + return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); +} +Promise.resolve(); + +const subscriber_queue = []; +/** + * Creates a `Readable` store that allows reading by subscription. + * @param value initial value + * @param {StartStopNotifier}start start and stop notifications for subscriptions + */ +function readable(value, start) { + return { + subscribe: writable(value, start).subscribe + }; +} +/** + * Create a `Writable` store that allows both updating and reading by subscription. + * @param {*=}value initial value + * @param {StartStopNotifier=}start start and stop notifications for subscriptions + */ +function writable(value, start = noop) { + let stop; + const subscribers = new Set(); + function set(new_value) { + if (safe_not_equal(value, new_value)) { + value = new_value; + if (stop) { // store is ready + const run_queue = !subscriber_queue.length; + for (const subscriber of subscribers) { + subscriber[1](); + subscriber_queue.push(subscriber, value); + } + if (run_queue) { + for (let i = 0; i < subscriber_queue.length; i += 2) { + subscriber_queue[i][0](subscriber_queue[i + 1]); + } + subscriber_queue.length = 0; + } + } + } + } + function update(fn) { + set(fn(value)); + } + function subscribe(run, invalidate = noop) { + const subscriber = [run, invalidate]; + subscribers.add(subscriber); + if (subscribers.size === 1) { + stop = start(set) || noop; + } + run(value); + return () => { + subscribers.delete(subscriber); + if (subscribers.size === 0) { + stop(); + stop = null; + } + }; + } + return { set, update, subscribe }; +} + +/** + * @param {unknown} err + * @return {Error} + */ +function coalesce_to_error(err) { + return err instanceof Error || + (err && /** @type {any} */ (err).name && /** @type {any} */ (err).message) + ? /** @type {Error} */ (err) + : new Error(JSON.stringify(err)); +} + +/** + * Inside a script element, only ``, so the script element might be unexpectedly + * kept open until until an unrelated HTML comment in the page. + * + * U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are escaped for the sake of pre-2018 + * browsers. + * + * @see tests for unsafe parsing examples. + * @see https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements + * @see https://html.spec.whatwg.org/multipage/syntax.html#cdata-rcdata-restrictions + * @see https://html.spec.whatwg.org/multipage/parsing.html#script-data-state + * @see https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-state + * @see https://github.com/tc39/proposal-json-superset + * @type {Record} + */ +const render_json_payload_script_dict = { + '<': '\\u003C', + '\u2028': '\\u2028', + '\u2029': '\\u2029' +}; + +const render_json_payload_script_regex = new RegExp( + `[${Object.keys(render_json_payload_script_dict).join('')}]`, + 'g' +); + +/** + * Generates a raw HTML string containing a safe script element carrying JSON data and associated attributes. + * + * It escapes all the special characters needed to guarantee the element is unbroken, but care must + * be taken to ensure it is inserted in the document at an acceptable position for a script element, + * and that the resulting string isn't further modified. + * + * Attribute names must be type-checked so we don't need to escape them. + * + * @param {import('types').PayloadScriptAttributes} attrs A list of attributes to be added to the element. + * @param {import('types').JSONValue} payload The data to be carried by the element. Must be serializable to JSON. + * @returns {string} The raw HTML of a script element carrying the JSON payload. + * @example const html = render_json_payload_script({ type: 'data', url: '/data.json' }, { foo: 'bar' }); + */ +function render_json_payload_script(attrs, payload) { + const safe_payload = JSON.stringify(payload).replace( + render_json_payload_script_regex, + (match) => render_json_payload_script_dict[match] + ); + + let safe_attrs = ''; + for (const [key, value] of Object.entries(attrs)) { + if (value === undefined) continue; + safe_attrs += ` sveltekit:data-${key}=${escape_html_attr(value)}`; + } + + return ``; +} + +/** + * When inside a double-quoted attribute value, only `&` and `"` hold special meaning. + * @see https://html.spec.whatwg.org/multipage/parsing.html#attribute-value-(double-quoted)-state + * @type {Record} + */ +const escape_html_attr_dict = { + '&': '&', + '"': '"' +}; + +const escape_html_attr_regex = new RegExp( + // special characters + `[${Object.keys(escape_html_attr_dict).join('')}]|` + + // high surrogate without paired low surrogate + '[\\ud800-\\udbff](?![\\udc00-\\udfff])|' + + // a valid surrogate pair, the only match with 2 code units + // we match it so that we can match unpaired low surrogates in the same pass + // TODO: use lookbehind assertions once they are widely supported: (?...`; + */ +function escape_html_attr(str) { + const escaped_str = str.replace(escape_html_attr_regex, (match) => { + if (match.length === 2) { + // valid surrogate pair + return match; + } + + return escape_html_attr_dict[match] ?? `&#${match.charCodeAt(0)};`; + }); + + return `"${escaped_str}"`; +} + +const s = JSON.stringify; + +/** @param {URL} url */ +function create_prerendering_url_proxy(url) { + return new Proxy(url, { + get: (target, prop, receiver) => { + if (prop === 'search' || prop === 'searchParams') { + throw new Error(`Cannot access url.${prop} on a page with prerendering enabled`); + } + return Reflect.get(target, prop, receiver); + } + }); +} + +const encoder = new TextEncoder(); + +/** + * SHA-256 hashing function adapted from https://bitwiseshiftleft.github.io/sjcl + * modified and redistributed under BSD license + * @param {string} data + */ +function sha256(data) { + if (!key[0]) precompute(); + + const out = init.slice(0); + const array = encode(data); + + for (let i = 0; i < array.length; i += 16) { + const w = array.subarray(i, i + 16); + + let tmp; + let a; + let b; + + let out0 = out[0]; + let out1 = out[1]; + let out2 = out[2]; + let out3 = out[3]; + let out4 = out[4]; + let out5 = out[5]; + let out6 = out[6]; + let out7 = out[7]; + + /* Rationale for placement of |0 : + * If a value can overflow is original 32 bits by a factor of more than a few + * million (2^23 ish), there is a possibility that it might overflow the + * 53-bit mantissa and lose precision. + * + * To avoid this, we clamp back to 32 bits by |'ing with 0 on any value that + * propagates around the loop, and on the hash state out[]. I don't believe + * that the clamps on out4 and on out0 are strictly necessary, but it's close + * (for out4 anyway), and better safe than sorry. + * + * The clamps on out[] are necessary for the output to be correct even in the + * common case and for short inputs. + */ + + for (let i = 0; i < 64; i++) { + // load up the input word for this round + + if (i < 16) { + tmp = w[i]; + } else { + a = w[(i + 1) & 15]; + + b = w[(i + 14) & 15]; + + tmp = w[i & 15] = + (((a >>> 7) ^ (a >>> 18) ^ (a >>> 3) ^ (a << 25) ^ (a << 14)) + + ((b >>> 17) ^ (b >>> 19) ^ (b >>> 10) ^ (b << 15) ^ (b << 13)) + + w[i & 15] + + w[(i + 9) & 15]) | + 0; + } + + tmp = + tmp + + out7 + + ((out4 >>> 6) ^ (out4 >>> 11) ^ (out4 >>> 25) ^ (out4 << 26) ^ (out4 << 21) ^ (out4 << 7)) + + (out6 ^ (out4 & (out5 ^ out6))) + + key[i]; // | 0; + + // shift register + out7 = out6; + out6 = out5; + out5 = out4; + + out4 = (out3 + tmp) | 0; + + out3 = out2; + out2 = out1; + out1 = out0; + + out0 = + (tmp + + ((out1 & out2) ^ (out3 & (out1 ^ out2))) + + ((out1 >>> 2) ^ + (out1 >>> 13) ^ + (out1 >>> 22) ^ + (out1 << 30) ^ + (out1 << 19) ^ + (out1 << 10))) | + 0; + } + + out[0] = (out[0] + out0) | 0; + out[1] = (out[1] + out1) | 0; + out[2] = (out[2] + out2) | 0; + out[3] = (out[3] + out3) | 0; + out[4] = (out[4] + out4) | 0; + out[5] = (out[5] + out5) | 0; + out[6] = (out[6] + out6) | 0; + out[7] = (out[7] + out7) | 0; + } + + const bytes = new Uint8Array(out.buffer); + reverse_endianness(bytes); + + return base64(bytes); +} + +/** The SHA-256 initialization vector */ +const init = new Uint32Array(8); + +/** The SHA-256 hash key */ +const key = new Uint32Array(64); + +/** Function to precompute init and key. */ +function precompute() { + /** @param {number} x */ + function frac(x) { + return (x - Math.floor(x)) * 0x100000000; + } + + let prime = 2; + + for (let i = 0; i < 64; prime++) { + let is_prime = true; + + for (let factor = 2; factor * factor <= prime; factor++) { + if (prime % factor === 0) { + is_prime = false; + + break; + } + } + + if (is_prime) { + if (i < 8) { + init[i] = frac(prime ** (1 / 2)); + } + + key[i] = frac(prime ** (1 / 3)); + + i++; + } + } +} + +/** @param {Uint8Array} bytes */ +function reverse_endianness(bytes) { + for (let i = 0; i < bytes.length; i += 4) { + const a = bytes[i + 0]; + const b = bytes[i + 1]; + const c = bytes[i + 2]; + const d = bytes[i + 3]; + + bytes[i + 0] = d; + bytes[i + 1] = c; + bytes[i + 2] = b; + bytes[i + 3] = a; + } +} + +/** @param {string} str */ +function encode(str) { + const encoded = encoder.encode(str); + const length = encoded.length * 8; + + // result should be a multiple of 512 bits in length, + // with room for a 1 (after the data) and two 32-bit + // words containing the original input bit length + const size = 512 * Math.ceil((length + 65) / 512); + const bytes = new Uint8Array(size / 8); + bytes.set(encoded); + + // append a 1 + bytes[encoded.length] = 0b10000000; + + reverse_endianness(bytes); + + // add the input bit length + const words = new Uint32Array(bytes.buffer); + words[words.length - 2] = Math.floor(length / 0x100000000); // this will always be zero for us + words[words.length - 1] = length; + + return words; +} + +/* + Based on https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727 + + MIT License + Copyright (c) 2020 Egor Nepomnyaschih + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); + +/** @param {Uint8Array} bytes */ +function base64(bytes) { + const l = bytes.length; + + let result = ''; + let i; + + for (i = 2; i < l; i += 3) { + result += chars[bytes[i - 2] >> 2]; + result += chars[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)]; + result += chars[((bytes[i - 1] & 0x0f) << 2) | (bytes[i] >> 6)]; + result += chars[bytes[i] & 0x3f]; + } + + if (i === l + 1) { + // 1 octet yet to write + result += chars[bytes[i - 2] >> 2]; + result += chars[(bytes[i - 2] & 0x03) << 4]; + result += '=='; + } + + if (i === l) { + // 2 octets yet to write + result += chars[bytes[i - 2] >> 2]; + result += chars[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)]; + result += chars[(bytes[i - 1] & 0x0f) << 2]; + result += '='; + } + + return result; +} + +/** @type {Promise} */ +let csp_ready; + +/** @type {() => string} */ +let generate_nonce; + +/** @type {(input: string) => string} */ +let generate_hash; + +if (typeof crypto !== 'undefined') { + const array = new Uint8Array(16); + + generate_nonce = () => { + crypto.getRandomValues(array); + return base64(array); + }; + + generate_hash = sha256; +} else { + // TODO: remove this in favor of web crypto API once we no longer support Node 14 + const name = 'crypto'; // store in a variable to fool esbuild when adapters bundle kit + csp_ready = import(name).then((crypto) => { + generate_nonce = () => { + return crypto.randomBytes(16).toString('base64'); + }; + + generate_hash = (input) => { + return crypto.createHash('sha256').update(input, 'utf-8').digest().toString('base64'); + }; + }); +} + +const quoted = new Set([ + 'self', + 'unsafe-eval', + 'unsafe-hashes', + 'unsafe-inline', + 'none', + 'strict-dynamic', + 'report-sample' +]); + +const crypto_pattern = /^(nonce|sha\d\d\d)-/; + +class Csp { + /** @type {boolean} */ + #use_hashes; + + /** @type {boolean} */ + #dev; + + /** @type {boolean} */ + #script_needs_csp; + + /** @type {boolean} */ + #style_needs_csp; + + /** @type {import('types').CspDirectives} */ + #directives; + + /** @type {import('types').Csp.Source[]} */ + #script_src; + + /** @type {import('types').Csp.Source[]} */ + #style_src; + + /** + * @param {{ + * mode: string, + * directives: import('types').CspDirectives + * }} config + * @param {{ + * dev: boolean; + * prerender: boolean; + * needs_nonce: boolean; + * }} opts + */ + constructor({ mode, directives }, { dev, prerender, needs_nonce }) { + this.#use_hashes = mode === 'hash' || (mode === 'auto' && prerender); + this.#directives = dev ? { ...directives } : directives; // clone in dev so we can safely mutate + this.#dev = dev; + + const d = this.#directives; + + if (dev) { + // remove strict-dynamic in dev... + // TODO reinstate this if we can figure out how to make strict-dynamic work + // if (d['default-src']) { + // d['default-src'] = d['default-src'].filter((name) => name !== 'strict-dynamic'); + // if (d['default-src'].length === 0) delete d['default-src']; + // } + + // if (d['script-src']) { + // d['script-src'] = d['script-src'].filter((name) => name !== 'strict-dynamic'); + // if (d['script-src'].length === 0) delete d['script-src']; + // } + + const effective_style_src = d['style-src'] || d['default-src']; + + // ...and add unsafe-inline so we can inject + + + + `; + + if (options.service_worker) { + head += + ''; + + body += ``; + } + } else { + if (inlined_style) { + const attributes = []; + if (options.dev) attributes.push(' data-svelte'); + if (csp.style_needs_nonce) attributes.push(` nonce="${csp.nonce}"`); + + csp.add_style(inlined_style); + + head += `\n\t${inlined_style}`; + } + + // prettier-ignore + head += Array.from(stylesheets) + .map((dep) => { + const attributes = [ + 'rel="stylesheet"', + `href="${options.prefix + dep}"` + ]; + + if (csp.style_needs_nonce) { + attributes.push(`nonce="${csp.nonce}"`); + } + + if (styles.has(dep)) { + // don't load stylesheets that are already inlined + // include them in disabled state so that Vite can detect them and doesn't try to add them + attributes.push('disabled', 'media="(max-width: 0)"'); + } + + return `\n\t`; + }) + .join(''); + + if (page_config.router || page_config.hydrate) { + head += Array.from(modulepreloads) + .map((dep) => `\n\t`) + .join(''); + + const attributes = ['type="module"', `data-hydrate="${target}"`]; + + csp.add_script(init_app); + + if (csp.script_needs_nonce) { + attributes.push(`nonce="${csp.nonce}"`); + } + + body += `\n\t\t`; + + body += serialized_data + .map(({ url, body, response }) => + render_json_payload_script( + { type: 'data', url, body: typeof body === 'string' ? hash(body) : undefined }, + response + ) + ) + .join('\n\t'); + + if (shadow_props) { + body += render_json_payload_script({ type: 'props' }, shadow_props); + } + } + + if (options.service_worker) { + // always include service worker unless it's turned off explicitly + csp.add_script(init_service_worker); + + head += ` + ${init_service_worker}`; + } + } + + if (state.prerender && !options.amp) { + const http_equiv = []; + + const csp_headers = csp.get_meta(); + if (csp_headers) { + http_equiv.push(csp_headers); + } + + if (maxage) { + http_equiv.push(``); + } + + if (http_equiv.length > 0) { + head = http_equiv.join('\n') + head; + } + } + + const segments = event.url.pathname.slice(options.paths.base.length).split('/').slice(2); + const assets = + options.paths.assets || (segments.length > 0 ? segments.map(() => '..').join('/') : '.'); + + const html = await resolve_opts.transformPage({ + html: options.template({ head, body, assets, nonce: /** @type {string} */ (csp.nonce) }) + }); + + const headers = new Headers({ + 'content-type': 'text/html', + etag: `"${hash(html)}"` + }); + + if (maxage) { + headers.set('cache-control', `${is_private ? 'private' : 'public'}, max-age=${maxage}`); + } + + if (!options.floc) { + headers.set('permissions-policy', 'interest-cohort=()'); + } + + if (!state.prerender) { + const csp_header = csp.get_header(); + if (csp_header) { + headers.set('content-security-policy', csp_header); + } + } + + return new Response(html, { + status, + headers + }); +} + +/** + * @param {any} data + * @param {(error: Error) => void} [fail] + */ +function try_serialize(data, fail) { + try { + return devalue(data); + } catch (err) { + if (fail) fail(coalesce_to_error(err)); + return null; + } +} + +// Ensure we return something truthy so the client will not re-render the page over the error + +/** @param {(Error & {frame?: string} & {loc?: object}) | undefined | null} error */ +function serialize_error(error) { + if (!error) return null; + let serialized = try_serialize(error); + if (!serialized) { + const { name, message, stack } = error; + serialized = try_serialize({ ...error, name, message, stack }); + } + if (!serialized) { + serialized = '{}'; + } + return serialized; +} + +/** + * @param {import('types').LoadOutput} loaded + * @returns {import('types').NormalizedLoadOutput} + */ +function normalize(loaded) { + const has_error_status = + loaded.status && loaded.status >= 400 && loaded.status <= 599 && !loaded.redirect; + if (loaded.error || has_error_status) { + const status = loaded.status; + + if (!loaded.error && has_error_status) { + return { + status: status || 500, + error: new Error() + }; + } + + const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error; + + if (!(error instanceof Error)) { + return { + status: 500, + error: new Error( + `"error" property returned from load() must be a string or instance of Error, received type "${typeof error}"` + ) + }; + } + + if (!status || status < 400 || status > 599) { + console.warn('"error" returned from load() without a valid status code — defaulting to 500'); + return { status: 500, error }; + } + + return { status, error }; + } + + if (loaded.redirect) { + if (!loaded.status || Math.floor(loaded.status / 100) !== 3) { + return { + status: 500, + error: new Error( + '"redirect" property returned from load() must be accompanied by a 3xx status code' + ) + }; + } + + if (typeof loaded.redirect !== 'string') { + return { + status: 500, + error: new Error('"redirect" property returned from load() must be a string') + }; + } + } + + // TODO remove before 1.0 + if (/** @type {any} */ (loaded).context) { + throw new Error( + 'You are returning "context" from a load function. ' + + '"context" was renamed to "stuff", please adjust your code accordingly.' + ); + } + + return /** @type {import('types').NormalizedLoadOutput} */ (loaded); +} + +const absolute = /^([a-z]+:)?\/?\//; +const scheme = /^[a-z]+:/; + +/** + * @param {string} base + * @param {string} path + */ +function resolve(base, path) { + if (scheme.test(path)) return path; + + const base_match = absolute.exec(base); + const path_match = absolute.exec(path); + + if (!base_match) { + throw new Error(`bad base path: "${base}"`); + } + + const baseparts = path_match ? [] : base.slice(base_match[0].length).split('/'); + const pathparts = path_match ? path.slice(path_match[0].length).split('/') : path.split('/'); + + baseparts.pop(); + + for (let i = 0; i < pathparts.length; i += 1) { + const part = pathparts[i]; + if (part === '.') continue; + else if (part === '..') baseparts.pop(); + else baseparts.push(part); + } + + const prefix = (path_match && path_match[0]) || (base_match && base_match[0]) || ''; + + return `${prefix}${baseparts.join('/')}`; +} + +/** @param {string} path */ +function is_root_relative(path) { + return path[0] === '/' && path[1] !== '/'; +} + +/** + * @param {string} path + * @param {import('types').TrailingSlash} trailing_slash + */ +function normalize_path(path, trailing_slash) { + if (path === '/' || trailing_slash === 'ignore') return path; + + if (trailing_slash === 'never') { + return path.endsWith('/') ? path.slice(0, -1) : path; + } else if (trailing_slash === 'always' && /\/[^./]+$/.test(path)) { + return path + '/'; + } + + return path; +} + +/** + * @param {{ + * event: import('types').RequestEvent; + * options: import('types').SSROptions; + * state: import('types').SSRState; + * route: import('types').SSRPage | null; + * node: import('types').SSRNode; + * $session: any; + * stuff: Record; + * is_error: boolean; + * is_leaf: boolean; + * status?: number; + * error?: Error; + * }} opts + * @returns {Promise} + */ +async function load_node({ + event, + options, + state, + route, + node, + $session, + stuff, + is_error, + is_leaf, + status, + error +}) { + const { module } = node; + + let uses_credentials = false; + + /** @type {Array} */ + const fetched = []; + + /** + * @type {string[]} + */ + let set_cookie_headers = []; + + /** @type {import('types').LoadOutput} */ + let loaded; + + /** @type {import('types').ShadowData} */ + const shadow = is_leaf + ? await load_shadow_data( + /** @type {import('types').SSRPage} */ (route), + event, + options, + !!state.prerender + ) + : {}; + + if (shadow.cookies) { + set_cookie_headers.push(...shadow.cookies); + } + + if (shadow.error) { + loaded = { + status: shadow.status, + error: shadow.error + }; + } else if (shadow.redirect) { + loaded = { + status: shadow.status, + redirect: shadow.redirect + }; + } else if (module.load) { + /** @type {import('types').LoadInput | import('types').ErrorLoadInput} */ + const load_input = { + url: state.prerender ? create_prerendering_url_proxy(event.url) : event.url, + params: event.params, + props: shadow.body || {}, + routeId: event.routeId, + get session() { + uses_credentials = true; + return $session; + }, + /** + * @param {RequestInfo} resource + * @param {RequestInit} opts + */ + fetch: async (resource, opts = {}) => { + /** @type {string} */ + let requested; + + if (typeof resource === 'string') { + requested = resource; + } else { + requested = resource.url; + + opts = { + method: resource.method, + headers: resource.headers, + body: resource.body, + mode: resource.mode, + credentials: resource.credentials, + cache: resource.cache, + redirect: resource.redirect, + referrer: resource.referrer, + integrity: resource.integrity, + ...opts + }; + } + + opts.headers = new Headers(opts.headers); + + // merge headers from request + for (const [key, value] of event.request.headers) { + if ( + key !== 'authorization' && + key !== 'cookie' && + key !== 'host' && + key !== 'if-none-match' && + !opts.headers.has(key) + ) { + opts.headers.set(key, value); + } + } + + const resolved = resolve(event.url.pathname, requested.split('?')[0]); + + /** @type {Response} */ + let response; + + /** @type {import('types').PrerenderDependency} */ + let dependency; + + // handle fetch requests for static assets. e.g. prebaked data, etc. + // we need to support everything the browser's fetch supports + const prefix = options.paths.assets || options.paths.base; + const filename = decodeURIComponent( + resolved.startsWith(prefix) ? resolved.slice(prefix.length) : resolved + ).slice(1); + const filename_html = `${filename}/index.html`; // path may also match path/index.html + + const is_asset = options.manifest.assets.has(filename); + const is_asset_html = options.manifest.assets.has(filename_html); + + if (is_asset || is_asset_html) { + const file = is_asset ? filename : filename_html; + + if (options.read) { + const type = is_asset + ? options.manifest.mimeTypes[filename.slice(filename.lastIndexOf('.'))] + : 'text/html'; + + response = new Response(options.read(file), { + headers: type ? { 'content-type': type } : {} + }); + } else { + response = await fetch( + `${event.url.origin}/${file}`, + /** @type {RequestInit} */ (opts) + ); + } + } else if (is_root_relative(resolved)) { + if (opts.credentials !== 'omit') { + uses_credentials = true; + + const cookie = event.request.headers.get('cookie'); + const authorization = event.request.headers.get('authorization'); + + if (cookie) { + opts.headers.set('cookie', cookie); + } + + if (authorization && !opts.headers.has('authorization')) { + opts.headers.set('authorization', authorization); + } + } + + if (opts.body && typeof opts.body !== 'string') { + // per https://developer.mozilla.org/en-US/docs/Web/API/Request/Request, this can be a + // Blob, BufferSource, FormData, URLSearchParams, USVString, or ReadableStream object. + // non-string bodies are irksome to deal with, but luckily aren't particularly useful + // in this context anyway, so we take the easy route and ban them + throw new Error('Request body must be a string'); + } + + response = await respond(new Request(new URL(requested, event.url).href, opts), options, { + getClientAddress: state.getClientAddress, + initiator: route, + prerender: state.prerender + }); + + if (state.prerender) { + dependency = { response, body: null }; + state.prerender.dependencies.set(resolved, dependency); + } + } else { + // external + if (resolved.startsWith('//')) { + requested = event.url.protocol + requested; + } + + // external fetch + // allow cookie passthrough for "same-origin" + // if SvelteKit is serving my.domain.com: + // - domain.com WILL NOT receive cookies + // - my.domain.com WILL receive cookies + // - api.domain.dom WILL NOT receive cookies + // - sub.my.domain.com WILL receive cookies + // ports do not affect the resolution + // leading dot prevents mydomain.com matching domain.com + if ( + `.${new URL(requested).hostname}`.endsWith(`.${event.url.hostname}`) && + opts.credentials !== 'omit' + ) { + uses_credentials = true; + + const cookie = event.request.headers.get('cookie'); + if (cookie) opts.headers.set('cookie', cookie); + } + + const external_request = new Request(requested, /** @type {RequestInit} */ (opts)); + response = await options.hooks.externalFetch.call(null, external_request); + } + + const proxy = new Proxy(response, { + get(response, key, _receiver) { + async function text() { + const body = await response.text(); + + /** @type {import('types').ResponseHeaders} */ + const headers = {}; + for (const [key, value] of response.headers) { + if (key === 'set-cookie') { + set_cookie_headers = set_cookie_headers.concat(value); + } else if (key !== 'etag') { + headers[key] = value; + } + } + + if (!opts.body || typeof opts.body === 'string') { + const status_number = Number(response.status); + if (isNaN(status_number)) { + throw new Error( + `response.status is not a number. value: "${ + response.status + }" type: ${typeof response.status}` + ); + } + + fetched.push({ + url: requested, + body: opts.body, + response: { + status: status_number, + statusText: response.statusText, + headers, + body + } + }); + } + + if (dependency) { + dependency.body = body; + } + + return body; + } + + if (key === 'arrayBuffer') { + return async () => { + const buffer = await response.arrayBuffer(); + + if (dependency) { + dependency.body = new Uint8Array(buffer); + } + + // TODO should buffer be inlined into the page (albeit base64'd)? + // any conditions in which it shouldn't be? + + return buffer; + }; + } + + if (key === 'text') { + return text; + } + + if (key === 'json') { + return async () => { + return JSON.parse(await text()); + }; + } + + // TODO arrayBuffer? + + return Reflect.get(response, key, response); + } + }); + + return proxy; + }, + stuff: { ...stuff } + }; + + if (options.dev) { + // TODO remove this for 1.0 + Object.defineProperty(load_input, 'page', { + get: () => { + throw new Error('`page` in `load` functions has been replaced by `url` and `params`'); + } + }); + } + + if (is_error) { + /** @type {import('types').ErrorLoadInput} */ (load_input).status = status; + /** @type {import('types').ErrorLoadInput} */ (load_input).error = error; + } + + loaded = await module.load.call(null, load_input); + + if (!loaded) { + // TODO do we still want to enforce this now that there's no fallthrough? + throw new Error(`load function must return a value${options.dev ? ` (${node.entry})` : ''}`); + } + + // TODO remove for 1.0 + // @ts-expect-error + if (loaded.fallthrough) { + throw new Error( + 'fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching' + ); + } + } else if (shadow.body) { + loaded = { + props: shadow.body + }; + } else { + loaded = {}; + } + + // generate __data.json files when prerendering + if (shadow.body && state.prerender) { + const pathname = `${event.url.pathname.replace(/\/$/, '')}/__data.json`; + + const dependency = { + response: new Response(undefined), + body: JSON.stringify(shadow.body) + }; + + state.prerender.dependencies.set(pathname, dependency); + } + + return { + node, + props: shadow.body, + loaded: normalize(loaded), + stuff: loaded.stuff || stuff, + fetched, + set_cookie_headers, + uses_credentials + }; +} + +/** + * + * @param {import('types').SSRPage} route + * @param {import('types').RequestEvent} event + * @param {import('types').SSROptions} options + * @param {boolean} prerender + * @returns {Promise} + */ +async function load_shadow_data(route, event, options, prerender) { + if (!route.shadow) return {}; + + try { + const mod = await route.shadow(); + + if (prerender && (mod.post || mod.put || mod.del || mod.patch)) { + throw new Error('Cannot prerender pages that have endpoints with mutative methods'); + } + + const method = normalize_request_method(event); + const is_get = method === 'head' || method === 'get'; + const handler = method === 'head' ? mod.head || mod.get : mod[method]; + + if (!handler && !is_get) { + return { + status: 405, + error: new Error(`${method} method not allowed`) + }; + } + + /** @type {import('types').ShadowData} */ + const data = { + status: 200, + cookies: [], + body: {} + }; + + if (!is_get) { + const result = await handler(event); + + // TODO remove for 1.0 + // @ts-expect-error + if (result.fallthrough) { + throw new Error( + 'fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching' + ); + } + + const { status, headers, body } = validate_shadow_output(result); + data.status = status; + + add_cookies(/** @type {string[]} */ (data.cookies), headers); + + // Redirects are respected... + if (status >= 300 && status < 400) { + data.redirect = /** @type {string} */ ( + headers instanceof Headers ? headers.get('location') : headers.location + ); + return data; + } + + // ...but 4xx and 5xx status codes _don't_ result in the error page + // rendering for non-GET requests — instead, we allow the page + // to render with any validation errors etc that were returned + data.body = body; + } + + const get = (method === 'head' && mod.head) || mod.get; + if (get) { + const result = await get(event); + + // TODO remove for 1.0 + // @ts-expect-error + if (result.fallthrough) { + throw new Error( + 'fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching' + ); + } + + const { status, headers, body } = validate_shadow_output(result); + add_cookies(/** @type {string[]} */ (data.cookies), headers); + data.status = status; + + if (status >= 400) { + data.error = new Error('Failed to load data'); + return data; + } + + if (status >= 300) { + data.redirect = /** @type {string} */ ( + headers instanceof Headers ? headers.get('location') : headers.location + ); + return data; + } + + data.body = { ...body, ...data.body }; + } + + return data; + } catch (e) { + const error = coalesce_to_error(e); + options.handle_error(error, event); + + return { + status: 500, + error + }; + } +} + +/** + * @param {string[]} target + * @param {Partial} headers + */ +function add_cookies(target, headers) { + const cookies = headers['set-cookie']; + if (cookies) { + if (Array.isArray(cookies)) { + target.push(...cookies); + } else { + target.push(/** @type {string} */ (cookies)); + } + } +} + +/** + * @param {import('types').ShadowEndpointOutput} result + */ +function validate_shadow_output(result) { + const { status = 200, body = {} } = result; + let headers = result.headers || {}; + + if (headers instanceof Headers) { + if (headers.has('set-cookie')) { + throw new Error( + 'Endpoint request handler cannot use Headers interface with Set-Cookie headers' + ); + } + } else { + headers = lowercase_keys(/** @type {Record} */ (headers)); + } + + if (!is_pojo(body)) { + throw new Error('Body returned from endpoint request handler must be a plain object'); + } + + return { status, headers, body }; +} + +/** + * @typedef {import('./types.js').Loaded} Loaded + * @typedef {import('types').SSROptions} SSROptions + * @typedef {import('types').SSRState} SSRState + */ + +/** + * @param {{ + * event: import('types').RequestEvent; + * options: SSROptions; + * state: SSRState; + * $session: any; + * status: number; + * error: Error; + * resolve_opts: import('types').RequiredResolveOptions; + * }} opts + */ +async function respond_with_error({ + event, + options, + state, + $session, + status, + error, + resolve_opts +}) { + try { + const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout + const default_error = await options.manifest._.nodes[1](); // 1 is always the root error + + const layout_loaded = /** @type {Loaded} */ ( + await load_node({ + event, + options, + state, + route: null, + node: default_layout, + $session, + stuff: {}, + is_error: false, + is_leaf: false + }) + ); + + const error_loaded = /** @type {Loaded} */ ( + await load_node({ + event, + options, + state, + route: null, + node: default_error, + $session, + stuff: layout_loaded ? layout_loaded.stuff : {}, + is_error: true, + is_leaf: false, + status, + error + }) + ); + + return await render_response({ + options, + state, + $session, + page_config: { + hydrate: options.hydrate, + router: options.router + }, + stuff: error_loaded.stuff, + status, + error, + branch: [layout_loaded, error_loaded], + event, + resolve_opts + }); + } catch (err) { + const error = coalesce_to_error(err); + + options.handle_error(error, event); + + return new Response(error.stack, { + status: 500 + }); + } +} + +/** + * @typedef {import('./types.js').Loaded} Loaded + * @typedef {import('types').SSRNode} SSRNode + * @typedef {import('types').SSROptions} SSROptions + * @typedef {import('types').SSRState} SSRState + */ + +/** + * @param {{ + * event: import('types').RequestEvent; + * options: SSROptions; + * state: SSRState; + * $session: any; + * resolve_opts: import('types').RequiredResolveOptions; + * route: import('types').SSRPage; + * }} opts + * @returns {Promise} + */ +async function respond$1(opts) { + const { event, options, state, $session, route, resolve_opts } = opts; + + /** @type {Array} */ + let nodes; + + if (!resolve_opts.ssr) { + return await render_response({ + ...opts, + branch: [], + page_config: { + hydrate: true, + router: true + }, + status: 200, + error: null, + event, + stuff: {} + }); + } + + try { + nodes = await Promise.all( + route.a.map((n) => options.manifest._.nodes[n] && options.manifest._.nodes[n]()) + ); + } catch (err) { + const error = coalesce_to_error(err); + + options.handle_error(error, event); + + return await respond_with_error({ + event, + options, + state, + $session, + status: 500, + error, + resolve_opts + }); + } + + // the leaf node will be present. only layouts may be undefined + const leaf = /** @type {SSRNode} */ (nodes[nodes.length - 1]).module; + + let page_config = get_page_config(leaf, options); + + if (state.prerender) { + // if the page isn't marked as prerenderable (or is explicitly + // marked NOT prerenderable, if `prerender.default` is `true`), + // then bail out at this point + const should_prerender = leaf.prerender ?? state.prerender.default; + if (!should_prerender) { + return new Response(undefined, { + status: 204 + }); + } + } + + /** @type {Array} */ + let branch = []; + + /** @type {number} */ + let status = 200; + + /** @type {Error | null} */ + let error = null; + + /** @type {string[]} */ + let set_cookie_headers = []; + + let stuff = {}; + + ssr: if (resolve_opts.ssr) { + for (let i = 0; i < nodes.length; i += 1) { + const node = nodes[i]; + + /** @type {Loaded | undefined} */ + let loaded; + + if (node) { + try { + loaded = await load_node({ + ...opts, + node, + stuff, + is_error: false, + is_leaf: i === nodes.length - 1 + }); + + set_cookie_headers = set_cookie_headers.concat(loaded.set_cookie_headers); + + if (loaded.loaded.redirect) { + return with_cookies( + new Response(undefined, { + status: loaded.loaded.status, + headers: { + location: loaded.loaded.redirect + } + }), + set_cookie_headers + ); + } + + if (loaded.loaded.error) { + ({ status, error } = loaded.loaded); + } + } catch (err) { + const e = coalesce_to_error(err); + + options.handle_error(e, event); + + status = 500; + error = e; + } + + if (loaded && !error) { + branch.push(loaded); + } + + if (error) { + while (i--) { + if (route.b[i]) { + const error_node = await options.manifest._.nodes[route.b[i]](); + + /** @type {Loaded} */ + let node_loaded; + let j = i; + while (!(node_loaded = branch[j])) { + j -= 1; + } + + try { + const error_loaded = /** @type {import('./types').Loaded} */ ( + await load_node({ + ...opts, + node: error_node, + stuff: node_loaded.stuff, + is_error: true, + is_leaf: false, + status, + error + }) + ); + + if (error_loaded.loaded.error) { + continue; + } + + page_config = get_page_config(error_node.module, options); + branch = branch.slice(0, j + 1).concat(error_loaded); + stuff = { ...node_loaded.stuff, ...error_loaded.stuff }; + break ssr; + } catch (err) { + const e = coalesce_to_error(err); + + options.handle_error(e, event); + + continue; + } + } + } + + // TODO backtrack until we find an __error.svelte component + // that we can use as the leaf node + // for now just return regular error page + return with_cookies( + await respond_with_error({ + event, + options, + state, + $session, + status, + error, + resolve_opts + }), + set_cookie_headers + ); + } + } + + if (loaded && loaded.loaded.stuff) { + stuff = { + ...stuff, + ...loaded.loaded.stuff + }; + } + } + } + + try { + return with_cookies( + await render_response({ + ...opts, + stuff, + event, + page_config, + status, + error, + branch: branch.filter(Boolean) + }), + set_cookie_headers + ); + } catch (err) { + const error = coalesce_to_error(err); + + options.handle_error(error, event); + + return with_cookies( + await respond_with_error({ + ...opts, + status: 500, + error + }), + set_cookie_headers + ); + } +} + +/** + * @param {import('types').SSRComponent} leaf + * @param {SSROptions} options + */ +function get_page_config(leaf, options) { + // TODO remove for 1.0 + if ('ssr' in leaf) { + throw new Error( + '`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs/hooks#handle' + ); + } + + return { + router: 'router' in leaf ? !!leaf.router : options.router, + hydrate: 'hydrate' in leaf ? !!leaf.hydrate : options.hydrate + }; +} + +/** + * @param {Response} response + * @param {string[]} set_cookie_headers + */ +function with_cookies(response, set_cookie_headers) { + if (set_cookie_headers.length) { + set_cookie_headers.forEach((value) => { + response.headers.append('set-cookie', value); + }); + } + return response; +} + +/** + * @param {import('types').RequestEvent} event + * @param {import('types').SSRPage} route + * @param {import('types').SSROptions} options + * @param {import('types').SSRState} state + * @param {import('types').RequiredResolveOptions} resolve_opts + * @returns {Promise} + */ +async function render_page(event, route, options, state, resolve_opts) { + if (state.initiator === route) { + // infinite request cycle detected + return new Response(`Not found: ${event.url.pathname}`, { + status: 404 + }); + } + + if (route.shadow) { + const type = negotiate(event.request.headers.get('accept') || 'text/html', [ + 'text/html', + 'application/json' + ]); + + if (type === 'application/json') { + return render_endpoint(event, await route.shadow()); + } + } + + const $session = await options.hooks.getSession(event); + + return respond$1({ + event, + options, + state, + $session, + resolve_opts, + route + }); +} + +/** + * @param {string} accept + * @param {string[]} types + */ +function negotiate(accept, types) { + const parts = accept + .split(',') + .map((str, i) => { + const match = /([^/]+)\/([^;]+)(?:;q=([0-9.]+))?/.exec(str); + if (match) { + const [, type, subtype, q = '1'] = match; + return { type, subtype, q: +q, i }; + } + + throw new Error(`Invalid Accept header: ${accept}`); + }) + .sort((a, b) => { + if (a.q !== b.q) { + return b.q - a.q; + } + + if ((a.subtype === '*') !== (b.subtype === '*')) { + return a.subtype === '*' ? 1 : -1; + } + + if ((a.type === '*') !== (b.type === '*')) { + return a.type === '*' ? 1 : -1; + } + + return a.i - b.i; + }); + + let accepted; + let min_priority = Infinity; + + for (const mimetype of types) { + const [type, subtype] = mimetype.split('/'); + const priority = parts.findIndex( + (part) => + (part.type === type || part.type === '*') && + (part.subtype === subtype || part.subtype === '*') + ); + + if (priority !== -1 && priority < min_priority) { + accepted = mimetype; + min_priority = priority; + } + } + + return accepted; +} + +/** + * @param {RegExpMatchArray} match + * @param {string[]} names + * @param {string[]} types + * @param {Record} matchers + */ +function exec(match, names, types, matchers) { + /** @type {Record} */ + const params = {}; + + for (let i = 0; i < names.length; i += 1) { + const name = names[i]; + const type = types[i]; + const value = match[i + 1] || ''; + + if (type) { + const matcher = matchers[type]; + if (!matcher) throw new Error(`Missing "${type}" param matcher`); // TODO do this ahead of time? + + if (!matcher(value)) return; + } + + params[name] = value; + } + + return params; +} + +const DATA_SUFFIX = '/__data.json'; + +/** @param {{ html: string }} opts */ +const default_transform = ({ html }) => html; + +/** @type {import('types').Respond} */ +async function respond(request, options, state) { + let url = new URL(request.url); + + const normalized = normalize_path(url.pathname, options.trailing_slash); + + if (normalized !== url.pathname && !state.prerender?.fallback) { + return new Response(undefined, { + status: 301, + headers: { + location: normalized + (url.search === '?' ? '' : url.search) + } + }); + } + + const { parameter, allowed } = options.method_override; + const method_override = url.searchParams.get(parameter)?.toUpperCase(); + + if (method_override) { + if (request.method === 'POST') { + if (allowed.includes(method_override)) { + request = new Proxy(request, { + get: (target, property, _receiver) => { + if (property === 'method') return method_override; + return Reflect.get(target, property, target); + } + }); + } else { + const verb = allowed.length === 0 ? 'enabled' : 'allowed'; + const body = `${parameter}=${method_override} is not ${verb}. See https://kit.svelte.dev/docs/configuration#methodoverride`; + + return new Response(body, { + status: 400 + }); + } + } else { + throw new Error(`${parameter}=${method_override} is only allowed with POST requests`); + } + } + + let decoded = decodeURI(url.pathname); + + /** @type {import('types').SSRRoute | null} */ + let route = null; + + /** @type {Record} */ + let params = {}; + + if (options.paths.base && !state.prerender?.fallback) { + if (!decoded.startsWith(options.paths.base)) { + return new Response(undefined, { status: 404 }); + } + decoded = decoded.slice(options.paths.base.length) || '/'; + } + + const is_data_request = decoded.endsWith(DATA_SUFFIX); + + if (is_data_request) { + decoded = decoded.slice(0, -DATA_SUFFIX.length) || '/'; + + const normalized = normalize_path( + url.pathname.slice(0, -DATA_SUFFIX.length), + options.trailing_slash + ); + + url = new URL(url.origin + normalized + url.search); + } + + if (!state.prerender || !state.prerender.fallback) { + const matchers = await options.manifest._.matchers(); + + for (const candidate of options.manifest._.routes) { + const match = candidate.pattern.exec(decoded); + if (!match) continue; + + const matched = exec(match, candidate.names, candidate.types, matchers); + if (matched) { + route = candidate; + params = decode_params(matched); + break; + } + } + } + + /** @type {import('types').RequestEvent} */ + const event = { + get clientAddress() { + if (!state.getClientAddress) { + throw new Error( + `${ + import.meta.env.VITE_SVELTEKIT_ADAPTER_NAME + } does not specify getClientAddress. Please raise an issue` + ); + } + + Object.defineProperty(event, 'clientAddress', { + value: state.getClientAddress() + }); + + return event.clientAddress; + }, + locals: {}, + params, + platform: state.platform, + request, + routeId: route && route.id, + url + }; + + // TODO remove this for 1.0 + /** + * @param {string} property + * @param {string} replacement + * @param {string} suffix + */ + const removed = (property, replacement, suffix = '') => ({ + get: () => { + throw new Error(`event.${property} has been replaced by event.${replacement}` + suffix); + } + }); + + const details = '. See https://github.com/sveltejs/kit/pull/3384 for details'; + + const body_getter = { + get: () => { + throw new Error( + 'To access the request body use the text/json/arrayBuffer/formData methods, e.g. `body = await request.json()`' + + details + ); + } + }; + + Object.defineProperties(event, { + method: removed('method', 'request.method', details), + headers: removed('headers', 'request.headers', details), + origin: removed('origin', 'url.origin'), + path: removed('path', 'url.pathname'), + query: removed('query', 'url.searchParams'), + body: body_getter, + rawBody: body_getter + }); + + /** @type {import('types').RequiredResolveOptions} */ + let resolve_opts = { + ssr: true, + transformPage: default_transform + }; + + // TODO match route before calling handle? + + try { + const response = await options.hooks.handle({ + event, + resolve: async (event, opts) => { + if (opts) { + resolve_opts = { + ssr: opts.ssr !== false, + transformPage: opts.transformPage || default_transform + }; + } + + if (state.prerender && state.prerender.fallback) { + return await render_response({ + event, + options, + state, + $session: await options.hooks.getSession(event), + page_config: { router: true, hydrate: true }, + stuff: {}, + status: 200, + error: null, + branch: [], + resolve_opts: { + ...resolve_opts, + ssr: false + } + }); + } + + if (route) { + /** @type {Response} */ + let response; + + if (is_data_request && route.type === 'page' && route.shadow) { + response = await render_endpoint(event, await route.shadow()); + + // loading data for a client-side transition is a special case + if (request.headers.has('x-sveltekit-load')) { + // since redirects are opaque to the browser, we need to repackage + // 3xx responses as 200s with a custom header + if (response.status >= 300 && response.status < 400) { + const location = response.headers.get('location'); + + if (location) { + const headers = new Headers(response.headers); + headers.set('x-sveltekit-location', location); + response = new Response(undefined, { + status: 204, + headers + }); + } + } + } + } else { + response = + route.type === 'endpoint' + ? await render_endpoint(event, await route.load()) + : await render_page(event, route, options, state, resolve_opts); + } + + if (response) { + // respond with 304 if etag matches + if (response.status === 200 && response.headers.has('etag')) { + let if_none_match_value = request.headers.get('if-none-match'); + + // ignore W/ prefix https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match#directives + if (if_none_match_value?.startsWith('W/"')) { + if_none_match_value = if_none_match_value.substring(2); + } + + const etag = /** @type {string} */ (response.headers.get('etag')); + + if (if_none_match_value === etag) { + const headers = new Headers({ etag }); + + // https://datatracker.ietf.org/doc/html/rfc7232#section-4.1 + for (const key of [ + 'cache-control', + 'content-location', + 'date', + 'expires', + 'vary' + ]) { + const value = response.headers.get(key); + if (value) headers.set(key, value); + } + + return new Response(undefined, { + status: 304, + headers + }); + } + } + + return response; + } + } + + // if this request came direct from the user, rather than + // via a `fetch` in a `load`, render a 404 page + if (!state.initiator) { + const $session = await options.hooks.getSession(event); + return await respond_with_error({ + event, + options, + state, + $session, + status: 404, + error: new Error(`Not found: ${event.url.pathname}`), + resolve_opts + }); + } + + if (state.prerender) { + return new Response('not found', { status: 404 }); + } + + // we can't load the endpoint from our own manifest, + // so we need to make an actual HTTP request + return await fetch(request); + }, + + // TODO remove for 1.0 + // @ts-expect-error + get request() { + throw new Error('request in handle has been replaced with event' + details); + } + }); + + // TODO for 1.0, change the error message to point to docs rather than PR + if (response && !(response instanceof Response)) { + throw new Error('handle must return a Response object' + details); + } + + return response; + } catch (/** @type {unknown} */ e) { + const error = coalesce_to_error(e); + + options.handle_error(error, event); + + try { + const $session = await options.hooks.getSession(event); + return await respond_with_error({ + event, + options, + state, + $session, + status: 500, + error, + resolve_opts + }); + } catch (/** @type {unknown} */ e) { + const error = coalesce_to_error(e); + + return new Response(options.dev ? error.stack : error.message, { + status: 500 + }); + } + } +} + +export { respond }; diff --git a/.svelte-kit/tsconfig.json b/.svelte-kit/tsconfig.json new file mode 100644 index 0000000..d5c53a9 --- /dev/null +++ b/.svelte-kit/tsconfig.json @@ -0,0 +1,43 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "module": "es2020", + "lib": [ + "es2020", + "DOM" + ], + "target": "es2020", + "importsNotUsedAsValues": "error", + "preserveValueImports": true, + "isolatedModules": true, + "resolveJsonModule": true, + "sourceMap": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": "..", + "allowJs": true, + "checkJs": true, + "paths": { + "$lib": [ + "src/lib" + ], + "$lib/*": [ + "src/lib/*" + ] + }, + "rootDirs": [ + "..", + "./types" + ] + }, + "include": [ + "../src/**/*.js", + "../src/**/*.ts", + "../src/**/*.svelte" + ], + "exclude": [ + "../node_modules/**", + "./**" + ] +} \ No newline at end of file diff --git a/.svelte-kit/types/src/routes/__layout.d.ts b/.svelte-kit/types/src/routes/__layout.d.ts new file mode 100644 index 0000000..16e375e --- /dev/null +++ b/.svelte-kit/types/src/routes/__layout.d.ts @@ -0,0 +1,7 @@ +// this file is auto-generated +import type { Load as GenericLoad } from '@sveltejs/kit'; + +export type Load< + InputProps extends Record = Record, + OutputProps extends Record = InputProps +> = GenericLoad<{}, InputProps, OutputProps>; \ No newline at end of file diff --git a/.svelte-kit/types/src/routes/index.d.ts b/.svelte-kit/types/src/routes/index.d.ts new file mode 100644 index 0000000..16e375e --- /dev/null +++ b/.svelte-kit/types/src/routes/index.d.ts @@ -0,0 +1,7 @@ +// this file is auto-generated +import type { Load as GenericLoad } from '@sveltejs/kit'; + +export type Load< + InputProps extends Record = Record, + OutputProps extends Record = InputProps +> = GenericLoad<{}, InputProps, OutputProps>; \ No newline at end of file diff --git a/README.md b/README.md index 69699d6..94a48f5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,40 @@ -# Nashboard: a Nostr network dashboard -Firstly, I want to say thank you to relay operators. Without them, the Nostr network wouldn't run and this site wouldn't exist. +# create-svelte -This small site displays basic statistics about the Nostr network - the events, the relays, the timestamps. You can think of it as the dashboard of the entire network. Visit: [nashboard.netlify.app](https://nashboard.netlify.app/). \ No newline at end of file +Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npm init svelte@next + +# create a new project in my-app +npm init svelte@next my-app +``` + +> Note: the `@next` is temporary + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..81ff977 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.svelte-kit/tsconfig.json" +} diff --git a/package.json b/package.json index 9245bca..f8ef13f 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,29 @@ { - "name": "nashboard", - "version": "0.0.1", - "private": true, - "scripts": { - "watch": "postcss public/tailwind.css -o public/app.css -w", - "build": "rollup -c", - "dev": "rollup -c -w", - "start": "sirv public --no-clear" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^17.0.0", - "@rollup/plugin-node-resolve": "^11.0.0", - "autoprefixer": "^10.4.2", - "postcss-cli": "^9.1.0", - "rollup": "^2.3.4", - "rollup-plugin-css-only": "^3.1.0", - "rollup-plugin-livereload": "^2.0.0", - "rollup-plugin-svelte": "^7.0.0", - "rollup-plugin-terser": "^7.0.0", - "svelte": "^3.0.0", - "tailwindcss": "^3.0.23" - }, - "dependencies": { - "sirv-cli": "^2.0.0", - "svelte-chartjs": "^1.1.4", - "timeago.js": "^4.0.2", - "underscore": "^1.13.2" - } + "name": "nashboard-sveltekit", + "version": "0.0.1", + "scripts": { + "dev": "svelte-kit dev", + "build": "svelte-kit build", + "package": "svelte-kit package", + "preview": "svelte-kit preview", + "prepare": "svelte-kit sync", + "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", + "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ." + }, + "devDependencies": { + "@sveltejs/adapter-auto": "next", + "@sveltejs/kit": "next", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-svelte3": "^3.2.1", + "prettier": "^2.5.1", + "prettier-plugin-svelte": "^2.5.0", + "svelte": "^3.44.0", + "postcss": "^8.4.5", + "postcss-load-config": "^3.1.1", + "svelte-preprocess": "^4.10.1", + "autoprefixer": "^10.4.2", + "tailwindcss": "^3.0.12" + }, + "type": "module" } diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 0000000..fe10e55 --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,13 @@ +const tailwindcss = require('tailwindcss'); +const autoprefixer = require('autoprefixer'); + +const config = { + plugins: [ + //Some plugins, like tailwindcss/nesting, need to run before Tailwind, + tailwindcss(), + //But others, like autoprefixer, need to run after, + autoprefixer + ] +}; + +module.exports = config; diff --git a/postcss.config.js b/postcss.config.js deleted file mode 100644 index e2dc478..0000000 --- a/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - } -} \ No newline at end of file diff --git a/public/app.css b/public/app.css deleted file mode 100644 index 7805bc5..0000000 --- a/public/app.css +++ /dev/null @@ -1,583 +0,0 @@ -/* -! tailwindcss v3.0.23 | MIT License | https://tailwindcss.com -*//* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ - -*, -::before, -::after { - box-sizing: border-box; /* 1 */ - border-width: 0; /* 2 */ - border-style: solid; /* 2 */ - border-color: #e5e7eb; /* 2 */ -} - -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -*/ - -html { - line-height: 1.5; /* 1 */ - -webkit-text-size-adjust: 100%; /* 2 */ - -moz-tab-size: 4; /* 3 */ - -o-tab-size: 4; - tab-size: 4; /* 3 */ - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - -body { - margin: 0; /* 1 */ - line-height: inherit; /* 2 */ -} - -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; /* 1 */ - color: inherit; /* 2 */ - border-top-width: 1px; /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font family by default. -2. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; /* 1 */ - border-color: inherit; /* 2 */ - border-collapse: collapse; /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - line-height: inherit; /* 1 */ - color: inherit; /* 1 */ - margin: 0; /* 2 */ - padding: 0; /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -[type='button'], -[type='reset'], -[type='submit'] { - -webkit-appearance: button; /* 1 */ - background-color: transparent; /* 2 */ - background-image: none; /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; /* 1 */ - color: #9ca3af; /* 2 */ -} - -input:-ms-input-placeholder, textarea:-ms-input-placeholder { - opacity: 1; /* 1 */ - color: #9ca3af; /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; /* 1 */ - color: #9ca3af; /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; /* 1 */ - vertical-align: middle; /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -/* -Ensure the default browser behavior of the `hidden` attribute. -*/ - -[hidden] { - display: none; -} - -*, ::before, ::after { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} -.mx-auto { - margin-left: auto; - margin-right: auto; -} -.my-5 { - margin-top: 1.25rem; - margin-bottom: 1.25rem; -} -.my-1 { - margin-top: 0.25rem; - margin-bottom: 0.25rem; -} -.mr-3 { - margin-right: 0.75rem; -} -.mb-2 { - margin-bottom: 0.5rem; -} -.block { - display: block; -} -.flex { - display: flex; -} -.max-w-3xl { - max-width: 48rem; -} -.flex-1 { - flex: 1 1 0%; -} -.shrink { - flex-shrink: 1; -} -.flex-col { - flex-direction: column; -} -.justify-between { - justify-content: space-between; -} -.space-y-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); -} -.self-start { - align-self: flex-start; -} -.break-words { - overflow-wrap: break-word; -} -.rounded-md { - border-radius: 0.375rem; -} -.border-l-4 { - border-left-width: 4px; -} -.border-slate-800 { - --tw-border-opacity: 1; - border-color: rgb(30 41 59 / var(--tw-border-opacity)); -} -.bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} -.bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); -} -.from-pink-100 { - --tw-gradient-from: #fce7f3; - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgb(252 231 243 / 0)); -} -.to-orange-200 { - --tw-gradient-to: #fed7aa; -} -.p-3 { - padding: 0.75rem; -} -.p-2 { - padding: 0.5rem; -} -.px-4 { - padding-left: 1rem; - padding-right: 1rem; -} -.pb-3 { - padding-bottom: 0.75rem; -} -.pl-3 { - padding-left: 0.75rem; -} -.text-center { - text-align: center; -} -.font-mono { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} -.text-sm { - font-size: 0.875rem; - line-height: 1.25rem; -} -.text-2xl { - font-size: 1.5rem; - line-height: 2rem; -} -.text-neutral-400 { - --tw-text-opacity: 1; - color: rgb(163 163 163 / var(--tw-text-opacity)); -} -.text-neutral-500 { - --tw-text-opacity: 1; - color: rgb(115 115 115 / var(--tw-text-opacity)); -} -.text-orange-700 { - --tw-text-opacity: 1; - color: rgb(194 65 12 / var(--tw-text-opacity)); -} -.text-neutral-600 { - --tw-text-opacity: 1; - color: rgb(82 82 82 / var(--tw-text-opacity)); -} -.underline { - -webkit-text-decoration-line: underline; - text-decoration-line: underline; -} -.shadow { - --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} -@media (min-width: 640px) { - - .sm\:flex { - display: flex; - } - - .sm\:w-1\/2 { - width: 50%; - } - - .sm\:space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - } - - .sm\:space-y-0 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0px * var(--tw-space-y-reverse)); - } - - .sm\:space-y-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1rem * var(--tw-space-y-reverse)); - } -} \ No newline at end of file diff --git a/public/global.css b/public/global.css deleted file mode 100644 index e69de29..0000000 diff --git a/public/index.html b/public/index.html deleted file mode 100644 index c531ab7..0000000 --- a/public/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - Nashboard - - - - - - - - - - - - diff --git a/public/tailwind.css b/public/tailwind.css deleted file mode 100644 index bd6213e..0000000 --- a/public/tailwind.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index e8965ec..0000000 --- a/rollup.config.js +++ /dev/null @@ -1,76 +0,0 @@ -import svelte from 'rollup-plugin-svelte'; -import commonjs from '@rollup/plugin-commonjs'; -import resolve from '@rollup/plugin-node-resolve'; -import livereload from 'rollup-plugin-livereload'; -import { terser } from 'rollup-plugin-terser'; -import css from 'rollup-plugin-css-only'; - -const production = !process.env.ROLLUP_WATCH; - -function serve() { - let server; - - function toExit() { - if (server) server.kill(0); - } - - return { - writeBundle() { - if (server) return; - server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { - stdio: ['ignore', 'inherit', 'inherit'], - shell: true - }); - - process.on('SIGTERM', toExit); - process.on('exit', toExit); - } - }; -} - -export default { - input: 'src/main.js', - output: { - sourcemap: true, - format: 'iife', - name: 'app', - file: 'public/build/bundle.js' - }, - plugins: [ - svelte({ - compilerOptions: { - // enable run-time checks when not in production - dev: !production - } - }), - // we'll extract any component CSS out into - // a separate file - better for performance - css({ output: 'bundle.css' }), - - // If you have external dependencies installed from - // npm, you'll most likely need these plugins. In - // some cases you'll need additional configuration - - // consult the documentation for details: - // https://github.com/rollup/plugins/tree/master/packages/commonjs - resolve({ - browser: true, - dedupe: ['svelte'] - }), - commonjs(), - - // In dev mode, call `npm run start` once - // the bundle has been generated - !production && serve(), - - // Watch the `public` directory and refresh the - // browser on changes when not in production - !production && livereload('public'), - - // If we're building for production (npm run build - // instead of npm run dev), minify - production && terser() - ], - watch: { - clearScreen: false - } -}; diff --git a/scripts/setupTypeScript.js b/scripts/setupTypeScript.js deleted file mode 100644 index 133658a..0000000 --- a/scripts/setupTypeScript.js +++ /dev/null @@ -1,121 +0,0 @@ -// @ts-check - -/** This script modifies the project to support TS code in .svelte files like: - - - - As well as validating the code for CI. - */ - -/** To work on this script: - rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template -*/ - -const fs = require("fs") -const path = require("path") -const { argv } = require("process") - -const projectRoot = argv[2] || path.join(__dirname, "..") - -// Add deps to pkg.json -const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8")) -packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, { - "svelte-check": "^2.0.0", - "svelte-preprocess": "^4.0.0", - "@rollup/plugin-typescript": "^8.0.0", - "typescript": "^4.0.0", - "tslib": "^2.0.0", - "@tsconfig/svelte": "^2.0.0" -}) - -// Add script for checking -packageJSON.scripts = Object.assign(packageJSON.scripts, { - "check": "svelte-check --tsconfig ./tsconfig.json" -}) - -// Write the package JSON -fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " ")) - -// mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too -const beforeMainJSPath = path.join(projectRoot, "src", "main.js") -const afterMainTSPath = path.join(projectRoot, "src", "main.ts") -fs.renameSync(beforeMainJSPath, afterMainTSPath) - -// Switch the app.svelte file to use TS -const appSveltePath = path.join(projectRoot, "src", "App.svelte") -let appFile = fs.readFileSync(appSveltePath, "utf8") -appFile = appFile.replace(" - -
- NETWORK ACTIVITY (24H, UTC) -
-
- {#each timeArrFirst as time, i} -
- {time} - {networkActivity[i]} evt -
- {/each} -
-
- {#each timeArrSecond as time, i} -
- {time} - {networkActivity[i + 12]} evt -
- {/each} -
-
-
diff --git a/src/App.svelte b/src/App.svelte deleted file mode 100644 index 3fbbe01..0000000 --- a/src/App.svelte +++ /dev/null @@ -1,160 +0,0 @@ - - -
-
-
- - - -
- EVENT TYPES (24H) - -
- - - -
- -
- NOSTR NETWORK'S LATEST EVENTS -
- {#each tweets as tweet} - - {/each} -
-
-
-
diff --git a/src/Count.svelte b/src/Count.svelte deleted file mode 100644 index c896aad..0000000 --- a/src/Count.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - -
- NOSTR NETWORK'S EVENT COUNT -
-
- {eventCount1h} - last 1h -
-
- {eventCount24h} - last 24h -
-
-
diff --git a/src/Dots.svelte b/src/Dots.svelte deleted file mode 100644 index eaddb01..0000000 --- a/src/Dots.svelte +++ /dev/null @@ -1,6 +0,0 @@ - -
-
-
· · ·
-
-
\ No newline at end of file diff --git a/src/Kind.svelte b/src/Kind.svelte deleted file mode 100644 index bc6b331..0000000 --- a/src/Kind.svelte +++ /dev/null @@ -1,37 +0,0 @@ - - -
- EVENT TYPES (24H) - -
diff --git a/src/Relay.svelte b/src/Relay.svelte deleted file mode 100644 index 2a5418d..0000000 --- a/src/Relay.svelte +++ /dev/null @@ -1,21 +0,0 @@ - - -
diff --git a/src/Tweet.svelte b/src/Tweet.svelte deleted file mode 100644 index bd8948c..0000000 --- a/src/Tweet.svelte +++ /dev/null @@ -1,24 +0,0 @@ - - -
-
- {pubkey.slice(0, 5) + '...' + pubkey.slice(-5)} - {format(time + '000', 'en_short')} -
- {#if replied} -
-
- {replied.pubkey} -
-
-
{replied.message}
-
- {/if} -
{message}
-
diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..1a7b7cf --- /dev/null +++ b/src/app.css @@ -0,0 +1,4 @@ +/* Write your global styles here, in PostCSS syntax */ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/src/app.d.ts b/src/app.d.ts new file mode 100644 index 0000000..9cbf1c5 --- /dev/null +++ b/src/app.d.ts @@ -0,0 +1,10 @@ +/// + +// See https://kit.svelte.dev/docs/types#the-app-namespace +// for information about these interfaces +declare namespace App { + // interface Locals {} + // interface Platform {} + // interface Session {} + // interface Stuff {} +} diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..d8ed254 --- /dev/null +++ b/src/app.html @@ -0,0 +1,13 @@ + + + + + + + + %svelte.head% + + +
%svelte.body%
+ + diff --git a/src/main.js b/src/main.js deleted file mode 100644 index d6cacbb..0000000 --- a/src/main.js +++ /dev/null @@ -1,10 +0,0 @@ -import App from './App.svelte'; - -const app = new App({ - target: document.body, - props: { - name: 'world' - } -}); - -export default app; \ No newline at end of file diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte new file mode 100644 index 0000000..2e511e0 --- /dev/null +++ b/src/routes/__layout.svelte @@ -0,0 +1,5 @@ + + + diff --git a/src/routes/index.svelte b/src/routes/index.svelte new file mode 100644 index 0000000..8bbb635 --- /dev/null +++ b/src/routes/index.svelte @@ -0,0 +1,4 @@ +

Welcome to SvelteKit

+

Visit kit.svelte.dev to read the documentation

+ +

hello from branch

diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH= 1.2.0" - ws "^7.4.3" - -local-access@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/local-access/-/local-access-1.1.0.tgz#e007c76ba2ca83d5877ba1a125fc8dfe23ba4798" - integrity sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw== + yallist "^4.0.0" magic-string@^0.25.7: - version "0.25.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" - integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== dependencies: - sourcemap-codec "^1.4.4" + sourcemap-codec "^1.4.8" -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +magic-string@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.1.tgz#ba9b651354fa9512474199acecf9c6dbe93f97fd" + integrity sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg== + dependencies: + sourcemap-codec "^1.4.8" -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -737,6 +1088,11 @@ micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + minimatch@^3.0.4: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -744,26 +1100,38 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.1.1: +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + mri@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== -mrmime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b" - integrity sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ== +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -nanoid@^3.2.0: +nanoid@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + node-releases@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" @@ -791,10 +1159,17 @@ once@^1.3.0: dependencies: wrappy "1" -"opts@>= 1.2.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1" - integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg== +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" parent-module@^1.0.0: version "1.0.1" @@ -818,6 +1193,11 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -838,29 +1218,6 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -postcss-cli@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/postcss-cli/-/postcss-cli-9.1.0.tgz#1a86404cbe848e370127b4bdf5cd2be83bc45ebe" - integrity sha512-zvDN2ADbWfza42sAnj+O2uUWyL0eRL1V+6giM2vi4SqTR3gTYy8XzcpfwccayF2szcUif0HMmXiEaDv9iEhcpw== - dependencies: - chokidar "^3.3.0" - dependency-graph "^0.11.0" - fs-extra "^10.0.0" - get-stdin "^9.0.0" - globby "^12.0.0" - picocolors "^1.0.0" - postcss-load-config "^3.0.0" - postcss-reporter "^7.0.0" - pretty-hrtime "^1.0.3" - read-cache "^1.0.0" - slash "^4.0.0" - yargs "^17.0.0" - postcss-js@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" @@ -868,7 +1225,7 @@ postcss-js@^4.0.0: dependencies: camelcase-css "^2.0.1" -postcss-load-config@^3.0.0, postcss-load-config@^3.1.0: +postcss-load-config@^3.1.0, postcss-load-config@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.3.tgz#21935b2c43b9a86e6581a576ca7ee1bde2bd1d23" integrity sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw== @@ -883,14 +1240,6 @@ postcss-nested@5.0.6: dependencies: postcss-selector-parser "^6.0.6" -postcss-reporter@^7.0.0: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-7.0.5.tgz#e55bd0fdf8d17e4f25fb55e9143fcd79349a2ceb" - integrity sha512-glWg7VZBilooZGOFPhN9msJ3FQs19Hie7l5a/eE6WglzYqVeH3ong3ShFcp9kDWJT1g2Y/wd59cocf9XxBtkWA== - dependencies: - picocolors "^1.0.0" - thenby "^1.3.4" - postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9: version "6.0.9" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" @@ -904,19 +1253,39 @@ postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.6: - version "8.4.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1" - integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA== +postcss@^8.4.5, postcss@^8.4.6: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== dependencies: - nanoid "^3.2.0" + nanoid "^3.3.1" picocolors "^1.0.0" source-map-js "^1.0.2" -pretty-hrtime@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" - integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-plugin-svelte@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-2.6.0.tgz#0e845b560b55cd1d951d6c50431b4949f8591746" + integrity sha512-NPSRf6Y5rufRlBleok/pqg4+1FyGsL0zYhkYP6hnueeL1J/uCm3OfOZPsLX4zqD9VAdcXfyEL2PYqGv8ZoOSfA== + +prettier@^2.5.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.0.tgz#12f8f504c4d8ddb76475f441337542fa799207d4" + integrity sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== queue-microtask@^1.2.2: version "1.2.3" @@ -928,20 +1297,6 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -read-cache@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" - integrity sha1-5mTvMRYRZsl1HNvo28+GtftY93Q= - dependencies: - pify "^2.3.0" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -949,22 +1304,22 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -require-relative@^0.8.7: - version "0.8.7" - resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" - integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.17.0, resolve@^1.19.0, resolve@^1.22.0: +resolve@^1.22.0: version "1.22.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== @@ -978,49 +1333,24 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rollup-plugin-css-only@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-css-only/-/rollup-plugin-css-only-3.1.0.tgz#6a701cc5b051c6b3f0961e69b108a9a118e1b1df" - integrity sha512-TYMOE5uoD76vpj+RTkQLzC9cQtbnJNktHPB507FzRWBVaofg7KhIqq1kGbcVOadARSozWF883Ho9KpSPKH8gqA== +rimraf@^2.5.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: - "@rollup/pluginutils" "4" + glob "^7.1.3" -rollup-plugin-livereload@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.5.tgz#4747fa292a2cceb0c972c573d71b3d66b4252b37" - integrity sha512-vqQZ/UQowTW7VoiKEM5ouNW90wE5/GZLfdWuR0ELxyKOJUIaj+uismPZZaICU4DnWPVjnpCDDxEqwU7pcKY/PA== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: - livereload "^0.9.1" + glob "^7.1.3" -rollup-plugin-svelte@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.0.tgz#d45f2b92b1014be4eb46b55aa033fb9a9c65f04d" - integrity sha512-vopCUq3G+25sKjwF5VilIbiY6KCuMNHP1PFvx2Vr3REBNMDllKHFZN2B9jwwC+MqNc3UPKkjXnceLPEjTjXGXg== - dependencies: - require-relative "^0.8.7" - rollup-pluginutils "^2.8.2" - -rollup-plugin-terser@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" - integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== - dependencies: - "@babel/code-frame" "^7.10.4" - jest-worker "^26.2.1" - serialize-javascript "^4.0.0" - terser "^5.0.0" - -rollup-pluginutils@^2.8.2: - version "2.8.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" - integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== - dependencies: - estree-walker "^0.6.1" - -rollup@^2.3.4: - version "2.68.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.68.0.tgz#6ccabfd649447f8f21d62bf41662e5caece3bd66" - integrity sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA== +rollup@^2.59.0: + version "2.70.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.1.tgz#824b1f1f879ea396db30b0fc3ae8d2fead93523e" + integrity sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA== optionalDependencies: fsevents "~2.3.2" @@ -1031,87 +1361,77 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -sade@^1.6.0: +sade@^1.7.4: version "1.8.1" resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== dependencies: mri "^1.1.0" -safe-buffer@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +sander@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/sander/-/sander-0.5.1.tgz#741e245e231f07cafb6fdf0f133adfa216a502ad" + integrity sha1-dB4kXiMfB8r7b98PEzrfohalAq0= + dependencies: + es6-promise "^3.1.2" + graceful-fs "^4.1.3" + mkdirp "^0.5.1" + rimraf "^2.5.2" -semiver@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semiver/-/semiver-1.1.0.tgz#9c97fb02c21c7ce4fcf1b73e2c7a24324bdddd5f" - integrity sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg== +semver@^7.2.1: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" -serialize-javascript@^4.0.0: +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +slice-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: - randombytes "^2.1.0" + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" -sirv-cli@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/sirv-cli/-/sirv-cli-2.0.2.tgz#4b25ff8dc577be41588357c1f87fbf264a1bba55" - integrity sha512-OtSJDwxsF1NWHc7ps3Sa0s+dPtP15iQNJzfKVz+MxkEo3z72mCD+yu30ct79rPr0CaV1HXSOBp+MIY5uIhHZ1A== +sorcery@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/sorcery/-/sorcery-0.10.0.tgz#8ae90ad7d7cb05fc59f1ab0c637845d5c15a52b7" + integrity sha1-iukK19fLBfxZ8asMY3hF1cFaUrc= dependencies: - console-clear "^1.1.0" - get-port "^3.2.0" - kleur "^4.1.4" - local-access "^1.0.1" - sade "^1.6.0" - semiver "^1.0.0" - sirv "^2.0.0" - tinydate "^1.0.0" - -sirv@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.2.tgz#128b9a628d77568139cff85703ad5497c46a4760" - integrity sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w== - dependencies: - "@polka/url" "^1.0.0-next.20" - mrmime "^1.0.0" - totalist "^3.0.0" - -slash@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" - integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== + buffer-crc32 "^0.2.5" + minimist "^1.2.0" + sander "^0.5.0" + sourcemap-codec "^1.3.0" source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -sourcemap-codec@^1.4.4: +sourcemap-codec@^1.3.0, sourcemap-codec@^1.4.8: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -1127,6 +1447,18 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -1134,7 +1466,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -1146,19 +1478,40 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -svelte-chartjs@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/svelte-chartjs/-/svelte-chartjs-1.1.4.tgz#468868aec8a2469ba3480628f77c81ae992ac2de" - integrity sha512-G+G3h1yDFKNTamwq1iDSK1nthStVpEKaCh8K17cUlMPRX1bFF14sK2kWNv0tPj+OGWDTJgDM3X18EU0o3/kH5Q== - dependencies: - chart.js "^3.5.0" +svelte-hmr@^0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.11.tgz#63d532dc9c2c849ab708592f034765fa2502e568" + integrity sha512-R9CVfX6DXxW1Kn45Jtmx+yUe+sPhrbYSUp7TkzbW0jI5fVPn6lsNG9NEs5dFg5qRhFNAoVdRw5qQDLALNKhwbQ== -svelte@^3.0.0: +svelte-preprocess@^4.10.1: + version "4.10.4" + resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-4.10.4.tgz#308a410266bfc55b4e608da8d552b63580141260" + integrity sha512-fuwol0N4UoHsNQolLFbMqWivqcJ9N0vfWO9IuPAiX/5okfoGXURyJ6nECbuEIv0nU3M8Xe2I1ONNje2buk7l6A== + dependencies: + "@types/pug" "^2.0.4" + "@types/sass" "^1.16.0" + detect-indent "^6.0.0" + magic-string "^0.25.7" + sorcery "^0.10.0" + strip-indent "^3.0.0" + +svelte@^3.44.0: version "3.46.4" resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.46.4.tgz#0c46bc4a3e20a2617a1b7dc43a722f9d6c084a38" integrity sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg== -tailwindcss@^3.0.23: +table@^6.0.9: + version "6.8.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" + integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +tailwindcss@^3.0.12: version "3.0.23" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.23.tgz#c620521d53a289650872a66adfcb4129d2200d10" integrity sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA== @@ -1185,30 +1538,18 @@ tailwindcss@^3.0.23: quick-lru "^5.1.1" resolve "^1.22.0" -terser@^5.0.0: - version "5.11.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.11.0.tgz#2da5506c02e12cd8799947f30ce9c5b760be000f" - integrity sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A== +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +tiny-glob@^0.2.9: + version "0.2.9" + resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.9.tgz#2212d441ac17928033b110f8b3640683129d31e2" + integrity sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg== dependencies: - acorn "^8.5.0" - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.20" - -thenby@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/thenby/-/thenby-1.3.4.tgz#81581f6e1bb324c6dedeae9bfc28e59b1a2201cc" - integrity sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ== - -timeago.js@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-4.0.2.tgz#724e8c8833e3490676c7bb0a75f5daf20e558028" - integrity sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w== - -tinydate@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/tinydate/-/tinydate-1.3.0.tgz#e6ca8e5a22b51bb4ea1c3a2a4fd1352dbd4c57fb" - integrity sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w== + globalyzer "0.1.0" + globrex "^0.1.2" to-regex-range@^5.0.1: version "5.0.1" @@ -1217,74 +1558,75 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -totalist@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.0.tgz#4ef9c58c5f095255cdc3ff2a0a55091c57a3a1bd" - integrity sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" -underscore@^1.13.2: - version "1.13.2" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.2.tgz#276cea1e8b9722a8dbed0100a407dda572125881" - integrity sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +vite@^2.8.0: + version "2.8.6" + resolved "https://registry.yarnpkg.com/vite/-/vite-2.8.6.tgz#32d50e23c99ca31b26b8ccdc78b1d72d4d7323d3" + integrity sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug== dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" + esbuild "^0.14.14" + postcss "^8.4.6" + resolve "^1.22.0" + rollup "^2.59.0" + optionalDependencies: + fsevents "~2.3.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@^7.4.3: - version "7.5.7" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" - integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== - xtend@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yargs-parser@^21.0.0: - version "21.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" - integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== - -yargs@^17.0.0: - version "17.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" - integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.0.0"