Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.

This commit is contained in:
becarta
2025-05-23 12:43:00 +02:00
parent f40db0f5c9
commit a544759a3b
11127 changed files with 1647032 additions and 0 deletions

59
node_modules/astro/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,59 @@
MIT License
Copyright (c) 2021 Fred K. Schott
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.
"""
This license applies to parts of the `packages/create-astro` and `packages/astro` subdirectories originating from the https://github.com/sveltejs/kit repository:
Copyright (c) 2020 [these people](https://github.com/sveltejs/kit/graphs/contributors)
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.
"""
"""
This license applies to parts of the `packages/create-astro` and `packages/astro` subdirectories originating from the https://github.com/vitejs/vite repository:
MIT License
Copyright (c) 2019-present, Yuxi (Evan) You and Vite contributors
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.
"""

43
node_modules/astro/README.md generated vendored Normal file
View File

@@ -0,0 +1,43 @@
<br/>
<p align="center">
<img src="../../.github/assets/banner.jpg" alt="Build the web you want">
<br/><br/>
<a href="https://astro.build">Astro</a> is the all-in-one web framework designed for speed.
<br/>
Pull your content from anywhere and deploy everywhere, all powered by your favorite UI components and libraries.
<br/><br/>
</p>
## Install
```bash
# Recommended!
npm create astro@latest
# Manual:
npm install --save-dev astro
```
Looking for help? Start with our [Getting Started](https://docs.astro.build/en/getting-started/) guide.
Looking for quick examples? [Open a starter project](https://astro.new/) right in your browser.
## Documentation
Visit our [official documentation](https://docs.astro.build/).
## Support
Having trouble? Get help in the official [Astro Discord](https://astro.build/chat).
## Contributing
**New contributors welcome!** Check out our [Contributors Guide](/CONTRIBUTING.md) for help getting started.
Join us on [Discord](https://astro.build/chat) to meet other contributors. We'll help you get your first contribution in no time!
## Sponsors
Astro is generously supported by [Vercel](https://vercel.com/), [storyblok](https://storyblok.com/), and several other amazing organizations [listed here.](https://opencollective.com/astrodotbuild)
[❤️ Sponsor Astro! ❤️](https://github.com/withastro/.github/blob/main/FUNDING.md)

1535
node_modules/astro/astro-jsx.d.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

83
node_modules/astro/astro.js generated vendored Executable file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/env node
'use strict';
// ISOMORPHIC FILE: NO TOP-LEVEL IMPORT/REQUIRE() ALLOWED
// This file has to run as both ESM and CJS on older Node.js versions
const CI_INSTRUCTIONS = {
NETLIFY: 'https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-and-javascript',
GITHUB_ACTIONS:
'https://docs.github.com/en/actions/guides/building-and-testing-nodejs#specifying-the-nodejs-version',
VERCEL: 'https://vercel.com/docs/runtimes#official-runtimes/node-js/node-js-version',
};
// Hardcode supported Node.js version so we don't have to read differently in CJS & ESM.
const engines = '>=18.14.1';
const skipSemverCheckIfAbove = 19;
/** `astro *` */
async function main() {
const version = process.versions.node;
// Fast-path for higher Node.js versions
if ((parseInt(version) || 0) <= skipSemverCheckIfAbove) {
const semver = await import('semver');
try {
if (!semver.satisfies(version, engines)) {
await errorNodeUnsupported();
return;
}
} catch {
await errorNodeUnsupported();
return;
}
}
// windows drive letters can sometimes be lowercase, which vite cannot process
if (process.platform === 'win32') {
const cwd = process.cwd();
const correctedCwd = cwd.slice(0, 1).toUpperCase() + cwd.slice(1);
if (correctedCwd !== cwd) process.chdir(correctedCwd);
}
return import('./dist/cli/index.js')
.then(({ cli }) => cli(process.argv))
.catch((error) => {
console.error(error);
process.exit(1);
});
}
async function errorNodeUnsupported() {
console.error(`\
Node.js v${process.versions.node} is not supported by Astro!
Please upgrade Node.js to a supported version: "${engines}"\n`);
// eslint-disable-next-line @typescript-eslint/no-require-imports
const ci = typeof require !== 'undefined' ? require('ci-info') : await import('ci-info');
// Special instructions for CI environments, which may have special steps needed.
// This is a common issue that we can help users with proactively.
if (ci.isCI) {
let platform;
for (const [key, value] of Object.entries(ci)) {
if (value === true) {
platform = key;
break;
}
}
console.log(
`${ci.name} CI Environment Detected!\nAdditional steps may be needed to set your Node.js version:`,
);
console.log(`Documentation: https://docs.astro.build/en/guides/deploy/`);
if (CI_INSTRUCTIONS[platform]) {
console.log(`${ci.name} Documentation: ${CI_INSTRUCTIONS[platform]}`);
}
console.log(``);
}
process.exit(1);
}
main()
.then(() => process.exit(0))
.catch(() => process.exit(1));

524
node_modules/astro/client.d.ts generated vendored Normal file
View File

@@ -0,0 +1,524 @@
/// <reference types="vite/types/import-meta.d.ts" />
/// <reference path="./types/content.d.ts" />
/// <reference path="./types/actions.d.ts" />
// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace App {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Locals {}
}
interface ImportMetaEnv {
/**
* The prefix for Astro-generated asset links if the build.assetsPrefix config option is set. This can be used to create asset links not handled by Astro.
*/
readonly ASSETS_PREFIX: string | Record<string, string>;
/**
* This is set to the site option specified in your projects Astro config file.
*/
readonly SITE: string;
}
interface ImportMeta {
/**
* Astro and Vite expose environment variables through `import.meta.env`. For a complete list of the environment variables available, see the two references below.
*
* - [Astro reference](https://docs.astro.build/en/guides/environment-variables/#default-environment-variables)
* - [Vite reference](https://vite.dev/guide/env-and-mode.html#env-variables)
*/
readonly env: ImportMetaEnv;
}
declare module 'astro:assets' {
// Exporting things one by one is a bit cumbersome, not sure if there's a better way - erika, 2023-02-03
type AstroAssets = {
// getImage's type here is different from the internal function since the Vite module implicitly pass the service config
/**
* Get an optimized image and the necessary attributes to render it.
*
* **Example**
* ```astro
* ---
* import { getImage } from 'astro:assets';
* import originalImage from '../assets/image.png';
*
* const optimizedImage = await getImage({src: originalImage, width: 1280 });
* ---
* <img src={optimizedImage.src} {...optimizedImage.attributes} />
* ```
*
* This is functionally equivalent to using the `<Image />` component, as the component calls this function internally.
*/
getImage: (
options: import('./dist/assets/types.js').UnresolvedImageTransform,
) => Promise<import('./dist/assets/types.js').GetImageResult>;
imageConfig: import('./dist/@types/astro.js').AstroConfig['image'];
getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
inferRemoteSize: typeof import('./dist/assets/utils/index.js').inferRemoteSize;
Image: typeof import('./components/Image.astro').default;
Picture: typeof import('./components/Picture.astro').default;
};
type ImgAttributes = import('./dist/type-utils.js').WithRequired<
Omit<import('./types').HTMLAttributes<'img'>, 'src' | 'width' | 'height'>,
'alt'
>;
export type LocalImageProps = import('./dist/type-utils.js').Simplify<
import('./dist/assets/types.js').LocalImageProps<ImgAttributes>
>;
export type RemoteImageProps = import('./dist/type-utils.js').Simplify<
import('./dist/assets/types.js').RemoteImageProps<ImgAttributes>
>;
export const {
getImage,
getConfiguredImageService,
imageConfig,
Image,
Picture,
inferRemoteSize,
}: AstroAssets;
}
type ImageMetadata = import('./dist/assets/types.js').ImageMetadata;
declare module '*.gif' {
const metadata: ImageMetadata;
export default metadata;
}
declare module '*.jpeg' {
const metadata: ImageMetadata;
export default metadata;
}
declare module '*.jpg' {
const metadata: ImageMetadata;
export default metadata;
}
declare module '*.png' {
const metadata: ImageMetadata;
export default metadata;
}
declare module '*.tiff' {
const metadata: ImageMetadata;
export default metadata;
}
declare module '*.webp' {
const metadata: ImageMetadata;
export default metadata;
}
declare module '*.svg' {
const metadata: ImageMetadata;
export default metadata;
}
declare module '*.avif' {
const metadata: ImageMetadata;
export default metadata;
}
declare module 'astro:transitions' {
type TransitionModule = typeof import('./dist/virtual-modules/transitions.js');
export const slide: TransitionModule['slide'];
export const fade: TransitionModule['fade'];
export const createAnimationScope: TransitionModule['createAnimationScope'];
type ViewTransitionsModule = typeof import('./components/ViewTransitions.astro');
export const ViewTransitions: ViewTransitionsModule['default'];
}
declare module 'astro:transitions/client' {
type TransitionRouterModule = typeof import('./dist/virtual-modules/transitions-router.js');
export const navigate: TransitionRouterModule['navigate'];
export const supportsViewTransitions: TransitionRouterModule['supportsViewTransitions'];
export const getFallback: TransitionRouterModule['getFallback'];
export const transitionEnabledOnThisPage: TransitionRouterModule['transitionEnabledOnThisPage'];
export type Fallback = import('./dist/virtual-modules/transitions-types.js').Fallback;
export type Direction = import('./dist/virtual-modules/transitions-types.ts').Direction;
export type NavigationTypeString =
import('./dist/virtual-modules/transitions-types.js').NavigationTypeString;
export type Options = import('./dist/virtual-modules/transitions-types.js').Options;
type EventModule = typeof import('./dist/virtual-modules/transitions-events.js');
export const TRANSITION_BEFORE_PREPARATION: EventModule['TRANSITION_BEFORE_PREPARATION'];
export const TRANSITION_AFTER_PREPARATION: EventModule['TRANSITION_AFTER_PREPARATION'];
export const TRANSITION_BEFORE_SWAP: EventModule['TRANSITION_BEFORE_SWAP'];
export const TRANSITION_AFTER_SWAP: EventModule['TRANSITION_AFTER_SWAP'];
export const TRANSITION_PAGE_LOAD: EventModule['TRANSITION_PAGE_LOAD'];
export type TransitionBeforePreparationEvent =
import('./dist/virtual-modules/transitions-events.js').TransitionBeforePreparationEvent;
export type TransitionBeforeSwapEvent =
import('./dist/virtual-modules/transitions-events.js').TransitionBeforeSwapEvent;
export const isTransitionBeforePreparationEvent: EventModule['isTransitionBeforePreparationEvent'];
export const isTransitionBeforeSwapEvent: EventModule['isTransitionBeforeSwapEvent'];
type TransitionSwapFunctionModule =
typeof import('./dist/virtual-modules/transitions-swap-functions.js');
export const swapFunctions: TransitionSwapFunctionModule['swapFunctions'];
}
declare module 'astro:prefetch' {
export { prefetch, PrefetchOptions } from 'astro/virtual-modules/prefetch.js';
}
declare module 'astro:i18n' {
export * from 'astro/virtual-modules/i18n.js';
}
declare module 'astro:container' {
export * from 'astro/virtual-modules/container.js';
}
declare module 'astro:middleware' {
export * from 'astro/virtual-modules/middleware.js';
}
declare module 'astro:components' {
export * from 'astro/components';
}
declare module 'astro:schema' {
export * from 'astro/zod';
}
type MD = import('./dist/@types/astro.js').MarkdownInstance<Record<string, any>>;
interface ExportedMarkdownModuleEntities {
frontmatter: MD['frontmatter'];
file: MD['file'];
url: MD['url'];
getHeadings: MD['getHeadings'];
Content: MD['Content'];
rawContent: MD['rawContent'];
compiledContent: MD['compiledContent'];
load: MD['default'];
}
declare module '*.md' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
getHeaders,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.markdown' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
getHeaders,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mkdn' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
getHeaders,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mkd' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
getHeaders,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mdwn' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
getHeaders,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mdown' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
getHeaders,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mdx' {
type MDX = import('./dist/@types/astro.js').MDXInstance<Record<string, any>>;
export const frontmatter: MDX['frontmatter'];
export const file: MDX['file'];
export const url: MDX['url'];
export const getHeadings: MDX['getHeadings'];
export const Content: MDX['Content'];
export const components: MDX['components'];
const load: MDX['default'];
export default load;
}
declare module 'astro:ssr-manifest' {
export const manifest: import('./dist/@types/astro.js').SSRManifest;
}
// Everything below are Vite's types (apart from image types, which are in `client.d.ts`)
// CSS modules
type CSSModuleClasses = { readonly [key: string]: string };
declare module '*.module.css' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.scss' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.sass' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.less' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.styl' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.stylus' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.pcss' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.sss' {
const classes: CSSModuleClasses;
export default classes;
}
// CSS
declare module '*.css' {
const css: string;
export default css;
}
declare module '*.scss' {
const css: string;
export default css;
}
declare module '*.sass' {
const css: string;
export default css;
}
declare module '*.less' {
const css: string;
export default css;
}
declare module '*.styl' {
const css: string;
export default css;
}
declare module '*.stylus' {
const css: string;
export default css;
}
declare module '*.pcss' {
const css: string;
export default css;
}
declare module '*.sss' {
const css: string;
export default css;
}
// Built-in asset types
// see `src/node/constants.ts`
// images
declare module '*.jfif' {
const src: string;
export default src;
}
declare module '*.pjpeg' {
const src: string;
export default src;
}
declare module '*.pjp' {
const src: string;
export default src;
}
declare module '*.ico' {
const src: string;
export default src;
}
// media
declare module '*.mp4' {
const src: string;
export default src;
}
declare module '*.webm' {
const src: string;
export default src;
}
declare module '*.ogg' {
const src: string;
export default src;
}
declare module '*.mp3' {
const src: string;
export default src;
}
declare module '*.wav' {
const src: string;
export default src;
}
declare module '*.flac' {
const src: string;
export default src;
}
declare module '*.aac' {
const src: string;
export default src;
}
declare module '*.opus' {
const src: string;
export default src;
}
// fonts
declare module '*.woff' {
const src: string;
export default src;
}
declare module '*.woff2' {
const src: string;
export default src;
}
declare module '*.eot' {
const src: string;
export default src;
}
declare module '*.ttf' {
const src: string;
export default src;
}
declare module '*.otf' {
const src: string;
export default src;
}
// other
declare module '*.webmanifest' {
const src: string;
export default src;
}
declare module '*.pdf' {
const src: string;
export default src;
}
declare module '*.txt' {
const src: string;
export default src;
}
// wasm?init
declare module '*.wasm?init' {
const initWasm: (options: WebAssembly.Imports) => Promise<WebAssembly.Instance>;
export default initWasm;
}
// web worker
declare module '*?worker' {
const workerConstructor: {
new (): Worker;
};
export default workerConstructor;
}
declare module '*?worker&inline' {
const workerConstructor: {
new (): Worker;
};
export default workerConstructor;
}
declare module '*?worker&url' {
const src: string;
export default src;
}
declare module '*?sharedworker' {
const sharedWorkerConstructor: {
new (): SharedWorker;
};
export default sharedWorkerConstructor;
}
declare module '*?sharedworker&inline' {
const sharedWorkerConstructor: {
new (): SharedWorker;
};
export default sharedWorkerConstructor;
}
declare module '*?sharedworker&url' {
const src: string;
export default src;
}
declare module '*?raw' {
const src: string;
export default src;
}
declare module '*?url' {
const src: string;
export default src;
}
declare module '*?inline' {
const src: string;
export default src;
}

126
node_modules/astro/components/Code.astro generated vendored Normal file
View File

@@ -0,0 +1,126 @@
---
import type { ThemePresets } from '@astrojs/markdown-remark';
import type {
BuiltinLanguage,
LanguageRegistration,
ShikiTransformer,
SpecialLanguage,
ThemeRegistration,
ThemeRegistrationRaw,
} from 'shiki';
import { bundledLanguages } from 'shiki/langs';
import { getCachedHighlighter } from '../dist/core/shiki.js';
import type { HTMLAttributes } from '../types';
interface Props extends Omit<HTMLAttributes<'pre'>, 'lang'> {
/** The code to highlight. Required. */
code: string;
/**
* The language of your code.
* Supports all languages listed here: https://shiki.style/languages
* Instructions for loading a custom language: https://shiki.style/guide/load-lang
*
* @default "plaintext"
*/
lang?: BuiltinLanguage | SpecialLanguage | LanguageRegistration;
/**
* A metastring to pass to the highlighter.
* Allows passing information to transformers: https://shiki.style/guide/transformers#meta
*
* @default undefined
*/
meta?: string;
/**
* The styling theme.
* Supports all themes listed here: https://shiki.style/themes
* Instructions for loading a custom theme: https://shiki.style/guide/load-theme
*
* @default "github-dark"
*/
theme?: ThemePresets | ThemeRegistration | ThemeRegistrationRaw;
/**
* Multiple themes to style with -- alternative to "theme" option.
* Supports all themes found above; see https://shiki.style/guide/dual-themes for more information.
*/
themes?: Record<string, ThemePresets | ThemeRegistration | ThemeRegistrationRaw>;
/**
* Chooses a theme from the "themes" option that you've defined as the default styling theme.
* - <string>: one of the keys defined in the "themes" option. Will throw an error if the key is not defined.
* - false: disabled. You'll have to apply the styling theme yourself. No effect if the "themes" option is not set.
*
* See https://shiki.style/guide/dual-themes#without-default-color for more information.
*
* @default "light"
*/
defaultColor?: 'light' | 'dark' | string | false;
/**
* Enable word wrapping.
* - true: enabled.
* - false: disabled.
* - null: All overflow styling removed. Code will overflow the element by default.
*
* @default false
*/
wrap?: boolean | null;
/**
* Generate inline code element only, without the pre element wrapper.
*
* @default false
*/
inline?: boolean;
/**
* Shiki transformers to customize the generated HTML by manipulating the hast tree.
* Supports all transformers listed here: https://shiki.style/packages/transformers#transformers
* Instructions for custom transformers: https://shiki.style/guide/transformers
*/
transformers?: ShikiTransformer[];
}
const {
code,
lang = 'plaintext',
meta,
theme = 'github-dark',
themes = {},
defaultColor = 'light',
wrap = false,
inline = false,
transformers = [],
...rest
} = Astro.props;
// shiki 1.0 compat
if (typeof lang === 'object') {
// `id` renamed to `name` (always override)
if ((lang as any).id) {
lang.name = (lang as any).id;
}
// `grammar` flattened to lang itself
if ((lang as any).grammar) {
Object.assign(lang, (lang as any).grammar);
}
}
const highlighter = await getCachedHighlighter({
langs: [
typeof lang === 'string'
? Object.keys(bundledLanguages).includes(lang)
? lang
: 'plaintext'
: (lang as any),
],
theme,
themes,
defaultColor,
wrap,
transformers,
});
const html = await highlighter.highlight(code, typeof lang === 'string' ? lang : lang.name, {
inline,
meta,
attributes: rest as any,
});
---
<Fragment set:html={html} />

61
node_modules/astro/components/Debug.astro generated vendored Normal file
View File

@@ -0,0 +1,61 @@
---
import Code from './Code.astro';
const key = Object.keys(Astro.props)[0];
const value = Astro.props[key];
---
<div class="astro-debug">
<div class="astro-debug-header">
<h2 class="astro-debug-title">
<span class="astro-debug-label">Debug</span>
<span class="astro-debug-name">"{key}"</span>
</h2>
</div>
<Code code={JSON.stringify(value, null, 2)} />
</div>
<style is:inline>
.astro-debug {
font-size: 14px;
padding: 1rem 1.5rem;
background: white;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
'Open Sans', 'Helvetica Neue', sans-serif;
}
.astro-debug-header,
pre.astro-code {
margin: -1rem -1.5rem 1rem;
padding: 0.25rem 0.75rem;
}
.astro-debug-header {
background: #ff1639;
border-radius: 4px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.astro-debug-title {
font-size: 1em;
color: white;
margin: 0.5em 0;
}
.astro-debug-label {
font-weight: bold;
text-transform: uppercase;
margin-right: 0.75em;
}
pre.astro-code {
border: 1px solid #eee;
padding: 1rem 0.75rem;
border-radius: 4px;
border-top-left-radius: 0;
border-top-right-radius: 0;
font-size: 14px;
}
</style>

38
node_modules/astro/components/Image.astro generated vendored Normal file
View File

@@ -0,0 +1,38 @@
---
import { type LocalImageProps, type RemoteImageProps, getImage } from 'astro:assets';
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
import type { HTMLAttributes } from '../types';
// The TypeScript diagnostic for JSX props uses the last member of the union to suggest props, so it would be better for
// LocalImageProps to be last. Unfortunately, when we do this the error messages that remote images get are complete nonsense
// Not 100% sure how to fix this, seems to be a TypeScript issue. Unfortunate.
type Props = LocalImageProps | RemoteImageProps;
const props = Astro.props;
if (props.alt === undefined || props.alt === null) {
throw new AstroError(AstroErrorData.ImageMissingAlt);
}
// As a convenience, allow width and height to be string with a number in them, to match HTML's native `img`.
if (typeof props.width === 'string') {
props.width = parseInt(props.width);
}
if (typeof props.height === 'string') {
props.height = parseInt(props.height);
}
const image = await getImage(props);
const additionalAttributes: HTMLAttributes<'img'> = {};
if (image.srcSet.values.length > 0) {
additionalAttributes.srcset = image.srcSet.attribute;
}
if (import.meta.env.DEV) {
additionalAttributes['data-image-component'] = 'true';
}
---
<img src={image.src} {...additionalAttributes} {...image.attributes} />

110
node_modules/astro/components/Picture.astro generated vendored Normal file
View File

@@ -0,0 +1,110 @@
---
import { type LocalImageProps, type RemoteImageProps, getImage } from 'astro:assets';
import * as mime from 'mrmime';
import type { GetImageResult, ImageOutputFormat } from '../dist/@types/astro';
import { isESMImportedImage, resolveSrc } from '../dist/assets/utils/imageKind';
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
import type { HTMLAttributes } from '../types';
type Props = (LocalImageProps | RemoteImageProps) & {
formats?: ImageOutputFormat[];
fallbackFormat?: ImageOutputFormat;
pictureAttributes?: HTMLAttributes<'picture'>;
};
const defaultFormats = ['webp'] as const;
const defaultFallbackFormat = 'png' as const;
// Certain formats don't want PNG fallbacks:
// - GIF will typically want to stay as a gif, either for animation or for the lower amount of colors
// - SVGs can't be converted to raster formats in most cases
// - JPEGs compress photographs and high-noise images better than PNG in most cases
// For those, we'll use the original format as the fallback instead.
const specialFormatsFallback = ['gif', 'svg', 'jpg', 'jpeg'] as const;
const { formats = defaultFormats, pictureAttributes = {}, fallbackFormat, ...props } = Astro.props;
if (props.alt === undefined || props.alt === null) {
throw new AstroError(AstroErrorData.ImageMissingAlt);
}
// Picture attribute inherit scoped styles from class and attributes
const scopedStyleClass = props.class?.match(/\bastro-\w{8}\b/)?.[0];
if (scopedStyleClass) {
if (pictureAttributes.class) {
pictureAttributes.class = `${pictureAttributes.class} ${scopedStyleClass}`;
} else {
pictureAttributes.class = scopedStyleClass;
}
}
for (const key in props) {
if (key.startsWith('data-astro-cid')) {
pictureAttributes[key] = props[key];
}
}
const originalSrc = await resolveSrc(props.src);
const optimizedImages: GetImageResult[] = await Promise.all(
formats.map(
async (format) =>
await getImage({
...props,
src: originalSrc,
format: format,
widths: props.widths,
densities: props.densities,
}),
),
);
let resultFallbackFormat = fallbackFormat ?? defaultFallbackFormat;
if (
!fallbackFormat &&
isESMImportedImage(originalSrc) &&
(specialFormatsFallback as ReadonlyArray<string>).includes(originalSrc.format)
) {
resultFallbackFormat = originalSrc.format;
}
const fallbackImage = await getImage({
...props,
format: resultFallbackFormat,
widths: props.widths,
densities: props.densities,
});
const imgAdditionalAttributes: HTMLAttributes<'img'> = {};
const sourceAdditionalAttributes: HTMLAttributes<'source'> = {};
// Propagate the `sizes` attribute to the `source` elements
if (props.sizes) {
sourceAdditionalAttributes.sizes = props.sizes;
}
if (fallbackImage.srcSet.values.length > 0) {
imgAdditionalAttributes.srcset = fallbackImage.srcSet.attribute;
}
if (import.meta.env.DEV) {
imgAdditionalAttributes['data-image-component'] = 'true';
}
---
<picture {...pictureAttributes}>
{
Object.entries(optimizedImages).map(([_, image]) => {
const srcsetAttribute =
props.densities || (!props.densities && !props.widths)
? `${image.src}${image.srcSet.values.length > 0 ? ', ' + image.srcSet.attribute : ''}`
: image.srcSet.attribute;
return (
<source
srcset={srcsetAttribute}
type={mime.lookup(image.options.format ?? image.src) ?? `image/${image.options.format}`}
{...sourceAdditionalAttributes}
/>
);
})
}
<img src={fallbackImage.src} {...imgAdditionalAttributes} {...fallbackImage.attributes} />
</picture>

149
node_modules/astro/components/ViewTransitions.astro generated vendored Normal file
View File

@@ -0,0 +1,149 @@
---
type Fallback = 'none' | 'animate' | 'swap';
export interface Props {
fallback?: Fallback;
/** @deprecated handleForms is enabled by default in Astro 4.0
*
* Set `data-astro-reload` on your form to opt-out of the default behavior.
*/
handleForms?: boolean;
}
const { fallback = 'animate' } = Astro.props;
---
<style is:global>
/* Route announcer */
.astro-route-announcer {
position: absolute;
left: 0;
top: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);
overflow: hidden;
white-space: nowrap;
width: 1px;
height: 1px;
}
</style>
<meta name="astro-view-transitions-enabled" content="true" />
<meta name="astro-view-transitions-fallback" content={fallback} />
<script>
import type { Options } from 'astro:transitions/client';
import { supportsViewTransitions, navigate } from 'astro:transitions/client';
// NOTE: import from `astro/virtual-modules/prefetch.js` as `astro:prefetch` requires the `prefetch` config to be enabled
// @ts-ignore
import { init } from 'astro/virtual-modules/prefetch.js';
type Fallback = 'none' | 'animate' | 'swap';
function getFallback(): Fallback {
const el = document.querySelector('[name="astro-view-transitions-fallback"]');
if (el) {
return el.getAttribute('content') as Fallback;
}
return 'animate';
}
function isReloadEl(el: HTMLElement | SVGAElement): boolean {
return el.dataset.astroReload !== undefined;
}
if (supportsViewTransitions || getFallback() !== 'none') {
if (import.meta.env.DEV && window.matchMedia('(prefers-reduced-motion)').matches) {
console.warn(
`[transitions]: all view transition animations, including fallback animation, are disabled as this device has the prefer-reduced-motion setting enabled.`,
);
}
document.addEventListener('click', (ev) => {
let link = ev.target;
if (ev.composed) {
link = ev.composedPath()[0];
}
if (link instanceof Element) {
link = link.closest('a, area');
}
if (
!(link instanceof HTMLAnchorElement) &&
!(link instanceof SVGAElement) &&
!(link instanceof HTMLAreaElement)
)
return;
// This check verifies that the click is happening on an anchor
// that is going to another page within the same origin. Basically it determines
// same-origin navigation, but omits special key combos for new tabs, etc.
const linkTarget = link instanceof HTMLElement ? link.target : link.target.baseVal;
const href = link instanceof HTMLElement ? link.href : link.href.baseVal;
const origin = new URL(href, location.href).origin;
if (
isReloadEl(link) ||
link.hasAttribute('download') ||
!link.href ||
(linkTarget && linkTarget !== '_self') ||
origin !== location.origin ||
ev.button !== 0 || // left clicks only
ev.metaKey || // new tab (mac)
ev.ctrlKey || // new tab (windows)
ev.altKey || // download
ev.shiftKey || // new window
ev.defaultPrevented
) {
// No page transitions in these cases,
// Let the browser standard action handle this
return;
}
ev.preventDefault();
navigate(href, {
history: link.dataset.astroHistory === 'replace' ? 'replace' : 'auto',
sourceElement: link,
});
});
document.addEventListener('submit', (ev) => {
let el = ev.target as HTMLElement;
if (el.tagName !== 'FORM' || ev.defaultPrevented || isReloadEl(el)) {
return;
}
const form = el as HTMLFormElement;
const submitter = ev.submitter;
const formData = new FormData(form, submitter);
// form.action and form.method can point to an <input name="action"> or <input name="method">
// in which case should fallback to the form attribute
const formAction =
typeof form.action === 'string' ? form.action : form.getAttribute('action');
const formMethod =
typeof form.method === 'string' ? form.method : form.getAttribute('method');
// Use the form action, if defined, otherwise fallback to current path.
let action = submitter?.getAttribute('formaction') ?? formAction ?? location.pathname;
// Use the form method, if defined, otherwise fallback to "get"
const method = submitter?.getAttribute('formmethod') ?? formMethod ?? 'get';
// the "dialog" method is a special keyword used within <dialog> elements
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-method
if (method === 'dialog' || location.origin !== new URL(action, location.href).origin) {
// No page transitions in these cases,
// Let the browser standard action handle this
return;
}
const options: Options = { sourceElement: submitter ?? form };
if (method === 'get') {
const params = new URLSearchParams(formData as any);
const url = new URL(action);
url.search = params.toString();
action = url.toString();
} else {
options.formData = formData;
}
ev.preventDefault();
navigate(action, options);
});
// @ts-expect-error injected by vite-plugin-transitions for treeshaking
if (!__PREFETCH_DISABLED__) {
init({ prefetchAll: true });
}
}
</script>

6
node_modules/astro/components/index.ts generated vendored Normal file
View File

@@ -0,0 +1,6 @@
// The `ts-ignore` comments here are necessary because we're importing this file inside the `astro:components`
// virtual module's types, which means that `tsc` will try to resolve these imports. Don't mind the editor errors.
// @ts-ignore
export { default as Code } from './Code.astro';
// @ts-ignore
export { default as Debug } from './Debug.astro';

66
node_modules/astro/components/viewtransitions.css generated vendored Normal file
View File

@@ -0,0 +1,66 @@
@keyframes astroFadeInOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes astroFadeIn {
from {
opacity: 0;
mix-blend-mode: plus-lighter;
}
to {
opacity: 1;
mix-blend-mode: plus-lighter;
}
}
@keyframes astroFadeOut {
from {
opacity: 1;
mix-blend-mode: plus-lighter;
}
to {
opacity: 0;
mix-blend-mode: plus-lighter;
}
}
@keyframes astroSlideFromRight {
from {
transform: translateX(100%);
}
}
@keyframes astroSlideFromLeft {
from {
transform: translateX(-100%);
}
}
@keyframes astroSlideToRight {
to {
transform: translateX(100%);
}
}
@keyframes astroSlideToLeft {
to {
transform: translateX(-100%);
}
}
@media (prefers-reduced-motion) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
[data-astro-transition-scope] {
animation: none !important;
}
}

48
node_modules/astro/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,48 @@
type ViteUserConfig = import('vite').UserConfig;
type ViteUserConfigFn = import('vite').UserConfigFn;
type AstroUserConfig = import('./dist/@types/astro.js').AstroUserConfig;
type AstroInlineConfig = import('./dist/@types/astro.js').AstroInlineConfig;
type ImageServiceConfig = import('./dist/@types/astro.js').ImageServiceConfig;
type SharpImageServiceConfig = import('./dist/assets/services/sharp.js').SharpImageServiceConfig;
type EnvField = typeof import('./dist/env/config.js').envField;
/**
* See the full Astro Configuration API Documentation
* https://astro.build/config
*/
export function defineConfig(config: AstroUserConfig): AstroUserConfig;
/**
* Use Astro to generate a fully resolved Vite config
*/
export function getViteConfig(
config: ViteUserConfig,
inlineAstroConfig?: AstroInlineConfig,
): ViteUserConfigFn;
/**
* Return the configuration needed to use the Sharp-based image service
*/
export function sharpImageService(config?: SharpImageServiceConfig): ImageServiceConfig;
/**
* @deprecated The Squoosh image service is deprecated and will be removed in Astro 5.x.
* We suggest migrating to the default Sharp image service instead, as it is faster, more powerful and better maintained.
*
* Return the configuration needed to use the Squoosh-based image service
* See: https://docs.astro.build/en/guides/images/#configure-squoosh
*/
export function squooshImageService(): ImageServiceConfig;
/**
* Return the configuration needed to use the passthrough image service. This image services does not perform
* any image transformations, and is mainly useful when your platform does not support other image services, or you are
* not using Astro's built-in image processing.
* See: https://docs.astro.build/en/guides/images/#configure-no-op-passthrough-service
*/
export function passthroughImageService(): ImageServiceConfig;
/**
* Return a valid env field to use in this Astro config for `experimental.env.schema`.
*/
export const envField: EnvField;

23
node_modules/astro/config.mjs generated vendored Normal file
View File

@@ -0,0 +1,23 @@
export { defineConfig, getViteConfig } from './dist/config/index.js';
export { envField } from './dist/env/config.js';
export function sharpImageService(config = {}) {
return {
entrypoint: 'astro/assets/services/sharp',
config,
};
}
export function squooshImageService() {
return {
entrypoint: 'astro/assets/services/squoosh',
config: {},
};
}
export function passthroughImageService() {
return {
entrypoint: 'astro/assets/services/noop',
config: {},
};
}

0
node_modules/astro/dist/@types/app.d.js generated vendored Normal file
View File

3385
node_modules/astro/dist/@types/astro.d.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

0
node_modules/astro/dist/@types/astro.js generated vendored Normal file
View File

41
node_modules/astro/dist/@types/typed-emitter.d.ts generated vendored Normal file
View File

@@ -0,0 +1,41 @@
/**
* The MIT License (MIT)
* Copyright (c) 2018 Andy Wermke
* https://github.com/andywer/typed-emitter/blob/9a139b6fa0ec6b0db6141b5b756b784e4f7ef4e4/LICENSE
*/
export type EventMap = {
[key: string]: (...args: any[]) => void;
};
/**
* Type-safe event emitter.
*
* Use it like this:
*
* ```typescript
* type MyEvents = {
* error: (error: Error) => void;
* message: (from: string, content: string) => void;
* }
*
* const myEmitter = new EventEmitter() as TypedEmitter<MyEvents>;
*
* myEmitter.emit("error", "x") // <- Will catch this type error;
* ```
*/
export interface TypedEventEmitter<Events extends EventMap> {
addListener<E extends keyof Events>(event: E, listener: Events[E]): this;
on<E extends keyof Events>(event: E, listener: Events[E]): this;
once<E extends keyof Events>(event: E, listener: Events[E]): this;
prependListener<E extends keyof Events>(event: E, listener: Events[E]): this;
prependOnceListener<E extends keyof Events>(event: E, listener: Events[E]): this;
off<E extends keyof Events>(event: E, listener: Events[E]): this;
removeAllListeners<E extends keyof Events>(event?: E): this;
removeListener<E extends keyof Events>(event: E, listener: Events[E]): this;
emit<E extends keyof Events>(event: E, ...args: Parameters<Events[E]>): boolean;
eventNames(): (keyof Events | string | symbol)[];
rawListeners<E extends keyof Events>(event: E): Events[E][];
listeners<E extends keyof Events>(event: E): Events[E][];
listenerCount<E extends keyof Events>(event: E): number;
getMaxListeners(): number;
setMaxListeners(maxListeners: number): this;
}

0
node_modules/astro/dist/@types/typed-emitter.js generated vendored Normal file
View File

11
node_modules/astro/dist/actions/consts.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
export declare const VIRTUAL_MODULE_ID = "astro:actions";
export declare const RESOLVED_VIRTUAL_MODULE_ID: string;
export declare const ACTIONS_TYPES_FILE = "astro/actions.d.ts";
export declare const VIRTUAL_INTERNAL_MODULE_ID = "astro:internal-actions";
export declare const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = "\0astro:internal-actions";
export declare const NOOP_ACTIONS = "\0noop-actions";
export declare const ACTION_QUERY_PARAMS: {
actionName: string;
actionPayload: string;
actionRedirect: string;
};

20
node_modules/astro/dist/actions/consts.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
const VIRTUAL_MODULE_ID = "astro:actions";
const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
const ACTIONS_TYPES_FILE = "astro/actions.d.ts";
const VIRTUAL_INTERNAL_MODULE_ID = "astro:internal-actions";
const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = "\0astro:internal-actions";
const NOOP_ACTIONS = "\0noop-actions";
const ACTION_QUERY_PARAMS = {
actionName: "_astroAction",
actionPayload: "_astroActionPayload",
actionRedirect: "_astroActionRedirect"
};
export {
ACTIONS_TYPES_FILE,
ACTION_QUERY_PARAMS,
NOOP_ACTIONS,
RESOLVED_VIRTUAL_INTERNAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
VIRTUAL_INTERNAL_MODULE_ID,
VIRTUAL_MODULE_ID
};

8
node_modules/astro/dist/actions/integration.d.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
import type { AstroIntegration, AstroSettings } from '../@types/astro.js';
/**
* This integration is applied when the user is using Actions in their project.
* It will inject the necessary routes and middlewares to handle actions.
*/
export default function astroIntegrationActionsRouteHandler({ settings, }: {
settings: AstroSettings;
}): AstroIntegration;

45
node_modules/astro/dist/actions/integration.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
import { ActionsWithoutServerOutputError } from "../core/errors/errors-data.js";
import { AstroError } from "../core/errors/errors.js";
import { isServerLikeOutput, viteID } from "../core/util.js";
import { ACTIONS_TYPES_FILE, VIRTUAL_MODULE_ID } from "./consts.js";
function astroIntegrationActionsRouteHandler({
settings
}) {
return {
name: VIRTUAL_MODULE_ID,
hooks: {
async "astro:config:setup"(params) {
params.injectRoute({
pattern: "/_actions/[...path]",
entrypoint: "astro/actions/runtime/route.js",
prerender: false
});
params.addMiddleware({
entrypoint: "astro/actions/runtime/middleware.js",
order: "post"
});
},
"astro:config:done": async (params) => {
if (!isServerLikeOutput(params.config)) {
const error = new AstroError(ActionsWithoutServerOutputError);
error.stack = void 0;
throw error;
}
const stringifiedActionsImport = JSON.stringify(
viteID(new URL("./actions", params.config.srcDir))
);
settings.injectedTypes.push({
filename: ACTIONS_TYPES_FILE,
content: `declare module "astro:actions" {
type Actions = typeof import(${stringifiedActionsImport})["server"];
export const actions: Actions;
}`
});
}
}
};
}
export {
astroIntegrationActionsRouteHandler as default
};

15
node_modules/astro/dist/actions/plugins.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import type fsMod from 'node:fs';
import type { Plugin as VitePlugin } from 'vite';
import type { AstroSettings } from '../@types/astro.js';
/**
* This plugin is responsible to load the known file `actions/index.js` / `actions.js`
* If the file doesn't exist, it returns an empty object.
* @param settings
*/
export declare function vitePluginUserActions({ settings }: {
settings: AstroSettings;
}): VitePlugin;
export declare function vitePluginActions({ fs, settings, }: {
fs: typeof fsMod;
settings: AstroSettings;
}): VitePlugin;

80
node_modules/astro/dist/actions/plugins.js generated vendored Normal file
View File

@@ -0,0 +1,80 @@
import {
NOOP_ACTIONS,
RESOLVED_VIRTUAL_INTERNAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
VIRTUAL_INTERNAL_MODULE_ID,
VIRTUAL_MODULE_ID
} from "./consts.js";
import { isActionsFilePresent } from "./utils.js";
function vitePluginUserActions({ settings }) {
let resolvedActionsId;
return {
name: "@astro/plugin-actions",
async resolveId(id) {
if (id === NOOP_ACTIONS) {
return NOOP_ACTIONS;
}
if (id === VIRTUAL_INTERNAL_MODULE_ID) {
const resolvedModule = await this.resolve(
`${decodeURI(new URL("actions", settings.config.srcDir).pathname)}`
);
if (!resolvedModule) {
return NOOP_ACTIONS;
}
resolvedActionsId = resolvedModule.id;
return RESOLVED_VIRTUAL_INTERNAL_MODULE_ID;
}
},
load(id) {
if (id === NOOP_ACTIONS) {
return "export const server = {}";
} else if (id === RESOLVED_VIRTUAL_INTERNAL_MODULE_ID) {
return `export { server } from '${resolvedActionsId}';`;
}
}
};
}
function vitePluginActions({
fs,
settings
}) {
return {
name: VIRTUAL_MODULE_ID,
enforce: "pre",
resolveId(id) {
if (id === VIRTUAL_MODULE_ID) {
return RESOLVED_VIRTUAL_MODULE_ID;
}
},
async configureServer(server) {
const filePresentOnStartup = await isActionsFilePresent(fs, settings.config.srcDir);
async function watcherCallback() {
const filePresent = await isActionsFilePresent(fs, settings.config.srcDir);
if (filePresentOnStartup !== filePresent) {
server.restart();
}
}
server.watcher.on("add", watcherCallback);
server.watcher.on("change", watcherCallback);
},
async load(id, opts) {
if (id !== RESOLVED_VIRTUAL_MODULE_ID) return;
let code = await fs.promises.readFile(
new URL("../../templates/actions.mjs", import.meta.url),
"utf-8"
);
if (opts?.ssr) {
code += `
export * from 'astro/actions/runtime/virtual/server.js';`;
} else {
code += `
export * from 'astro/actions/runtime/virtual/client.js';`;
}
return code;
}
};
}
export {
vitePluginActions,
vitePluginUserActions
};

View File

@@ -0,0 +1,9 @@
import { type SerializedActionResult } from './virtual/shared.js';
export type ActionPayload = {
actionResult: SerializedActionResult;
actionName: string;
};
export type Locals = {
_actionPayload: ActionPayload;
};
export declare const onRequest: import("../../@types/astro.js").MiddlewareHandler;

110
node_modules/astro/dist/actions/runtime/middleware.js generated vendored Normal file
View File

@@ -0,0 +1,110 @@
import { yellow } from "kleur/colors";
import { defineMiddleware } from "../../core/middleware/index.js";
import { getOriginPathname } from "../../core/routing/rewrite.js";
import { ACTION_QUERY_PARAMS } from "../consts.js";
import { ACTION_API_CONTEXT_SYMBOL, formContentTypes, hasContentType } from "./utils.js";
import { getAction } from "./virtual/get-action.js";
import {
serializeActionResult
} from "./virtual/shared.js";
const onRequest = defineMiddleware(async (context, next) => {
if (context._isPrerendered) {
if (context.request.method === "POST") {
console.warn(
yellow("[astro:actions]"),
"POST requests should not be sent to prerendered pages. If you're using Actions, disable prerendering with `export const prerender = false`."
);
}
return next();
}
const locals = context.locals;
if (locals._actionPayload) return next();
const actionPayload = context.cookies.get(ACTION_QUERY_PARAMS.actionPayload)?.json();
if (actionPayload) {
if (!isActionPayload(actionPayload)) {
throw new Error("Internal: Invalid action payload in cookie.");
}
return renderResult({ context, next, ...actionPayload });
}
const actionName = context.url.searchParams.get(ACTION_QUERY_PARAMS.actionName);
if (context.request.method === "POST" && actionName) {
return handlePost({ context, next, actionName });
}
return next();
});
async function renderResult({
context,
next,
actionResult,
actionName
}) {
const locals = context.locals;
locals._actionPayload = { actionResult, actionName };
const response = await next();
context.cookies.delete(ACTION_QUERY_PARAMS.actionPayload);
if (actionResult.type === "error") {
return new Response(response.body, {
status: actionResult.status,
statusText: actionResult.type,
headers: response.headers
});
}
return response;
}
async function handlePost({
context,
next,
actionName
}) {
const { request } = context;
const baseAction = await getAction(actionName);
const contentType = request.headers.get("content-type");
let formData;
if (contentType && hasContentType(contentType, formContentTypes)) {
formData = await request.clone().formData();
}
const { getActionResult, callAction, props, redirect, ...actionAPIContext } = context;
Reflect.set(actionAPIContext, ACTION_API_CONTEXT_SYMBOL, true);
const action = baseAction.bind(actionAPIContext);
const actionResult = await action(formData);
if (context.url.searchParams.get(ACTION_QUERY_PARAMS.actionRedirect) === "false") {
return renderResult({
context,
next,
actionName,
actionResult: serializeActionResult(actionResult)
});
}
return redirectWithResult({ context, actionName, actionResult });
}
async function redirectWithResult({
context,
actionName,
actionResult
}) {
context.cookies.set(ACTION_QUERY_PARAMS.actionPayload, {
actionName,
actionResult: serializeActionResult(actionResult)
});
if (actionResult.error) {
const referer2 = context.request.headers.get("Referer");
if (!referer2) {
throw new Error("Internal: Referer unexpectedly missing from Action POST request.");
}
return context.redirect(referer2);
}
const referer = getOriginPathname(context.request);
if (referer) {
return context.redirect(referer);
}
return context.redirect(context.url.pathname);
}
function isActionPayload(json) {
if (typeof json !== "object" || json == null) return false;
if (!("actionResult" in json) || typeof json.actionResult !== "object") return false;
if (!("actionName" in json) || typeof json.actionName !== "string") return false;
return true;
}
export {
onRequest
};

2
node_modules/astro/dist/actions/runtime/route.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
import type { APIRoute } from '../../@types/astro.js';
export declare const POST: APIRoute;

45
node_modules/astro/dist/actions/runtime/route.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
import { ACTION_API_CONTEXT_SYMBOL, formContentTypes, hasContentType } from "./utils.js";
import { getAction } from "./virtual/get-action.js";
import { serializeActionResult } from "./virtual/shared.js";
const POST = async (context) => {
const { request, url } = context;
let baseAction;
try {
baseAction = await getAction(url.pathname);
} catch (e) {
if (import.meta.env.DEV) throw e;
console.error(e);
return new Response(e instanceof Error ? e.message : null, { status: 404 });
}
const contentType = request.headers.get("Content-Type");
const contentLength = request.headers.get("Content-Length");
let args;
if (!contentType || contentLength === "0") {
args = void 0;
} else if (contentType && hasContentType(contentType, formContentTypes)) {
args = await request.clone().formData();
} else if (contentType && hasContentType(contentType, ["application/json"])) {
args = await request.clone().json();
} else {
return new Response(null, { status: 415 });
}
const { getActionResult, callAction, props, redirect, ...actionAPIContext } = context;
Reflect.set(actionAPIContext, ACTION_API_CONTEXT_SYMBOL, true);
const action = baseAction.bind(actionAPIContext);
const result = await action(args);
const serialized = serializeActionResult(result);
if (serialized.type === "empty") {
return new Response(null, {
status: serialized.status
});
}
return new Response(serialized.body, {
status: serialized.status,
headers: {
"Content-Type": serialized.contentType
}
});
};
export {
POST
};

17
node_modules/astro/dist/actions/runtime/utils.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import type { APIContext } from '../../@types/astro.js';
export declare const ACTION_API_CONTEXT_SYMBOL: unique symbol;
export declare const formContentTypes: string[];
export declare function hasContentType(contentType: string, expected: string[]): boolean;
export type ActionAPIContext = Omit<APIContext, 'getActionResult' | 'callAction' | 'props' | 'redirect'>;
export type MaybePromise<T> = T | Promise<T>;
/**
* Used to preserve the input schema type in the error object.
* This allows for type inference on the `fields` property
* when type narrowed to an `ActionInputError`.
*
* Example: Action has an input schema of `{ name: z.string() }`.
* When calling the action and checking `isInputError(result.error)`,
* `result.error.fields` will be typed with the `name` field.
*/
export type ErrorInferenceObject = Record<string, any>;
export declare function isActionAPIContext(ctx: ActionAPIContext): boolean;

16
node_modules/astro/dist/actions/runtime/utils.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
const ACTION_API_CONTEXT_SYMBOL = Symbol.for("astro.actionAPIContext");
const formContentTypes = ["application/x-www-form-urlencoded", "multipart/form-data"];
function hasContentType(contentType, expected) {
const type = contentType.split(";")[0].toLowerCase();
return expected.some((t) => type === t);
}
function isActionAPIContext(ctx) {
const symbol = Reflect.get(ctx, ACTION_API_CONTEXT_SYMBOL);
return symbol === true;
}
export {
ACTION_API_CONTEXT_SYMBOL,
formContentTypes,
hasContentType,
isActionAPIContext
};

View File

@@ -0,0 +1,2 @@
export * from './shared.js';
export declare function defineAction(): void;

View File

@@ -0,0 +1,7 @@
export * from "./shared.js";
function defineAction() {
throw new Error("[astro:action] `defineAction()` unexpectedly used on the client.");
}
export {
defineAction
};

View File

@@ -0,0 +1,8 @@
import type { ZodType } from 'zod';
import type { ActionAccept, ActionClient } from './server.js';
/**
* Get server-side action based on the route path.
* Imports from the virtual module `astro:internal-actions`, which maps to
* the user's `src/actions/index.ts` file at build-time.
*/
export declare function getAction(path: string): Promise<ActionClient<unknown, ActionAccept, ZodType>>;

View File

@@ -0,0 +1,29 @@
import { ActionNotFoundError } from "../../../core/errors/errors-data.js";
import { AstroError } from "../../../core/errors/errors.js";
async function getAction(path) {
const pathKeys = path.replace(/^.*\/_actions\//, "").split(".").map((key) => decodeURIComponent(key));
let { server: actionLookup } = await import("astro:internal-actions");
if (actionLookup == null || !(typeof actionLookup === "object")) {
throw new TypeError(
`Expected \`server\` export in actions file to be an object. Received ${typeof actionLookup}.`
);
}
for (const key of pathKeys) {
if (!(key in actionLookup)) {
throw new AstroError({
...ActionNotFoundError,
message: ActionNotFoundError.message(pathKeys.join("."))
});
}
actionLookup = actionLookup[key];
}
if (typeof actionLookup !== "function") {
throw new TypeError(
`Expected handler for action ${pathKeys.join(".")} to be a function. Received ${typeof actionLookup}.`
);
}
return actionLookup;
}
export {
getAction
};

View File

@@ -0,0 +1,20 @@
import { z } from 'zod';
import { type ActionAPIContext, type ErrorInferenceObject, type MaybePromise } from '../utils.js';
import { type SafeResult } from './shared.js';
export * from './shared.js';
export type ActionAccept = 'form' | 'json';
export type ActionHandler<TInputSchema, TOutput> = TInputSchema extends z.ZodType ? (input: z.infer<TInputSchema>, context: ActionAPIContext) => MaybePromise<TOutput> : (input: any, context: ActionAPIContext) => MaybePromise<TOutput>;
export type ActionReturnType<T extends ActionHandler<any, any>> = Awaited<ReturnType<T>>;
export type ActionClient<TOutput, TAccept extends ActionAccept | undefined, TInputSchema extends z.ZodType | undefined> = TInputSchema extends z.ZodType ? ((input: TAccept extends 'form' ? FormData : z.input<TInputSchema>) => Promise<SafeResult<z.input<TInputSchema> extends ErrorInferenceObject ? z.input<TInputSchema> : ErrorInferenceObject, Awaited<TOutput>>>) & {
queryString: string;
orThrow: (input: TAccept extends 'form' ? FormData : z.input<TInputSchema>) => Promise<Awaited<TOutput>>;
} : ((input?: any) => Promise<SafeResult<never, Awaited<TOutput>>>) & {
orThrow: (input?: any) => Promise<Awaited<TOutput>>;
};
export declare function defineAction<TOutput, TAccept extends ActionAccept | undefined = undefined, TInputSchema extends z.ZodType | undefined = TAccept extends 'form' ? z.ZodType<FormData> : undefined>({ accept, input: inputSchema, handler, }: {
input?: TInputSchema;
accept?: TAccept;
handler: ActionHandler<TInputSchema, TOutput>;
}): ActionClient<TOutput, TAccept, TInputSchema> & string;
/** Transform form data to an object based on a Zod schema. */
export declare function formDataToObject<T extends z.AnyZodObject>(formData: FormData, schema: T): Record<string, unknown>;

View File

@@ -0,0 +1,128 @@
import { z } from "zod";
import { ActionCalledFromServerError } from "../../../core/errors/errors-data.js";
import { AstroError } from "../../../core/errors/errors.js";
import {
isActionAPIContext
} from "../utils.js";
import { ActionError, ActionInputError, callSafely } from "./shared.js";
export * from "./shared.js";
function defineAction({
accept,
input: inputSchema,
handler
}) {
const serverHandler = accept === "form" ? getFormServerHandler(handler, inputSchema) : getJsonServerHandler(handler, inputSchema);
async function safeServerHandler(unparsedInput) {
if (typeof this === "function" || !isActionAPIContext(this)) {
throw new AstroError(ActionCalledFromServerError);
}
return callSafely(() => serverHandler(unparsedInput, this));
}
Object.assign(safeServerHandler, {
orThrow(unparsedInput) {
if (typeof this === "function") {
throw new AstroError(ActionCalledFromServerError);
}
return serverHandler(unparsedInput, this);
}
});
return safeServerHandler;
}
function getFormServerHandler(handler, inputSchema) {
return async (unparsedInput, context) => {
if (!(unparsedInput instanceof FormData)) {
throw new ActionError({
code: "UNSUPPORTED_MEDIA_TYPE",
message: "This action only accepts FormData."
});
}
if (!inputSchema) return await handler(unparsedInput, context);
const baseSchema = unwrapBaseObjectSchema(inputSchema, unparsedInput);
const parsed = await inputSchema.safeParseAsync(
baseSchema instanceof z.ZodObject ? formDataToObject(unparsedInput, baseSchema) : unparsedInput
);
if (!parsed.success) {
throw new ActionInputError(parsed.error.issues);
}
return await handler(parsed.data, context);
};
}
function getJsonServerHandler(handler, inputSchema) {
return async (unparsedInput, context) => {
if (unparsedInput instanceof FormData) {
throw new ActionError({
code: "UNSUPPORTED_MEDIA_TYPE",
message: "This action only accepts JSON."
});
}
if (!inputSchema) return await handler(unparsedInput, context);
const parsed = await inputSchema.safeParseAsync(unparsedInput);
if (!parsed.success) {
throw new ActionInputError(parsed.error.issues);
}
return await handler(parsed.data, context);
};
}
function formDataToObject(formData, schema) {
const obj = schema._def.unknownKeys === "passthrough" ? Object.fromEntries(formData.entries()) : {};
for (const [key, baseValidator] of Object.entries(schema.shape)) {
let validator = baseValidator;
while (validator instanceof z.ZodOptional || validator instanceof z.ZodNullable || validator instanceof z.ZodDefault) {
if (validator instanceof z.ZodDefault && !formData.has(key)) {
obj[key] = validator._def.defaultValue();
}
validator = validator._def.innerType;
}
if (!formData.has(key) && key in obj) {
continue;
} else if (validator instanceof z.ZodBoolean) {
const val = formData.get(key);
obj[key] = val === "true" ? true : val === "false" ? false : formData.has(key);
} else if (validator instanceof z.ZodArray) {
obj[key] = handleFormDataGetAll(key, formData, validator);
} else {
obj[key] = handleFormDataGet(key, formData, validator, baseValidator);
}
}
return obj;
}
function handleFormDataGetAll(key, formData, validator) {
const entries = Array.from(formData.getAll(key));
const elementValidator = validator._def.type;
if (elementValidator instanceof z.ZodNumber) {
return entries.map(Number);
} else if (elementValidator instanceof z.ZodBoolean) {
return entries.map(Boolean);
}
return entries;
}
function handleFormDataGet(key, formData, validator, baseValidator) {
const value = formData.get(key);
if (!value) {
return baseValidator instanceof z.ZodOptional ? void 0 : null;
}
return validator instanceof z.ZodNumber ? Number(value) : value;
}
function unwrapBaseObjectSchema(schema, unparsedInput) {
while (schema instanceof z.ZodEffects || schema instanceof z.ZodPipeline) {
if (schema instanceof z.ZodEffects) {
schema = schema._def.schema;
}
if (schema instanceof z.ZodPipeline) {
schema = schema._def.in;
}
}
if (schema instanceof z.ZodDiscriminatedUnion) {
const typeKey = schema._def.discriminator;
const typeValue = unparsedInput.get(typeKey);
if (typeof typeValue !== "string") return schema;
const objSchema = schema._def.optionsMap.get(typeValue);
if (!objSchema) return schema;
return objSchema;
}
return schema;
}
export {
defineAction,
formDataToObject
};

View File

@@ -0,0 +1,57 @@
import type { z } from 'zod';
import type { ErrorInferenceObject, MaybePromise, ActionAPIContext as _ActionAPIContext } from '../utils.js';
export type ActionAPIContext = _ActionAPIContext;
export declare const ACTION_QUERY_PARAMS: {
actionName: string;
actionPayload: string;
actionRedirect: string;
};
export declare const ACTION_ERROR_CODES: readonly ["BAD_REQUEST", "UNAUTHORIZED", "FORBIDDEN", "NOT_FOUND", "TIMEOUT", "CONFLICT", "PRECONDITION_FAILED", "PAYLOAD_TOO_LARGE", "UNSUPPORTED_MEDIA_TYPE", "UNPROCESSABLE_CONTENT", "TOO_MANY_REQUESTS", "CLIENT_CLOSED_REQUEST", "INTERNAL_SERVER_ERROR"];
export type ActionErrorCode = (typeof ACTION_ERROR_CODES)[number];
export declare class ActionError<_T extends ErrorInferenceObject = ErrorInferenceObject> extends Error {
type: string;
code: ActionErrorCode;
status: number;
constructor(params: {
message?: string;
code: ActionErrorCode;
stack?: string;
});
static codeToStatus(code: ActionErrorCode): number;
static statusToCode(status: number): ActionErrorCode;
static fromJson(body: any): ActionError<ErrorInferenceObject>;
}
export declare function isActionError(error?: unknown): error is ActionError;
export declare function isInputError<T extends ErrorInferenceObject>(error?: ActionError<T>): error is ActionInputError<T>;
export declare function isInputError(error?: unknown): error is ActionInputError<ErrorInferenceObject>;
export type SafeResult<TInput extends ErrorInferenceObject, TOutput> = {
data: TOutput;
error: undefined;
} | {
data: undefined;
error: ActionError<TInput>;
};
export declare class ActionInputError<T extends ErrorInferenceObject> extends ActionError {
type: string;
issues: z.ZodIssue[];
fields: z.ZodError<T>['formErrors']['fieldErrors'];
constructor(issues: z.ZodIssue[]);
}
export declare function callSafely<TOutput>(handler: () => MaybePromise<TOutput>): Promise<SafeResult<z.ZodType, TOutput>>;
export declare function getActionQueryString(name: string): string;
export type SerializedActionResult = {
type: 'data';
contentType: 'application/json+devalue';
status: 200;
body: string;
} | {
type: 'error';
contentType: 'application/json';
status: number;
body: string;
} | {
type: 'empty';
status: 204;
};
export declare function serializeActionResult(res: SafeResult<any, any>): SerializedActionResult;
export declare function deserializeActionResult(res: SerializedActionResult): SafeResult<any, any>;

View File

@@ -0,0 +1,226 @@
import { parse as devalueParse, stringify as devalueStringify } from "devalue";
import { REDIRECT_STATUS_CODES } from "../../../core/constants.js";
import { ActionsReturnedInvalidDataError } from "../../../core/errors/errors-data.js";
import { AstroError } from "../../../core/errors/errors.js";
import { ACTION_QUERY_PARAMS as _ACTION_QUERY_PARAMS } from "../../consts.js";
const ACTION_QUERY_PARAMS = _ACTION_QUERY_PARAMS;
const ACTION_ERROR_CODES = [
"BAD_REQUEST",
"UNAUTHORIZED",
"FORBIDDEN",
"NOT_FOUND",
"TIMEOUT",
"CONFLICT",
"PRECONDITION_FAILED",
"PAYLOAD_TOO_LARGE",
"UNSUPPORTED_MEDIA_TYPE",
"UNPROCESSABLE_CONTENT",
"TOO_MANY_REQUESTS",
"CLIENT_CLOSED_REQUEST",
"INTERNAL_SERVER_ERROR"
];
const codeToStatusMap = {
// Implemented from tRPC error code table
// https://trpc.io/docs/server/error-handling#error-codes
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
TIMEOUT: 405,
CONFLICT: 409,
PRECONDITION_FAILED: 412,
PAYLOAD_TOO_LARGE: 413,
UNSUPPORTED_MEDIA_TYPE: 415,
UNPROCESSABLE_CONTENT: 422,
TOO_MANY_REQUESTS: 429,
CLIENT_CLOSED_REQUEST: 499,
INTERNAL_SERVER_ERROR: 500
};
const statusToCodeMap = Object.entries(codeToStatusMap).reduce(
// reverse the key-value pairs
(acc, [key, value]) => ({ ...acc, [value]: key }),
{}
);
class ActionError extends Error {
type = "AstroActionError";
code = "INTERNAL_SERVER_ERROR";
status = 500;
constructor(params) {
super(params.message);
this.code = params.code;
this.status = ActionError.codeToStatus(params.code);
if (params.stack) {
this.stack = params.stack;
}
}
static codeToStatus(code) {
return codeToStatusMap[code];
}
static statusToCode(status) {
return statusToCodeMap[status] ?? "INTERNAL_SERVER_ERROR";
}
static fromJson(body) {
if (isInputError(body)) {
return new ActionInputError(body.issues);
}
if (isActionError(body)) {
return new ActionError(body);
}
return new ActionError({
code: "INTERNAL_SERVER_ERROR"
});
}
}
function isActionError(error) {
return typeof error === "object" && error != null && "type" in error && error.type === "AstroActionError";
}
function isInputError(error) {
return typeof error === "object" && error != null && "type" in error && error.type === "AstroActionInputError" && "issues" in error && Array.isArray(error.issues);
}
class ActionInputError extends ActionError {
type = "AstroActionInputError";
// We don't expose all ZodError properties.
// Not all properties will serialize from server to client,
// and we don't want to import the full ZodError object into the client.
issues;
fields;
constructor(issues) {
super({
message: `Failed to validate: ${JSON.stringify(issues, null, 2)}`,
code: "BAD_REQUEST"
});
this.issues = issues;
this.fields = {};
for (const issue of issues) {
if (issue.path.length > 0) {
const key = issue.path[0].toString();
this.fields[key] ??= [];
this.fields[key]?.push(issue.message);
}
}
}
}
async function callSafely(handler) {
try {
const data = await handler();
return { data, error: void 0 };
} catch (e) {
if (e instanceof ActionError) {
return { data: void 0, error: e };
}
return {
data: void 0,
error: new ActionError({
message: e instanceof Error ? e.message : "Unknown error",
code: "INTERNAL_SERVER_ERROR"
})
};
}
}
function getActionQueryString(name) {
const searchParams = new URLSearchParams({ [_ACTION_QUERY_PARAMS.actionName]: name });
return `?${searchParams.toString()}`;
}
function serializeActionResult(res) {
if (res.error) {
if (import.meta.env?.DEV) {
actionResultErrorStack.set(res.error.stack);
}
return {
type: "error",
status: res.error.status,
contentType: "application/json",
body: JSON.stringify({
...res.error,
message: res.error.message
})
};
}
if (res.data === void 0) {
return {
type: "empty",
status: 204
};
}
let body;
try {
body = devalueStringify(res.data, {
// Add support for URL objects
URL: (value) => value instanceof URL && value.href
});
} catch (e) {
let hint = ActionsReturnedInvalidDataError.hint;
if (res.data instanceof Response) {
hint = REDIRECT_STATUS_CODES.includes(res.data.status) ? "If you need to redirect when the action succeeds, trigger a redirect where the action is called. See the Actions guide for server and client redirect examples: https://docs.astro.build/en/guides/actions." : "If you need to return a Response object, try using a server endpoint instead. See https://docs.astro.build/en/guides/endpoints/#server-endpoints-api-routes";
}
throw new AstroError({
...ActionsReturnedInvalidDataError,
message: ActionsReturnedInvalidDataError.message(String(e)),
hint
});
}
return {
type: "data",
status: 200,
contentType: "application/json+devalue",
body
};
}
function deserializeActionResult(res) {
if (res.type === "error") {
let json;
try {
json = JSON.parse(res.body);
} catch {
return {
data: void 0,
error: new ActionError({
message: res.body,
code: "INTERNAL_SERVER_ERROR"
})
};
}
if (import.meta.env?.PROD) {
return { error: ActionError.fromJson(json), data: void 0 };
} else {
const error = ActionError.fromJson(json);
error.stack = actionResultErrorStack.get();
return {
error,
data: void 0
};
}
}
if (res.type === "empty") {
return { data: void 0, error: void 0 };
}
return {
data: devalueParse(res.body, {
URL: (href) => new URL(href)
}),
error: void 0
};
}
const actionResultErrorStack = /* @__PURE__ */ function actionResultErrorStackFn() {
let errorStack;
return {
set(stack) {
errorStack = stack;
},
get() {
return errorStack;
}
};
}();
export {
ACTION_ERROR_CODES,
ACTION_QUERY_PARAMS,
ActionError,
ActionInputError,
callSafely,
deserializeActionResult,
getActionQueryString,
isActionError,
isInputError,
serializeActionResult
};

11
node_modules/astro/dist/actions/utils.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import type fsMod from 'node:fs';
import type { APIContext } from '../@types/astro.js';
import type { Locals } from './runtime/middleware.js';
import { type ActionAPIContext } from './runtime/utils.js';
export declare function hasActionPayload(locals: APIContext['locals']): locals is Locals;
export declare function createGetActionResult(locals: APIContext['locals']): APIContext['getActionResult'];
export declare function createCallAction(context: ActionAPIContext): APIContext['callAction'];
/**
* Check whether the Actions config file is present.
*/
export declare function isActionsFilePresent(fs: typeof fsMod, srcDir: URL): Promise<boolean>;

64
node_modules/astro/dist/actions/utils.js generated vendored Normal file
View File

@@ -0,0 +1,64 @@
import * as eslexer from "es-module-lexer";
import { ACTION_API_CONTEXT_SYMBOL } from "./runtime/utils.js";
import { deserializeActionResult, getActionQueryString } from "./runtime/virtual/shared.js";
function hasActionPayload(locals) {
return "_actionPayload" in locals;
}
function createGetActionResult(locals) {
return (actionFn) => {
if (!hasActionPayload(locals) || actionFn.toString() !== getActionQueryString(locals._actionPayload.actionName)) {
return void 0;
}
return deserializeActionResult(locals._actionPayload.actionResult);
};
}
function createCallAction(context) {
return (baseAction, input) => {
Reflect.set(context, ACTION_API_CONTEXT_SYMBOL, true);
const action = baseAction.bind(context);
return action(input);
};
}
let didInitLexer = false;
async function isActionsFilePresent(fs, srcDir) {
if (!didInitLexer) await eslexer.init;
const actionsFile = search(fs, srcDir);
if (!actionsFile) return false;
let contents;
try {
contents = fs.readFileSync(actionsFile, "utf-8");
} catch {
return false;
}
const [, exports] = eslexer.parse(contents, actionsFile.pathname);
for (const exp of exports) {
if (exp.n === "server") {
return true;
}
}
return false;
}
function search(fs, srcDir) {
const paths = [
"actions.mjs",
"actions.js",
"actions.mts",
"actions.ts",
"actions/index.mjs",
"actions/index.js",
"actions/index.mts",
"actions/index.ts"
].map((p) => new URL(p, srcDir));
for (const file of paths) {
if (fs.existsSync(file)) {
return file;
}
}
return void 0;
}
export {
createCallAction,
createGetActionResult,
hasActionPayload,
isActionsFilePresent
};

24
node_modules/astro/dist/assets/build/generate.d.ts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import type PQueue from 'p-queue';
import type { AstroConfig } from '../../@types/astro.js';
import type { BuildPipeline } from '../../core/build/pipeline.js';
import type { Logger } from '../../core/logger/core.js';
import type { MapValue } from '../../type-utils.js';
import type { AssetsGlobalStaticImagesList } from '../types.js';
type AssetEnv = {
logger: Logger;
isSSR: boolean;
count: {
total: number;
current: number;
};
useCache: boolean;
assetsCacheDir: URL;
serverRoot: URL;
clientRoot: URL;
imageConfig: AstroConfig['image'];
assetsFolder: AstroConfig['build']['assets'];
};
export declare function prepareAssetsGenerationEnv(pipeline: BuildPipeline, totalCount: number): Promise<AssetEnv>;
export declare function generateImagesForPath(originalFilePath: string, transformsAndPath: MapValue<AssetsGlobalStaticImagesList>, env: AssetEnv, queue: PQueue): Promise<void>;
export declare function getStaticImageList(): AssetsGlobalStaticImagesList;
export {};

198
node_modules/astro/dist/assets/build/generate.js generated vendored Normal file
View File

@@ -0,0 +1,198 @@
import fs, { readFileSync } from "node:fs";
import { basename } from "node:path/posix";
import { dim, green } from "kleur/colors";
import { getOutDirWithinCwd } from "../../core/build/common.js";
import { getTimeStat } from "../../core/build/util.js";
import { AstroError } from "../../core/errors/errors.js";
import { AstroErrorData } from "../../core/errors/index.js";
import { isRemotePath, removeLeadingForwardSlash } from "../../core/path.js";
import { isServerLikeOutput } from "../../core/util.js";
import { getConfiguredImageService } from "../internal.js";
import { isESMImportedImage } from "../utils/imageKind.js";
import { loadRemoteImage } from "./remote.js";
async function prepareAssetsGenerationEnv(pipeline, totalCount) {
const { config, logger } = pipeline;
let useCache = true;
const assetsCacheDir = new URL("assets/", config.cacheDir);
const count = { total: totalCount, current: 1 };
try {
await fs.promises.mkdir(assetsCacheDir, { recursive: true });
} catch (err) {
logger.warn(
null,
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}`
);
useCache = false;
}
let serverRoot, clientRoot;
if (isServerLikeOutput(config)) {
serverRoot = config.build.server;
clientRoot = config.build.client;
} else {
serverRoot = getOutDirWithinCwd(config.outDir);
clientRoot = config.outDir;
}
return {
logger,
isSSR: isServerLikeOutput(config),
count,
useCache,
assetsCacheDir,
serverRoot,
clientRoot,
imageConfig: config.image,
assetsFolder: config.build.assets
};
}
function getFullImagePath(originalFilePath, env) {
return new URL(removeLeadingForwardSlash(originalFilePath), env.serverRoot);
}
async function generateImagesForPath(originalFilePath, transformsAndPath, env, queue) {
let originalImage;
for (const [_, transform] of transformsAndPath.transforms) {
await queue.add(async () => generateImage(transform.finalPath, transform.transform)).catch((e) => {
throw e;
});
}
if (!env.isSSR && transformsAndPath.originalSrcPath && !globalThis.astroAsset.referencedImages?.has(transformsAndPath.originalSrcPath)) {
try {
if (transformsAndPath.originalSrcPath) {
env.logger.debug(
"assets",
`Deleting ${originalFilePath} as it's not referenced outside of image processing.`
);
await fs.promises.unlink(getFullImagePath(originalFilePath, env));
}
} catch {
}
}
async function generateImage(filepath, options) {
const timeStart = performance.now();
const generationData = await generateImageInternal(filepath, options);
const timeEnd = performance.now();
const timeChange = getTimeStat(timeStart, timeEnd);
const timeIncrease = `(+${timeChange})`;
const statsText = generationData.cached ? `(reused cache entry)` : `(before: ${generationData.weight.before}kB, after: ${generationData.weight.after}kB)`;
const count = `(${env.count.current}/${env.count.total})`;
env.logger.info(
null,
` ${green("\u25B6")} ${filepath} ${dim(statsText)} ${dim(timeIncrease)} ${dim(count)}`
);
env.count.current++;
}
async function generateImageInternal(filepath, options) {
const isLocalImage = isESMImportedImage(options.src);
const finalFileURL = new URL("." + filepath, env.clientRoot);
const finalFolderURL = new URL("./", finalFileURL);
await fs.promises.mkdir(finalFolderURL, { recursive: true });
const cacheFile = basename(filepath) + (isLocalImage ? "" : ".json");
const cachedFileURL = new URL(cacheFile, env.assetsCacheDir);
try {
if (isLocalImage) {
await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
return {
cached: true
};
} else {
const JSONData = JSON.parse(readFileSync(cachedFileURL, "utf-8"));
if (!JSONData.data || !JSONData.expires) {
await fs.promises.unlink(cachedFileURL);
throw new Error(
`Malformed cache entry for ${filepath}, cache will be regenerated for this file.`
);
}
if (JSONData.expires > Date.now()) {
await fs.promises.writeFile(finalFileURL, Buffer.from(JSONData.data, "base64"));
return {
cached: true
};
} else {
await fs.promises.unlink(cachedFileURL);
}
}
} catch (e) {
if (e.code !== "ENOENT") {
throw new Error(`An error was encountered while reading the cache file. Error: ${e}`);
}
}
const originalImagePath = isLocalImage ? options.src.src : options.src;
if (!originalImage) {
originalImage = await loadImage(originalFilePath, env);
}
let resultData = {
data: void 0,
expires: originalImage.expires
};
const imageService = await getConfiguredImageService();
try {
resultData.data = (await imageService.transform(
originalImage.data,
{ ...options, src: originalImagePath },
env.imageConfig
)).data;
} catch (e) {
const error = new AstroError(
{
...AstroErrorData.CouldNotTransformImage,
message: AstroErrorData.CouldNotTransformImage.message(originalFilePath)
},
{ cause: e }
);
throw error;
}
try {
if (env.useCache) {
if (isLocalImage) {
await fs.promises.writeFile(cachedFileURL, resultData.data);
} else {
await fs.promises.writeFile(
cachedFileURL,
JSON.stringify({
data: Buffer.from(resultData.data).toString("base64"),
expires: resultData.expires
})
);
}
}
} catch (e) {
env.logger.warn(
null,
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
);
} finally {
await fs.promises.writeFile(finalFileURL, resultData.data);
}
return {
cached: false,
weight: {
// Divide by 1024 to get size in kilobytes
before: Math.trunc(originalImage.data.byteLength / 1024),
after: Math.trunc(Buffer.from(resultData.data).byteLength / 1024)
}
};
}
}
function getStaticImageList() {
if (!globalThis?.astroAsset?.staticImages) {
return /* @__PURE__ */ new Map();
}
return globalThis.astroAsset.staticImages;
}
async function loadImage(path, env) {
if (isRemotePath(path)) {
const remoteImage = await loadRemoteImage(path);
return {
data: remoteImage.data,
expires: remoteImage.expires
};
}
return {
data: await fs.promises.readFile(getFullImagePath(path, env)),
expires: 0
};
}
export {
generateImagesForPath,
getStaticImageList,
prepareAssetsGenerationEnv
};

8
node_modules/astro/dist/assets/build/remote.d.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
export type RemoteCacheEntry = {
data: string;
expires: number;
};
export declare function loadRemoteImage(src: string): Promise<{
data: Buffer;
expires: number;
}>;

42
node_modules/astro/dist/assets/build/remote.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
import CachePolicy from "http-cache-semantics";
async function loadRemoteImage(src) {
const req = new Request(src);
const res = await fetch(req);
if (!res.ok) {
throw new Error(
`Failed to load remote image ${src}. The request did not return a 200 OK response. (received ${res.status}))`
);
}
const policy = new CachePolicy(webToCachePolicyRequest(req), webToCachePolicyResponse(res));
const expires = policy.storable() ? policy.timeToLive() : 0;
return {
data: Buffer.from(await res.arrayBuffer()),
expires: Date.now() + expires
};
}
function webToCachePolicyRequest({ url, method, headers: _headers }) {
let headers = {};
try {
headers = Object.fromEntries(_headers.entries());
} catch {
}
return {
method,
url,
headers
};
}
function webToCachePolicyResponse({ status, headers: _headers }) {
let headers = {};
try {
headers = Object.fromEntries(_headers.entries());
} catch {
}
return {
status,
headers
};
}
export {
loadRemoteImage
};

11
node_modules/astro/dist/assets/consts.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
export declare const VIRTUAL_MODULE_ID = "astro:assets";
export declare const VIRTUAL_SERVICE_ID = "virtual:image-service";
export declare const VALID_INPUT_FORMATS: readonly ["jpeg", "jpg", "png", "tiff", "webp", "gif", "svg", "avif"];
/**
* Valid formats that our base services support.
* Certain formats can be imported (namely SVGs) but will not be processed.
*/
export declare const VALID_SUPPORTED_FORMATS: readonly ["jpeg", "jpg", "png", "tiff", "webp", "gif", "svg", "avif"];
export declare const DEFAULT_OUTPUT_FORMAT: "webp";
export declare const VALID_OUTPUT_FORMATS: readonly ["avif", "png", "webp", "jpeg", "jpg", "svg"];
export declare const DEFAULT_HASH_PROPS: string[];

34
node_modules/astro/dist/assets/consts.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
const VIRTUAL_MODULE_ID = "astro:assets";
const VIRTUAL_SERVICE_ID = "virtual:image-service";
const VALID_INPUT_FORMATS = [
"jpeg",
"jpg",
"png",
"tiff",
"webp",
"gif",
"svg",
"avif"
];
const VALID_SUPPORTED_FORMATS = [
"jpeg",
"jpg",
"png",
"tiff",
"webp",
"gif",
"svg",
"avif"
];
const DEFAULT_OUTPUT_FORMAT = "webp";
const VALID_OUTPUT_FORMATS = ["avif", "png", "webp", "jpeg", "jpg", "svg"];
const DEFAULT_HASH_PROPS = ["src", "width", "height", "format", "quality"];
export {
DEFAULT_HASH_PROPS,
DEFAULT_OUTPUT_FORMAT,
VALID_INPUT_FORMATS,
VALID_OUTPUT_FORMATS,
VALID_SUPPORTED_FORMATS,
VIRTUAL_MODULE_ID,
VIRTUAL_SERVICE_ID
};

2
node_modules/astro/dist/assets/endpoint/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
import type { AstroSettings } from '../../@types/astro.js';
export declare function injectImageEndpoint(settings: AstroSettings, mode: 'dev' | 'build'): AstroSettings;

12
node_modules/astro/dist/assets/endpoint/config.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
function injectImageEndpoint(settings, mode) {
const endpointEntrypoint = settings.config.image.endpoint ?? (mode === "dev" ? "astro/assets/endpoint/node" : "astro/assets/endpoint/generic");
settings.injectedRoutes.push({
pattern: "/_image",
entrypoint: endpointEntrypoint,
prerender: false
});
return settings;
}
export {
injectImageEndpoint
};

5
node_modules/astro/dist/assets/endpoint/generic.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import type { APIRoute } from '../../@types/astro.js';
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export declare const GET: APIRoute;

63
node_modules/astro/dist/assets/endpoint/generic.js generated vendored Normal file
View File

@@ -0,0 +1,63 @@
import { imageConfig } from "astro:assets";
import { isRemotePath } from "@astrojs/internal-helpers/path";
import * as mime from "mrmime";
import { getConfiguredImageService } from "../internal.js";
import { etag } from "../utils/etag.js";
import { isRemoteAllowed } from "../utils/remotePattern.js";
async function loadRemoteImage(src, headers) {
try {
const res = await fetch(src, {
// Forward all headers from the original request
headers
});
if (!res.ok) {
return void 0;
}
return await res.arrayBuffer();
} catch {
return void 0;
}
}
const GET = async ({ request }) => {
try {
const imageService = await getConfiguredImageService();
if (!("transform" in imageService)) {
throw new Error("Configured image service is not a local service");
}
const url = new URL(request.url);
const transform = await imageService.parseURL(url, imageConfig);
if (!transform?.src) {
throw new Error("Incorrect transform returned by `parseURL`");
}
let inputBuffer = void 0;
const isRemoteImage = isRemotePath(transform.src);
const sourceUrl = isRemoteImage ? new URL(transform.src) : new URL(transform.src, url.origin);
if (isRemoteImage && isRemoteAllowed(transform.src, imageConfig) === false) {
return new Response("Forbidden", { status: 403 });
}
inputBuffer = await loadRemoteImage(sourceUrl, isRemoteImage ? new Headers() : request.headers);
if (!inputBuffer) {
return new Response("Not Found", { status: 404 });
}
const { data, format } = await imageService.transform(
new Uint8Array(inputBuffer),
transform,
imageConfig
);
return new Response(data, {
status: 200,
headers: {
"Content-Type": mime.lookup(format) ?? `image/${format}`,
"Cache-Control": "public, max-age=31536000",
ETag: etag(data.toString()),
Date: (/* @__PURE__ */ new Date()).toUTCString()
}
});
} catch (err) {
console.error("Could not process image request:", err);
return new Response(`Server Error: ${err}`, { status: 500 });
}
};
export {
GET
};

5
node_modules/astro/dist/assets/endpoint/node.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import type { APIRoute } from '../../@types/astro.js';
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export declare const GET: APIRoute;

108
node_modules/astro/dist/assets/endpoint/node.js generated vendored Normal file
View File

@@ -0,0 +1,108 @@
import { readFile } from "node:fs/promises";
import os from "node:os";
import { isAbsolute } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { assetsDir, imageConfig, outDir } from "astro:assets";
import { isRemotePath, removeQueryString } from "@astrojs/internal-helpers/path";
import * as mime from "mrmime";
import { getConfiguredImageService } from "../internal.js";
import { etag } from "../utils/etag.js";
import { isRemoteAllowed } from "../utils/remotePattern.js";
function replaceFileSystemReferences(src) {
return os.platform().includes("win32") ? src.replace(/^\/@fs\//, "") : src.replace(/^\/@fs/, "");
}
async function loadLocalImage(src, url) {
const assetsDirPath = fileURLToPath(assetsDir);
let fileUrl;
if (import.meta.env.DEV) {
fileUrl = pathToFileURL(removeQueryString(replaceFileSystemReferences(src)));
} else {
try {
const idx = url.pathname.indexOf("/_image");
if (idx > 0) {
src = src.slice(idx);
}
fileUrl = new URL("." + src, outDir);
const filePath = fileURLToPath(fileUrl);
if (!isAbsolute(filePath) || !filePath.startsWith(assetsDirPath)) {
return void 0;
}
} catch {
return void 0;
}
}
let buffer = void 0;
try {
buffer = await readFile(fileUrl);
} catch {
try {
const sourceUrl = new URL(src, url.origin);
buffer = await loadRemoteImage(sourceUrl);
} catch (err) {
console.error("Could not process image request:", err);
return void 0;
}
}
return buffer;
}
async function loadRemoteImage(src) {
try {
const res = await fetch(src);
if (!res.ok) {
return void 0;
}
return Buffer.from(await res.arrayBuffer());
} catch {
return void 0;
}
}
const GET = async ({ request }) => {
try {
const imageService = await getConfiguredImageService();
if (!("transform" in imageService)) {
throw new Error("Configured image service is not a local service");
}
const url = new URL(request.url);
const transform = await imageService.parseURL(url, imageConfig);
if (!transform?.src) {
const err = new Error(
"Incorrect transform returned by `parseURL`. Expected a transform with a `src` property."
);
console.error("Could not parse image transform from URL:", err);
return new Response("Internal Server Error", { status: 500 });
}
let inputBuffer = void 0;
if (isRemotePath(transform.src)) {
if (isRemoteAllowed(transform.src, imageConfig) === false) {
return new Response("Forbidden", { status: 403 });
}
inputBuffer = await loadRemoteImage(new URL(transform.src));
} else {
inputBuffer = await loadLocalImage(transform.src, url);
}
if (!inputBuffer) {
return new Response("Internal Server Error", { status: 500 });
}
const { data, format } = await imageService.transform(inputBuffer, transform, imageConfig);
return new Response(data, {
status: 200,
headers: {
"Content-Type": mime.lookup(format) ?? `image/${format}`,
"Cache-Control": "public, max-age=31536000",
ETag: etag(data.toString()),
Date: (/* @__PURE__ */ new Date()).toUTCString()
}
});
} catch (err) {
console.error("Could not process image request:", err);
return new Response(
import.meta.env.DEV ? `Could not process image request: ${err}` : `Internal Server Error`,
{
status: 500
}
);
}
};
export {
GET
};

3
node_modules/astro/dist/assets/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
export { getConfiguredImageService, getImage } from './internal.js';
export { baseService, isLocalService } from './services/service.js';
export { type LocalImageProps, type RemoteImageProps } from './types.js';

9
node_modules/astro/dist/assets/index.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import { getConfiguredImageService, getImage } from "./internal.js";
import { baseService, isLocalService } from "./services/service.js";
import {} from "./types.js";
export {
baseService,
getConfiguredImageService,
getImage,
isLocalService
};

5
node_modules/astro/dist/assets/internal.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import type { AstroConfig } from '../@types/astro.js';
import { type ImageService } from './services/service.js';
import { type GetImageResult, type UnresolvedImageTransform } from './types.js';
export declare function getConfiguredImageService(): Promise<ImageService>;
export declare function getImage(options: UnresolvedImageTransform, imageConfig: AstroConfig['image']): Promise<GetImageResult>;

102
node_modules/astro/dist/assets/internal.js generated vendored Normal file
View File

@@ -0,0 +1,102 @@
import { isRemotePath } from "@astrojs/internal-helpers/path";
import { AstroError, AstroErrorData } from "../core/errors/index.js";
import { DEFAULT_HASH_PROPS } from "./consts.js";
import { isLocalService } from "./services/service.js";
import {
isImageMetadata
} from "./types.js";
import { isESMImportedImage, isRemoteImage, resolveSrc } from "./utils/imageKind.js";
import { inferRemoteSize } from "./utils/remoteProbe.js";
async function getConfiguredImageService() {
if (!globalThis?.astroAsset?.imageService) {
const { default: service } = await import(
// @ts-expect-error
"virtual:image-service"
).catch((e) => {
const error = new AstroError(AstroErrorData.InvalidImageService);
error.cause = e;
throw error;
});
if (!globalThis.astroAsset) globalThis.astroAsset = {};
globalThis.astroAsset.imageService = service;
return service;
}
return globalThis.astroAsset.imageService;
}
async function getImage(options, imageConfig) {
if (!options || typeof options !== "object") {
throw new AstroError({
...AstroErrorData.ExpectedImageOptions,
message: AstroErrorData.ExpectedImageOptions.message(JSON.stringify(options))
});
}
if (typeof options.src === "undefined") {
throw new AstroError({
...AstroErrorData.ExpectedImage,
message: AstroErrorData.ExpectedImage.message(
options.src,
"undefined",
JSON.stringify(options)
)
});
}
if (isImageMetadata(options)) {
throw new AstroError(AstroErrorData.ExpectedNotESMImage);
}
const service = await getConfiguredImageService();
const resolvedOptions = {
...options,
src: await resolveSrc(options.src)
};
if (options.inferSize && isRemoteImage(resolvedOptions.src) && isRemotePath(resolvedOptions.src)) {
const result = await inferRemoteSize(resolvedOptions.src);
resolvedOptions.width ??= result.width;
resolvedOptions.height ??= result.height;
delete resolvedOptions.inferSize;
}
const originalFilePath = isESMImportedImage(resolvedOptions.src) ? resolvedOptions.src.fsPath : void 0;
const clonedSrc = isESMImportedImage(resolvedOptions.src) ? (
// @ts-expect-error - clone is a private, hidden prop
resolvedOptions.src.clone ?? resolvedOptions.src
) : resolvedOptions.src;
resolvedOptions.src = clonedSrc;
const validatedOptions = service.validateOptions ? await service.validateOptions(resolvedOptions, imageConfig) : resolvedOptions;
const srcSetTransforms = service.getSrcSet ? await service.getSrcSet(validatedOptions, imageConfig) : [];
let imageURL = await service.getURL(validatedOptions, imageConfig);
let srcSets = await Promise.all(
srcSetTransforms.map(async (srcSet) => ({
transform: srcSet.transform,
url: await service.getURL(srcSet.transform, imageConfig),
descriptor: srcSet.descriptor,
attributes: srcSet.attributes
}))
);
if (isLocalService(service) && globalThis.astroAsset.addStaticImage && !(isRemoteImage(validatedOptions.src) && imageURL === validatedOptions.src)) {
const propsToHash = service.propertiesToHash ?? DEFAULT_HASH_PROPS;
imageURL = globalThis.astroAsset.addStaticImage(
validatedOptions,
propsToHash,
originalFilePath
);
srcSets = srcSetTransforms.map((srcSet) => ({
transform: srcSet.transform,
url: globalThis.astroAsset.addStaticImage(srcSet.transform, propsToHash, originalFilePath),
descriptor: srcSet.descriptor,
attributes: srcSet.attributes
}));
}
return {
rawOptions: resolvedOptions,
options: validatedOptions,
src: imageURL,
srcSet: {
values: srcSets,
attribute: srcSets.map((srcSet) => `${srcSet.url} ${srcSet.descriptor}`).join(", ")
},
attributes: service.getHTMLAttributes !== void 0 ? await service.getHTMLAttributes(validatedOptions, imageConfig) : {}
};
}
export {
getConfiguredImageService,
getImage
};

3
node_modules/astro/dist/assets/services/noop.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import { type LocalImageService } from './service.js';
declare const noopService: LocalImageService;
export default noopService;

15
node_modules/astro/dist/assets/services/noop.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import { baseService } from "./service.js";
const noopService = {
...baseService,
propertiesToHash: ["src"],
async transform(inputBuffer, transformOptions) {
return {
data: inputBuffer,
format: transformOptions.format
};
}
};
var noop_default = noopService;
export {
noop_default as default
};

101
node_modules/astro/dist/assets/services/service.d.ts generated vendored Normal file
View File

@@ -0,0 +1,101 @@
import type { AstroConfig } from '../../@types/astro.js';
import type { ImageOutputFormat, ImageTransform, UnresolvedSrcSetValue } from '../types.js';
export type ImageService = LocalImageService | ExternalImageService;
export declare function isLocalService(service: ImageService | undefined): service is LocalImageService;
export declare function parseQuality(quality: string): string | number;
type ImageConfig<T> = Omit<AstroConfig['image'], 'service'> & {
service: {
entrypoint: string;
config: T;
};
};
interface SharedServiceProps<T extends Record<string, any> = Record<string, any>> {
/**
* Return the URL to the endpoint or URL your images are generated from.
*
* For a local service, your service should expose an endpoint handling the image requests, or use Astro's at `/_image`.
*
* For external services, this should point to the URL your images are coming from, for instance, `/_vercel/image`
*
*/
getURL: (options: ImageTransform, imageConfig: ImageConfig<T>) => string | Promise<string>;
/**
* Generate additional `srcset` values for the image.
*
* While in most cases this is exclusively used for `srcset`, it can also be used in a more generic way to generate
* multiple variants of the same image. For instance, you can use this to generate multiple aspect ratios or multiple formats.
*/
getSrcSet?: (options: ImageTransform, imageConfig: ImageConfig<T>) => UnresolvedSrcSetValue[] | Promise<UnresolvedSrcSetValue[]>;
/**
* Return any additional HTML attributes separate from `src` that your service requires to show the image properly.
*
* For example, you might want to return the `width` and `height` to avoid CLS, or a particular `class` or `style`.
* In most cases, you'll want to return directly what your user supplied you, minus the attributes that were used to generate the image.
*/
getHTMLAttributes?: (options: ImageTransform, imageConfig: ImageConfig<T>) => Record<string, any> | Promise<Record<string, any>>;
/**
* Validate and return the options passed by the user.
*
* This method is useful to present errors to users who have entered invalid options.
* For instance, if they are missing a required property or have entered an invalid image format.
*
* This method should returns options, and can be used to set defaults (ex: a default output format to be used if the user didn't specify one.)
*/
validateOptions?: (options: ImageTransform, imageConfig: ImageConfig<T>) => ImageTransform | Promise<ImageTransform>;
}
export type ExternalImageService<T extends Record<string, any> = Record<string, any>> = SharedServiceProps<T>;
export type LocalImageTransform = {
src: string;
[key: string]: any;
};
export interface LocalImageService<T extends Record<string, any> = Record<string, any>> extends SharedServiceProps<T> {
/**
* Parse the requested parameters passed in the URL from `getURL` back into an object to be used later by `transform`.
*
* In most cases, this will get query parameters using, for example, `params.get('width')` and return those.
*/
parseURL: (url: URL, imageConfig: ImageConfig<T>) => LocalImageTransform | undefined | Promise<LocalImageTransform> | Promise<undefined>;
/**
* Performs the image transformations on the input image and returns both the binary data and
* final image format of the optimized image.
*/
transform: (inputBuffer: Uint8Array, transform: LocalImageTransform, imageConfig: ImageConfig<T>) => Promise<{
data: Uint8Array;
format: ImageOutputFormat;
}>;
/**
* A list of properties that should be used to generate the hash for the image.
*
* Generally, this should be all the properties that can change the result of the image. By default, this is `src`, `width`, `height`, `quality`, and `format`.
*/
propertiesToHash?: string[];
}
export type BaseServiceTransform = {
src: string;
width?: number;
height?: number;
format: string;
quality?: string | null;
};
/**
* Basic local service using the included `_image` endpoint.
* This service intentionally does not implement `transform`.
*
* Example usage:
* ```ts
* const service = {
* getURL: baseService.getURL,
* parseURL: baseService.parseURL,
* getHTMLAttributes: baseService.getHTMLAttributes,
* async transform(inputBuffer, transformOptions) {...}
* }
* ```
*
* This service adhere to the included services limitations:
* - Remote images are passed as is.
* - Only a limited amount of formats are supported.
* - For remote images, `width` and `height` are always required.
*
*/
export declare const baseService: Omit<LocalImageService, 'transform'>;
export {};

211
node_modules/astro/dist/assets/services/service.js generated vendored Normal file
View File

@@ -0,0 +1,211 @@
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
import { isRemotePath, joinPaths } from "../../core/path.js";
import { DEFAULT_HASH_PROPS, DEFAULT_OUTPUT_FORMAT, VALID_SUPPORTED_FORMATS } from "../consts.js";
import { isESMImportedImage } from "../utils/imageKind.js";
import { isRemoteAllowed } from "../utils/remotePattern.js";
function isLocalService(service) {
if (!service) {
return false;
}
return "transform" in service;
}
function parseQuality(quality) {
let result = parseInt(quality);
if (Number.isNaN(result)) {
return quality;
}
return result;
}
const baseService = {
propertiesToHash: DEFAULT_HASH_PROPS,
validateOptions(options) {
if (!options.src || typeof options.src !== "string" && typeof options.src !== "object") {
throw new AstroError({
...AstroErrorData.ExpectedImage,
message: AstroErrorData.ExpectedImage.message(
JSON.stringify(options.src),
typeof options.src,
JSON.stringify(options, (_, v) => v === void 0 ? null : v)
)
});
}
if (!isESMImportedImage(options.src)) {
if (options.src.startsWith("/@fs/") || !isRemotePath(options.src) && !options.src.startsWith("/")) {
throw new AstroError({
...AstroErrorData.LocalImageUsedWrongly,
message: AstroErrorData.LocalImageUsedWrongly.message(options.src)
});
}
let missingDimension;
if (!options.width && !options.height) {
missingDimension = "both";
} else if (!options.width && options.height) {
missingDimension = "width";
} else if (options.width && !options.height) {
missingDimension = "height";
}
if (missingDimension) {
throw new AstroError({
...AstroErrorData.MissingImageDimension,
message: AstroErrorData.MissingImageDimension.message(missingDimension, options.src)
});
}
} else {
if (!VALID_SUPPORTED_FORMATS.includes(options.src.format)) {
throw new AstroError({
...AstroErrorData.UnsupportedImageFormat,
message: AstroErrorData.UnsupportedImageFormat.message(
options.src.format,
options.src.src,
VALID_SUPPORTED_FORMATS
)
});
}
if (options.widths && options.densities) {
throw new AstroError(AstroErrorData.IncompatibleDescriptorOptions);
}
if (options.src.format === "svg") {
options.format = "svg";
}
if (options.src.format === "svg" && options.format !== "svg" || options.src.format !== "svg" && options.format === "svg") {
throw new AstroError(AstroErrorData.UnsupportedImageConversion);
}
}
if (!options.format) {
options.format = DEFAULT_OUTPUT_FORMAT;
}
if (options.width) options.width = Math.round(options.width);
if (options.height) options.height = Math.round(options.height);
return options;
},
getHTMLAttributes(options) {
const { targetWidth, targetHeight } = getTargetDimensions(options);
const { src, width, height, format, quality, densities, widths, formats, ...attributes } = options;
return {
...attributes,
width: targetWidth,
height: targetHeight,
loading: attributes.loading ?? "lazy",
decoding: attributes.decoding ?? "async"
};
},
getSrcSet(options) {
const srcSet = [];
const { targetWidth } = getTargetDimensions(options);
const { widths, densities } = options;
const targetFormat = options.format ?? DEFAULT_OUTPUT_FORMAT;
let imageWidth = options.width;
let maxWidth = Infinity;
if (isESMImportedImage(options.src)) {
imageWidth = options.src.width;
maxWidth = imageWidth;
}
const {
width: transformWidth,
height: transformHeight,
...transformWithoutDimensions
} = options;
const allWidths = [];
if (densities) {
const densityValues = densities.map((density) => {
if (typeof density === "number") {
return density;
} else {
return parseFloat(density);
}
});
const densityWidths = densityValues.sort().map((density) => Math.round(targetWidth * density));
allWidths.push(
...densityWidths.map((width, index) => ({
maxTargetWidth: Math.min(width, maxWidth),
descriptor: `${densityValues[index]}x`
}))
);
} else if (widths) {
allWidths.push(
...widths.map((width) => ({
maxTargetWidth: Math.min(width, maxWidth),
descriptor: `${width}w`
}))
);
}
for (const { maxTargetWidth, descriptor } of allWidths) {
const srcSetTransform = { ...transformWithoutDimensions };
if (maxTargetWidth !== imageWidth) {
srcSetTransform.width = maxTargetWidth;
} else {
if (options.width && options.height) {
srcSetTransform.width = options.width;
srcSetTransform.height = options.height;
}
}
srcSet.push({
transform: srcSetTransform,
descriptor,
attributes: {
type: `image/${targetFormat}`
}
});
}
return srcSet;
},
getURL(options, imageConfig) {
const searchParams = new URLSearchParams();
if (isESMImportedImage(options.src)) {
searchParams.append("href", options.src.src);
} else if (isRemoteAllowed(options.src, imageConfig)) {
searchParams.append("href", options.src);
} else {
return options.src;
}
const params = {
w: "width",
h: "height",
q: "quality",
f: "format"
};
Object.entries(params).forEach(([param, key]) => {
options[key] && searchParams.append(param, options[key].toString());
});
const imageEndpoint = joinPaths(import.meta.env.BASE_URL, "/_image");
return `${imageEndpoint}?${searchParams}`;
},
parseURL(url) {
const params = url.searchParams;
if (!params.has("href")) {
return void 0;
}
const transform = {
src: params.get("href"),
width: params.has("w") ? parseInt(params.get("w")) : void 0,
height: params.has("h") ? parseInt(params.get("h")) : void 0,
format: params.get("f"),
quality: params.get("q")
};
return transform;
}
};
function getTargetDimensions(options) {
let targetWidth = options.width;
let targetHeight = options.height;
if (isESMImportedImage(options.src)) {
const aspectRatio = options.src.width / options.src.height;
if (targetHeight && !targetWidth) {
targetWidth = Math.round(targetHeight * aspectRatio);
} else if (targetWidth && !targetHeight) {
targetHeight = Math.round(targetWidth / aspectRatio);
} else if (!targetWidth && !targetHeight) {
targetWidth = options.src.width;
targetHeight = options.src.height;
}
}
return {
targetWidth,
targetHeight
};
}
export {
baseService,
isLocalService,
parseQuality
};

10
node_modules/astro/dist/assets/services/sharp.d.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
import type { SharpOptions } from 'sharp';
import { type LocalImageService } from './service.js';
export interface SharpImageServiceConfig {
/**
* The `limitInputPixels` option passed to Sharp. See https://sharp.pixelplumbing.com/api-constructor for more information
*/
limitInputPixels?: SharpOptions['limitInputPixels'];
}
declare const sharpService: LocalImageService<SharpImageServiceConfig>;
export default sharpService;

66
node_modules/astro/dist/assets/services/sharp.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
import {
baseService,
parseQuality
} from "./service.js";
let sharp;
const qualityTable = {
low: 25,
mid: 50,
high: 80,
max: 100
};
async function loadSharp() {
let sharpImport;
try {
sharpImport = (await import("sharp")).default;
} catch {
throw new AstroError(AstroErrorData.MissingSharp);
}
sharpImport.cache(false);
return sharpImport;
}
const sharpService = {
validateOptions: baseService.validateOptions,
getURL: baseService.getURL,
parseURL: baseService.parseURL,
getHTMLAttributes: baseService.getHTMLAttributes,
getSrcSet: baseService.getSrcSet,
async transform(inputBuffer, transformOptions, config) {
if (!sharp) sharp = await loadSharp();
const transform = transformOptions;
if (transform.format === "svg") return { data: inputBuffer, format: "svg" };
const result = sharp(inputBuffer, {
failOnError: false,
pages: -1,
limitInputPixels: config.service.config.limitInputPixels
});
result.rotate();
if (transform.height && !transform.width) {
result.resize({ height: Math.round(transform.height) });
} else if (transform.width) {
result.resize({ width: Math.round(transform.width) });
}
if (transform.format) {
let quality = void 0;
if (transform.quality) {
const parsedQuality = parseQuality(transform.quality);
if (typeof parsedQuality === "number") {
quality = parsedQuality;
} else {
quality = transform.quality in qualityTable ? qualityTable[transform.quality] : void 0;
}
}
result.toFormat(transform.format, { quality });
}
const { data, info } = await result.toBuffer({ resolveWithObject: true });
return {
data,
format: info.format
};
}
};
var sharp_default = sharpService;
export {
sharp_default as default
};

3
node_modules/astro/dist/assets/services/squoosh.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import { type LocalImageService } from './service.js';
declare const service: LocalImageService;
export default service;

90
node_modules/astro/dist/assets/services/squoosh.js generated vendored Normal file
View File

@@ -0,0 +1,90 @@
import { yellow } from "kleur/colors";
import { imageMetadata } from "../utils/metadata.js";
import {
baseService,
parseQuality
} from "./service.js";
import { processBuffer } from "./vendor/squoosh/image-pool.js";
console.warn(
yellow(
"The Squoosh image service is deprecated and will be removed in Astro 5.x. We suggest migrating to the default Sharp image service instead, as it is faster, more powerful and better maintained."
)
);
const baseQuality = { low: 25, mid: 50, high: 80, max: 100 };
const qualityTable = {
avif: {
// Squoosh's AVIF encoder has a bit of a weird behavior where `62` is technically the maximum, and anything over is overkill
max: 62,
high: 45,
mid: 35,
low: 20
},
jpeg: baseQuality,
jpg: baseQuality,
webp: baseQuality
// Squoosh's PNG encoder does not support a quality setting, so we can skip that here
};
async function getRotationForEXIF(inputBuffer, src) {
const meta = await imageMetadata(inputBuffer, src);
if (!meta) return void 0;
switch (meta.orientation) {
case 3:
case 4:
return { type: "rotate", numRotations: 2 };
case 5:
case 6:
return { type: "rotate", numRotations: 1 };
case 7:
case 8:
return { type: "rotate", numRotations: 3 };
case void 0:
default:
return void 0;
}
}
const service = {
validateOptions: baseService.validateOptions,
getURL: baseService.getURL,
parseURL: baseService.parseURL,
getHTMLAttributes: baseService.getHTMLAttributes,
getSrcSet: baseService.getSrcSet,
async transform(inputBuffer, transformOptions) {
const transform = transformOptions;
let format = transform.format;
if (format === "svg") return { data: inputBuffer, format: "svg" };
const operations = [];
const rotation = await getRotationForEXIF(inputBuffer, transform.src);
if (rotation) {
operations.push(rotation);
}
if (transform.height && !transform.width) {
operations.push({
type: "resize",
height: Math.round(transform.height)
});
} else if (transform.width) {
operations.push({
type: "resize",
width: Math.round(transform.width)
});
}
let quality = void 0;
if (transform.quality) {
const parsedQuality = parseQuality(transform.quality);
if (typeof parsedQuality === "number") {
quality = parsedQuality;
} else {
quality = transform.quality in qualityTable[format] ? qualityTable[format][transform.quality] : void 0;
}
}
const data = await processBuffer(inputBuffer, operations, format, quality);
return {
data: Buffer.from(data),
format
};
}
};
var squoosh_default = service;
export {
squoosh_default as default
};

View File

@@ -0,0 +1,11 @@
var AVIFTune = /* @__PURE__ */ ((AVIFTune2) => {
AVIFTune2[AVIFTune2["auto"] = 0] = "auto";
AVIFTune2[AVIFTune2["psnr"] = 1] = "psnr";
AVIFTune2[AVIFTune2["ssim"] = 2] = "ssim";
return AVIFTune2;
})(AVIFTune || {});
var avif_enc_d_default = moduleFactory;
export {
AVIFTune,
avif_enc_d_default as default
};

View File

@@ -0,0 +1,2 @@
declare var Module: (Module: any) => any;
export default Module;

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,2 @@
declare const _default: Buffer;
export default _default;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
declare var Module: (Module: any) => any;
export default Module;

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,2 @@
declare const _default: Buffer;
export default _default;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,157 @@
interface DecodeModule extends EmscriptenWasm.Module {
decode: (data: Uint8Array) => ImageData;
}
export interface ResizeOptions {
width?: number;
height?: number;
method: 'triangle' | 'catrom' | 'mitchell' | 'lanczos3';
premultiply: boolean;
linearRGB: boolean;
}
export interface RotateOptions {
numRotations: number;
}
import type { MozJPEGModule as MozJPEGEncodeModule } from './mozjpeg/mozjpeg_enc.js';
import type { WebPModule as WebPEncodeModule } from './webp/webp_enc.js';
import type { AVIFModule as AVIFEncodeModule } from './avif/avif_enc.js';
import ImageData from './image_data.js';
export declare const preprocessors: {
readonly resize: {
readonly name: "Resize";
readonly description: "Resize the image before compressing";
readonly instantiate: () => Promise<(buffer: Uint8Array, input_width: number, input_height: number, { width, height, method, premultiply, linearRGB }: ResizeOptions) => ImageData>;
readonly defaultOptions: {
readonly method: "lanczos3";
readonly fitMethod: "stretch";
readonly premultiply: true;
readonly linearRGB: true;
};
};
readonly rotate: {
readonly name: "Rotate";
readonly description: "Rotate image";
readonly instantiate: () => Promise<(buffer: Uint8Array, width: number, height: number, { numRotations }: RotateOptions) => Promise<ImageData>>;
readonly defaultOptions: {
readonly numRotations: 0;
};
};
};
export declare const codecs: {
readonly mozjpeg: {
readonly name: "MozJPEG";
readonly extension: "jpg";
readonly detectors: readonly [RegExp];
readonly dec: () => Promise<DecodeModule>;
readonly enc: () => Promise<MozJPEGEncodeModule>;
readonly defaultEncoderOptions: {
readonly quality: 75;
readonly baseline: false;
readonly arithmetic: false;
readonly progressive: true;
readonly optimize_coding: true;
readonly smoothing: 0;
readonly color_space: 3;
readonly quant_table: 3;
readonly trellis_multipass: false;
readonly trellis_opt_zero: false;
readonly trellis_opt_table: false;
readonly trellis_loops: 1;
readonly auto_subsample: true;
readonly chroma_subsample: 2;
readonly separate_chroma_quality: false;
readonly chroma_quality: 75;
};
readonly autoOptimize: {
readonly option: "quality";
readonly min: 0;
readonly max: 100;
};
};
readonly webp: {
readonly name: "WebP";
readonly extension: "webp";
readonly detectors: readonly [RegExp];
readonly dec: () => Promise<DecodeModule>;
readonly enc: () => Promise<WebPEncodeModule>;
readonly defaultEncoderOptions: {
readonly quality: 75;
readonly target_size: 0;
readonly target_PSNR: 0;
readonly method: 4;
readonly sns_strength: 50;
readonly filter_strength: 60;
readonly filter_sharpness: 0;
readonly filter_type: 1;
readonly partitions: 0;
readonly segments: 4;
readonly pass: 1;
readonly show_compressed: 0;
readonly preprocessing: 0;
readonly autofilter: 0;
readonly partition_limit: 0;
readonly alpha_compression: 1;
readonly alpha_filtering: 1;
readonly alpha_quality: 100;
readonly lossless: 0;
readonly exact: 0;
readonly image_hint: 0;
readonly emulate_jpeg_size: 0;
readonly thread_level: 0;
readonly low_memory: 0;
readonly near_lossless: 100;
readonly use_delta_palette: 0;
readonly use_sharp_yuv: 0;
};
readonly autoOptimize: {
readonly option: "quality";
readonly min: 0;
readonly max: 100;
};
};
readonly avif: {
readonly name: "AVIF";
readonly extension: "avif";
readonly detectors: readonly [RegExp];
readonly dec: () => Promise<DecodeModule>;
readonly enc: () => Promise<AVIFEncodeModule>;
readonly defaultEncoderOptions: {
readonly cqLevel: 33;
readonly cqAlphaLevel: -1;
readonly denoiseLevel: 0;
readonly tileColsLog2: 0;
readonly tileRowsLog2: 0;
readonly speed: 6;
readonly subsample: 1;
readonly chromaDeltaQ: false;
readonly sharpness: 0;
readonly tune: 0;
};
readonly autoOptimize: {
readonly option: "cqLevel";
readonly min: 62;
readonly max: 0;
};
};
readonly oxipng: {
readonly name: "OxiPNG";
readonly extension: "png";
readonly detectors: readonly [RegExp];
readonly dec: () => Promise<{
decode: (buffer: Buffer | Uint8Array) => any;
}>;
readonly enc: () => Promise<{
encode: (buffer: Uint8ClampedArray | ArrayBuffer, width: number, height: number, opts: {
level: number;
}) => any;
}>;
readonly defaultEncoderOptions: {
readonly level: 2;
};
readonly autoOptimize: {
readonly option: "level";
readonly min: 6;
readonly max: 1;
};
};
};
export {};

View File

@@ -0,0 +1,287 @@
import { instantiateEmscriptenWasm } from "./emscripten-utils.js";
import mozDec from "./mozjpeg/mozjpeg_node_dec.js";
import mozDecWasm from "./mozjpeg/mozjpeg_node_dec.wasm.js";
import mozEnc from "./mozjpeg/mozjpeg_node_enc.js";
import mozEncWasm from "./mozjpeg/mozjpeg_node_enc.wasm.js";
import webpDec from "./webp/webp_node_dec.js";
import webpDecWasm from "./webp/webp_node_dec.wasm.js";
import webpEnc from "./webp/webp_node_enc.js";
import webpEncWasm from "./webp/webp_node_enc.wasm.js";
import avifDec from "./avif/avif_node_dec.js";
import avifDecWasm from "./avif/avif_node_dec.wasm.js";
import avifEnc from "./avif/avif_node_enc.js";
import avifEncWasm from "./avif/avif_node_enc.wasm.js";
import * as pngEncDec from "./png/squoosh_png.js";
import pngEncDecWasm from "./png/squoosh_png_bg.wasm.js";
const pngEncDecInit = () => pngEncDec.default(pngEncDecWasm);
import * as oxipng from "./png/squoosh_oxipng.js";
import oxipngWasm from "./png/squoosh_oxipng_bg.wasm.js";
const oxipngInit = () => oxipng.default(oxipngWasm);
import * as resize from "./resize/squoosh_resize.js";
import resizeWasm from "./resize/squoosh_resize_bg.wasm.js";
const resizeInit = () => resize.default(resizeWasm);
import rotateWasm from "./rotate/rotate.wasm.js";
import ImageData from "./image_data.js";
global.ImageData = ImageData;
function resizeNameToIndex(name) {
switch (name) {
case "triangle":
return 0;
case "catrom":
return 1;
case "mitchell":
return 2;
case "lanczos3":
return 3;
default:
throw Error(`Unknown resize algorithm "${name}"`);
}
}
function resizeWithAspect({
input_width,
input_height,
target_width,
target_height
}) {
if (!target_width && !target_height) {
throw Error("Need to specify at least width or height when resizing");
}
if (target_width && target_height) {
return { width: target_width, height: target_height };
}
if (!target_width) {
return {
width: Math.round(input_width / input_height * target_height),
height: target_height
};
}
return {
width: target_width,
height: Math.round(input_height / input_width * target_width)
};
}
const preprocessors = {
resize: {
name: "Resize",
description: "Resize the image before compressing",
instantiate: async () => {
await resizeInit();
return (buffer, input_width, input_height, { width, height, method, premultiply, linearRGB }) => {
;
({ width, height } = resizeWithAspect({
input_width,
input_height,
target_width: width,
target_height: height
}));
const imageData = new ImageData(
resize.resize(
buffer,
input_width,
input_height,
width,
height,
resizeNameToIndex(method),
premultiply,
linearRGB
),
width,
height
);
resize.cleanup();
return imageData;
};
},
defaultOptions: {
method: "lanczos3",
fitMethod: "stretch",
premultiply: true,
linearRGB: true
}
},
rotate: {
name: "Rotate",
description: "Rotate image",
instantiate: async () => {
return async (buffer, width, height, { numRotations }) => {
const degrees = numRotations * 90 % 360;
const sameDimensions = degrees === 0 || degrees === 180;
const size = width * height * 4;
const instance = (await WebAssembly.instantiate(rotateWasm)).instance;
const { memory } = instance.exports;
const additionalPagesNeeded = Math.ceil(
(size * 2 - memory.buffer.byteLength + 8) / (64 * 1024)
);
if (additionalPagesNeeded > 0) {
memory.grow(additionalPagesNeeded);
}
const view = new Uint8ClampedArray(memory.buffer);
view.set(buffer, 8);
instance.exports.rotate(width, height, degrees);
return new ImageData(
view.slice(size + 8, size * 2 + 8),
sameDimensions ? width : height,
sameDimensions ? height : width
);
};
},
defaultOptions: {
numRotations: 0
}
}
};
const codecs = {
mozjpeg: {
name: "MozJPEG",
extension: "jpg",
detectors: [/^\xFF\xD8\xFF/],
dec: () => instantiateEmscriptenWasm(mozDec, mozDecWasm),
enc: () => instantiateEmscriptenWasm(
mozEnc,
mozEncWasm
),
defaultEncoderOptions: {
quality: 75,
baseline: false,
arithmetic: false,
progressive: true,
optimize_coding: true,
smoothing: 0,
color_space: 3,
quant_table: 3,
trellis_multipass: false,
trellis_opt_zero: false,
trellis_opt_table: false,
trellis_loops: 1,
auto_subsample: true,
chroma_subsample: 2,
separate_chroma_quality: false,
chroma_quality: 75
},
autoOptimize: {
option: "quality",
min: 0,
max: 100
}
},
webp: {
name: "WebP",
extension: "webp",
detectors: [/^RIFF....WEBPVP8[LX ]/s],
dec: () => instantiateEmscriptenWasm(webpDec, webpDecWasm),
enc: () => instantiateEmscriptenWasm(
webpEnc,
webpEncWasm
),
defaultEncoderOptions: {
quality: 75,
target_size: 0,
target_PSNR: 0,
method: 4,
sns_strength: 50,
filter_strength: 60,
filter_sharpness: 0,
filter_type: 1,
partitions: 0,
segments: 4,
pass: 1,
show_compressed: 0,
preprocessing: 0,
autofilter: 0,
partition_limit: 0,
alpha_compression: 1,
alpha_filtering: 1,
alpha_quality: 100,
lossless: 0,
exact: 0,
image_hint: 0,
emulate_jpeg_size: 0,
thread_level: 0,
low_memory: 0,
near_lossless: 100,
use_delta_palette: 0,
use_sharp_yuv: 0
},
autoOptimize: {
option: "quality",
min: 0,
max: 100
}
},
avif: {
name: "AVIF",
extension: "avif",
// Disable eslint rule to not touch the original code
// eslint-disable-next-line no-control-regex, regexp/control-character-escape
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
dec: () => instantiateEmscriptenWasm(avifDec, avifDecWasm),
enc: async () => {
return instantiateEmscriptenWasm(
avifEnc,
avifEncWasm
);
},
defaultEncoderOptions: {
cqLevel: 33,
cqAlphaLevel: -1,
denoiseLevel: 0,
tileColsLog2: 0,
tileRowsLog2: 0,
speed: 6,
subsample: 1,
chromaDeltaQ: false,
sharpness: 0,
tune: 0
},
autoOptimize: {
option: "cqLevel",
min: 62,
max: 0
}
},
oxipng: {
name: "OxiPNG",
extension: "png",
// Disable eslint rule to not touch the original code
// eslint-disable-next-line no-control-regex, regexp/control-character-escape
detectors: [/^\x89PNG\x0D\x0A\x1A\x0A/],
dec: async () => {
await pngEncDecInit();
return {
decode: (buffer) => {
const imageData = pngEncDec.decode(buffer);
pngEncDec.cleanup();
return imageData;
}
};
},
enc: async () => {
await pngEncDecInit();
await oxipngInit();
return {
encode: (buffer, width, height, opts) => {
const simplePng = pngEncDec.encode(
new Uint8Array(buffer),
width,
height
);
const imageData = oxipng.optimise(simplePng, opts.level, false);
oxipng.cleanup();
return imageData;
}
};
},
defaultEncoderOptions: {
level: 2
},
autoOptimize: {
option: "level",
min: 6,
max: 1
}
}
};
export {
codecs,
preprocessors
};

View File

@@ -0,0 +1,9 @@
export declare function pathify(path: string): string;
export declare function instantiateEmscriptenWasm<T extends EmscriptenWasm.Module>(factory: EmscriptenWasm.ModuleFactory<T>, bytes: Uint8Array): Promise<T>;
export declare function dirname(url: string): string;
/**
* On certain serverless hosts, our ESM bundle is transpiled to CJS before being run, which means
* import.meta.url is undefined, so we'll fall back to __filename in those cases
* We should be able to remove this once https://github.com/netlify/zip-it-and-ship-it/issues/750 is fixed
*/
export declare function getModuleURL(url: string | undefined): string;

View File

@@ -0,0 +1,31 @@
import { fileURLToPath, pathToFileURL } from "node:url";
function pathify(path) {
if (path.startsWith("file://")) {
path = fileURLToPath(path);
}
return path;
}
function instantiateEmscriptenWasm(factory, bytes) {
return factory({
// @ts-expect-error This is a valid Emscripten option, but the type definitions don't know about it
wasmBinary: bytes,
locateFile(file) {
return file;
}
});
}
function dirname(url) {
return url.substring(0, url.lastIndexOf("/"));
}
function getModuleURL(url) {
if (!url) {
return pathToFileURL(__filename).toString();
}
return url;
}
export {
dirname,
getModuleURL,
instantiateEmscriptenWasm,
pathify
};

View File

@@ -0,0 +1,3 @@
import type { ImageOutputFormat } from '../../../types.js';
import type { Operation } from './image.js';
export declare function processBuffer(buffer: Uint8Array, operations: Operation[], encoding: ImageOutputFormat, quality?: number): Promise<Uint8Array>;

View File

@@ -0,0 +1,97 @@
import { cpus } from "node:os";
import { fileURLToPath } from "node:url";
import { isMainThread } from "node:worker_threads";
import { getModuleURL } from "./emscripten-utils.js";
import * as impl from "./impl.js";
import execOnce from "./utils/execOnce.js";
import WorkerPool from "./utils/workerPool.js";
const getWorker = execOnce(() => {
return new WorkerPool(
// There will be at most 7 workers needed since each worker will take
// at least 1 operation type.
Math.max(1, Math.min(cpus().length - 1, 7)),
fileURLToPath(getModuleURL(import.meta.url))
);
});
function handleJob(params) {
switch (params.operation) {
case "decode":
return impl.decodeBuffer(params.buffer);
case "resize":
return impl.resize({
image: params.imageData,
width: params.width,
height: params.height
});
case "rotate":
return impl.rotate(params.imageData, params.numRotations);
case "encodeavif":
return impl.encodeAvif(params.imageData, { quality: params.quality });
case "encodejpeg":
return impl.encodeJpeg(params.imageData, { quality: params.quality });
case "encodepng":
return impl.encodePng(params.imageData);
case "encodewebp":
return impl.encodeWebp(params.imageData, { quality: params.quality });
default:
throw Error(`Invalid job "${params.operation}"`);
}
}
async function processBuffer(buffer, operations, encoding, quality) {
const worker = await getWorker();
let imageData = await worker.dispatchJob({
operation: "decode",
buffer
});
for (const operation of operations) {
if (operation.type === "rotate") {
imageData = await worker.dispatchJob({
operation: "rotate",
imageData,
numRotations: operation.numRotations
});
} else if (operation.type === "resize") {
imageData = await worker.dispatchJob({
operation: "resize",
imageData,
height: operation.height,
width: operation.width
});
}
}
switch (encoding) {
case "avif":
return await worker.dispatchJob({
operation: "encodeavif",
imageData,
quality
});
case "jpeg":
case "jpg":
return await worker.dispatchJob({
operation: "encodejpeg",
imageData,
quality
});
case "png":
return await worker.dispatchJob({
operation: "encodepng",
imageData
});
case "webp":
return await worker.dispatchJob({
operation: "encodewebp",
imageData,
quality
});
case "svg":
default:
throw Error(`Unsupported encoding format`);
}
}
if (!isMainThread) {
WorkerPool.useThisThreadAsWorker(handleJob);
}
export {
processBuffer
};

View File

@@ -0,0 +1,13 @@
import type { ImageOutputFormat } from '../../../types.js';
type RotateOperation = {
type: 'rotate';
numRotations: number;
};
type ResizeOperation = {
type: 'resize';
width?: number;
height?: number;
};
export type Operation = RotateOperation | ResizeOperation;
export declare function processBuffer(buffer: Buffer, operations: Operation[], encoding: ImageOutputFormat, quality?: number): Promise<Uint8Array>;
export {};

View File

@@ -0,0 +1,28 @@
import * as impl from "./impl.js";
async function processBuffer(buffer, operations, encoding, quality) {
let imageData = await impl.decodeBuffer(buffer);
for (const operation of operations) {
if (operation.type === "rotate") {
imageData = await impl.rotate(imageData, operation.numRotations);
} else if (operation.type === "resize") {
imageData = await impl.resize({ image: imageData, width: operation.width, height: operation.height });
}
}
switch (encoding) {
case "avif":
return await impl.encodeAvif(imageData, { quality });
case "jpeg":
case "jpg":
return await impl.encodeJpeg(imageData, { quality });
case "png":
return await impl.encodePng(imageData);
case "webp":
return await impl.encodeWebp(imageData, { quality });
case "svg":
default:
throw Error(`Unsupported encoding format`);
}
}
export {
processBuffer
};

View File

@@ -0,0 +1,8 @@
export default class ImageData {
static from(input: ImageData): ImageData;
private _data;
width: number;
height: number;
get data(): Buffer;
constructor(data: Buffer | Uint8Array | Uint8ClampedArray, width: number, height: number);
}

View File

@@ -0,0 +1,25 @@
class ImageData {
static from(input) {
return new ImageData(input.data || input._data, input.width, input.height);
}
_data;
width;
height;
get data() {
if (Object.prototype.toString.call(this._data) === "[object Object]") {
return Buffer.from(Object.values(this._data));
}
if (this._data instanceof Buffer || this._data instanceof Uint8Array || this._data instanceof Uint8ClampedArray) {
return Buffer.from(this._data);
}
throw new Error("invariant");
}
constructor(data, width, height) {
this._data = data;
this.width = width;
this.height = height;
}
}
export {
ImageData as default
};

View File

@@ -0,0 +1,21 @@
import ImageData from './image_data.js';
export declare function decodeBuffer(_buffer: Buffer | Uint8Array): Promise<ImageData>;
export declare function rotate(image: ImageData, numRotations: number): Promise<ImageData>;
type ResizeOpts = {
image: ImageData;
} & {
width?: number;
height?: number;
};
export declare function resize({ image, width, height }: ResizeOpts): Promise<ImageData>;
export declare function encodeJpeg(image: ImageData, opts: {
quality?: number;
}): Promise<Uint8Array>;
export declare function encodeWebp(image: ImageData, opts: {
quality?: number;
}): Promise<Uint8Array>;
export declare function encodeAvif(image: ImageData, opts: {
quality?: number;
}): Promise<Uint8Array>;
export declare function encodePng(image: ImageData): Promise<Uint8Array>;
export {};

View File

@@ -0,0 +1,111 @@
import { preprocessors, codecs as supportedFormats } from "./codecs.js";
import ImageData from "./image_data.js";
const DELAY_MS = 1e3;
let _promise;
function delayOnce(ms) {
if (!_promise) {
_promise = new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
return _promise;
}
function maybeDelay() {
const isAppleM1 = process.arch === "arm64" && process.platform === "darwin";
if (isAppleM1) {
return delayOnce(DELAY_MS);
}
return Promise.resolve();
}
async function decodeBuffer(_buffer) {
const buffer = Buffer.from(_buffer);
const firstChunk = buffer.slice(0, 16);
const firstChunkString = Array.from(firstChunk).map((v) => String.fromCodePoint(v)).join("");
if (firstChunkString.includes("GIF")) {
throw Error(`GIF images are not supported, please use the Sharp image service`);
}
const key = Object.entries(supportedFormats).find(
([, { detectors }]) => detectors.some((detector) => detector.exec(firstChunkString))
)?.[0];
if (!key) {
throw Error(`Buffer has an unsupported format`);
}
const encoder = supportedFormats[key];
const mod = await encoder.dec();
const rgba = mod.decode(new Uint8Array(buffer));
return rgba;
}
async function rotate(image, numRotations) {
image = ImageData.from(image);
const m = await preprocessors["rotate"].instantiate();
return await m(image.data, image.width, image.height, { numRotations });
}
async function resize({ image, width, height }) {
image = ImageData.from(image);
const p = preprocessors["resize"];
const m = await p.instantiate();
await maybeDelay();
return await m(image.data, image.width, image.height, {
...p.defaultOptions,
width,
height
});
}
async function encodeJpeg(image, opts) {
image = ImageData.from(image);
const e = supportedFormats["mozjpeg"];
const m = await e.enc();
await maybeDelay();
const quality = opts.quality || e.defaultEncoderOptions.quality;
const r = await m.encode(image.data, image.width, image.height, {
...e.defaultEncoderOptions,
quality
});
return r;
}
async function encodeWebp(image, opts) {
image = ImageData.from(image);
const e = supportedFormats["webp"];
const m = await e.enc();
await maybeDelay();
const quality = opts.quality || e.defaultEncoderOptions.quality;
const r = await m.encode(image.data, image.width, image.height, {
...e.defaultEncoderOptions,
quality
});
return r;
}
async function encodeAvif(image, opts) {
image = ImageData.from(image);
const e = supportedFormats["avif"];
const m = await e.enc();
await maybeDelay();
const val = e.autoOptimize.min;
const quality = opts.quality || 75;
const r = await m.encode(image.data, image.width, image.height, {
...e.defaultEncoderOptions,
// Think of cqLevel as the "amount" of quantization (0 to 62),
// so a lower value yields higher quality (0 to 100).
cqLevel: quality === 0 ? val : Math.round(val - quality / 100 * val)
});
return r;
}
async function encodePng(image) {
image = ImageData.from(image);
const e = supportedFormats["oxipng"];
const m = await e.enc();
await maybeDelay();
const r = await m.encode(image.data, image.width, image.height, {
...e.defaultEncoderOptions
});
return r;
}
export {
decodeBuffer,
encodeAvif,
encodeJpeg,
encodePng,
encodeWebp,
resize,
rotate
};

View File

@@ -0,0 +1,11 @@
var MozJpegColorSpace = /* @__PURE__ */ ((MozJpegColorSpace2) => {
MozJpegColorSpace2[MozJpegColorSpace2["GRAYSCALE"] = 1] = "GRAYSCALE";
MozJpegColorSpace2[MozJpegColorSpace2["RGB"] = 2] = "RGB";
MozJpegColorSpace2[MozJpegColorSpace2["YCbCr"] = 3] = "YCbCr";
return MozJpegColorSpace2;
})(MozJpegColorSpace || {});
var mozjpeg_enc_d_default = moduleFactory;
export {
MozJpegColorSpace,
mozjpeg_enc_d_default as default
};

View File

@@ -0,0 +1,2 @@
declare var Module: (Module: any) => any;
export default Module;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
declare const _default: Buffer;
export default _default;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
declare var Module: (Module: any) => any;
export default Module;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
declare const _default: Buffer;
export default _default;

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More