Initial commit: New MoreminiMore website with fresh design

This commit is contained in:
MoreminiMore
2026-04-22 01:59:05 +07:00
commit 76409638cc
14010 changed files with 2052041 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 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 [Cloudflare](https://www.cloudflare.com/pt-br/?utm_source=astro&utm_medium=astro&utm_campaign=astro), [Mux](https://www.mux.com/?utm_campaign=21819274-Astro&utm_source=astro), [Netlify](https://www.netlify.com/?utm_campaign=Astro-2024&utm_source=astro-referral), [Webflow](https://webflow.com/feature/cloud?utm_source=Astro&utm_medium=tech-partner&utm_campaign=fy26-astro&utm_content=fy26-docs), and several [other amazing organizations](https://opencollective.com/astrodotbuild).
[❤️ Sponsor Astro! ❤️](https://github.com/withastro/.github/blob/main/FUNDING.md)

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

File diff suppressed because it is too large Load Diff

79
node_modules/astro/bin/astro.mjs generated vendored Executable file
View File

@@ -0,0 +1,79 @@
#!/usr/bin/env node
'use strict';
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 = '>=22.12.0';
const skipSemverCheckIfAbove = 23;
/** `astro *` */
async function main() {
const version = process.versions.node;
// Fast-path for higher Node.js versions
if ((Number.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`);
const ci = 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));

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

@@ -0,0 +1,521 @@
/// <reference types="vite/types/import-meta.d.ts" />
/// <reference path="./types/actions.d.ts" />
/// <reference path="./types/content.d.ts" />
/// <reference path="./types/env.d.ts" />
/// <reference path="./types/fonts.d.ts" />
/// <reference path="./types/transitions.d.ts" />
interface ImportMetaEnv {
// TODO: remove in Astro 7
/**
* 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.
* @deprecated This will be removed in a future major version of Astro. Use `build.assetsPrefix` from `astro:config/server` instead.
*/
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' {
// 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.
*/
export const getImage: (
options: import('./dist/assets/types.js').UnresolvedImageTransform,
) => Promise<import('./dist/assets/types.js').GetImageResult>;
export const imageConfig: import('./dist/types/public/config.js').AstroConfig['image'];
export const getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
export const inferRemoteSize: typeof import('./dist/assets/utils/index.js').inferRemoteSize;
export const Image: typeof import('./components/Image.astro').default;
export const Picture: typeof import('./components/Picture.astro').default;
export const Font: typeof import('./components/Font.astro').default;
export const fontData: Record<
import('astro:assets').CssVariable,
Array<import('astro:assets').FontData>
>;
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>
>;
}
declare module 'virtual:astro:image-styles.css' {
const styles: string;
export default styles;
}
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 '*.avif' {
const metadata: ImageMetadata;
export default metadata;
}
declare module '*.svg' {
const Component: import('./types').SvgComponent & ImageMetadata;
export default Component;
}
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:config/server' {
// biome-ignore format: bug
type ServerConfigSerialized = import('./dist/types/public/manifest.js').ServerDeserializedManifest;
const manifest: ServerConfigSerialized;
export = manifest;
}
declare module 'astro:config/client' {
// biome-ignore format: bug
type ClientConfigSerialized = import('./dist/types/public/manifest.js').ClientDeserializedManifest;
const manifest: ClientConfigSerialized;
export = manifest;
}
declare module 'astro:components' {
export * from 'astro/components';
}
// TODO: remove in Astro 7
/**
* @deprecated
* `import { z } from 'astro:schema'` is deprecated and will be removed
* in Astro 7. Use `import { z } from 'astro/zod'` instead.
*/
declare module 'astro:schema' {
export * from 'astro/zod';
import zod from 'astro/zod';
/**
* @deprecated
* `import { z } from 'astro:schema'` is deprecated and will be removed
* in Astro 7. Use `import { z } from 'astro/zod'` instead.
*/
export const z = zod.z;
}
type MD = import('./dist/types/public/content.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,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.markdown' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mkdn' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mkd' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mdwn' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mdown' {
const { load }: ExportedMarkdownModuleEntities;
export const {
frontmatter,
file,
url,
getHeadings,
Content,
rawContent,
compiledContent,
}: ExportedMarkdownModuleEntities;
export default load;
}
declare module '*.mdx' {
type MDX = import('./dist/types/public/content.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:static-paths' {
export const StaticPaths: typeof import('./dist/runtime/prerender/static-paths.js').StaticPaths;
}
// 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;
}
declare module '*?no-inline' {
const src: string;
export default src;
}
declare module '*?url&inline' {
const src: string;
export default src;
}
declare module '*?url&no-inline' {
const src: string;
export default src;
}

155
node_modules/astro/components/ClientRouter.astro generated vendored Normal file
View File

@@ -0,0 +1,155 @@
---
type Fallback = 'none' | 'animate' | 'swap';
export interface Props {
fallback?: Fallback;
}
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';
let lastClickedElementLeavingWindow: EventTarget | null = null;
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;
}
const leavesWindow = (ev: MouseEvent) =>
(ev.button && ev.button !== 0) || // left clicks only
ev.metaKey || // new tab (mac)
ev.ctrlKey || // new tab (windows)
ev.altKey || // download
ev.shiftKey; // new window
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;
lastClickedElementLeavingWindow = leavesWindow(ev) ? link : null;
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 ||
lastClickedElementLeavingWindow ||
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;
const submitter = ev.submitter;
const clickedWithKeys = submitter && submitter === lastClickedElementLeavingWindow;
lastClickedElementLeavingWindow = null;
if (el.tagName !== 'FORM' || ev.defaultPrevented || isReloadEl(el) || clickedWithKeys) {
return;
}
const form = el as HTMLFormElement;
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 fall back 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, fall back to current path.
let action = submitter?.getAttribute('formaction') ?? formAction ?? location.pathname;
// Use the form method, if defined; otherwise, fall back 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>

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

@@ -0,0 +1,129 @@
---
import { createShikiHighlighter, type ThemePresets } from '@astrojs/markdown-remark/shiki';
import type { ShikiTransformer, ThemeRegistration, ThemeRegistrationRaw } from 'shiki';
import { bundledLanguages } from 'shiki/langs';
import type { CodeLanguage } from '../dist/types/public/common.js';
import type { HTMLAttributes } from '../types.js';
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?: CodeLanguage;
/**
* Additional languages to load.
* Useful if `code` embeds languages not included by the given `lang`
* For example, TSX in Vue
*
* @default []
*/
embeddedLangs?: CodeLanguage[];
/**
* 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',
embeddedLangs = [],
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 createShikiHighlighter({
langs: [
typeof lang === 'string'
? Object.keys(bundledLanguages).includes(lang)
? lang
: 'plaintext'
: (lang as any),
...embeddedLangs,
],
theme,
themes,
});
const html = await highlighter.codeToHtml(code, typeof lang === 'string' ? lang : lang.name, {
defaultColor,
wrap,
inline,
transformers,
meta,
attributes: rest as any,
});
---
<Fragment set:html={html} />

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

@@ -0,0 +1,62 @@
---
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>

30
node_modules/astro/components/Font.astro generated vendored Normal file
View File

@@ -0,0 +1,30 @@
---
import { componentDataByCssVariable } from 'virtual:astro:assets/fonts/internal';
import { filterPreloads } from '../dist/assets/fonts/core/filter-preloads.js';
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
interface Props {
/** The `cssVariable` registered in your Astro configuration. */
cssVariable: import('astro:assets').CssVariable;
/** Whether it should output [preload links](https://web.dev/learn/performance/optimize-web-fonts#preload) or not. */
preload?: import('astro:assets').FontPreloadFilter;
}
const { cssVariable, preload = false } = Astro.props as Props;
const data = componentDataByCssVariable.get(cssVariable);
if (!data) {
throw new AstroError({
...AstroErrorData.FontFamilyNotFound,
message: AstroErrorData.FontFamilyNotFound.message(cssVariable),
});
}
const filteredPreloadData = filterPreloads(data.preloads, preload);
---
<style set:html={data.css}></style>
{
filteredPreloadData?.map(({ url, type }) => (
<link rel="preload" href={url} as="font" type={`font/${type}`} crossorigin />
))
}

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

@@ -0,0 +1,53 @@
---
import { getImage, imageConfig, type LocalImageProps, type RemoteImageProps } from 'astro:assets';
import type { UnresolvedImageTransform } from '../dist/assets/types.js';
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
import type { HTMLAttributes } from '../types.js';
// 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 = Number.parseInt(props.width);
}
if (typeof props.height === 'string') {
props.height = Number.parseInt(props.height);
}
const layout = props.layout ?? imageConfig.layout ?? 'none';
if (layout !== 'none') {
props.layout ??= imageConfig.layout;
props.fit ??= imageConfig.objectFit ?? 'cover';
props.position ??= imageConfig.objectPosition ?? 'center';
} else if (imageConfig.objectFit || imageConfig.objectPosition) {
props.fit ??= imageConfig.objectFit;
props.position ??= imageConfig.objectPosition;
}
const image = await getImage(props as UnresolvedImageTransform);
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';
}
const { class: className, ...attributes } = { ...additionalAttributes, ...image.attributes };
---
{/* Applying class outside of the spread prevents it from applying unnecessary astro-* classes */}
<img src={image.src} {...attributes} class={className} />

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

@@ -0,0 +1,141 @@
---
import { getImage, imageConfig, type LocalImageProps, type RemoteImageProps } from 'astro:assets';
import * as mime from 'mrmime';
import { isESMImportedImage, resolveSrc } from '../dist/assets/utils/imageKind.js';
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
import type {
GetImageResult,
ImageOutputFormat,
UnresolvedImageTransform,
} from '../dist/types/public/index.js';
import type { HTMLAttributes } from '../types.js';
export 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;
}
}
const layout = props.layout ?? imageConfig.layout ?? 'none';
const useResponsive = layout !== 'none';
if (useResponsive) {
props.layout ??= imageConfig.layout;
props.fit ??= imageConfig.objectFit ?? 'cover';
props.position ??= imageConfig.objectPosition ?? 'center';
} else if (imageConfig.objectFit || imageConfig.objectPosition) {
props.fit ??= imageConfig.objectFit;
props.position ??= imageConfig.objectPosition;
}
for (const key in props) {
if (key.startsWith('data-astro-cid')) {
// @ts-expect-error This is for island props so they're not properly typed
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,
} as UnresolvedImageTransform),
),
);
// Clone the `src` object if it's an ESM import so that we don't refer to any properties of the original object
// Causing our generate step to think the image is used outside of the image optimization pipeline
const clonedSrc = isESMImportedImage(originalSrc)
? // @ts-expect-error - clone is a private, hidden prop
(originalSrc.clone ?? originalSrc)
: originalSrc;
let resultFallbackFormat = fallbackFormat ?? defaultFallbackFormat;
if (
!fallbackFormat &&
isESMImportedImage(clonedSrc) &&
(specialFormatsFallback as ReadonlyArray<string>).includes(clonedSrc.format)
) {
resultFallbackFormat = clonedSrc.format;
}
const fallbackImage = await getImage({
...props,
format: resultFallbackFormat,
widths: props.widths,
densities: props.densities,
} as UnresolvedImageTransform);
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';
}
const { class: className, ...attributes } = {
...imgAdditionalAttributes,
...fallbackImage.attributes,
};
---
<picture {...pictureAttributes}>
{
Object.entries(optimizedImages).map(([_, image]) => {
const srcsetAttribute =
props.densities || (!props.densities && !props.widths && !useResponsive)
? `${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}
/>
);
})
}
{/* Applying class outside of the spread prevents it from applying unnecessary astro-* classes */}
<img src={fallbackImage.src} {...attributes} class={className} />
</picture>

11
node_modules/astro/components/ResponsiveImage.astro generated vendored Normal file
View File

@@ -0,0 +1,11 @@
---
import type { LocalImageProps, RemoteImageProps } from 'astro:assets';
import Image from './Image.astro';
type Props = LocalImageProps | RemoteImageProps;
const { class: className, ...props } = Astro.props;
---
{/* Applying class outside of the spread prevents it from applying unnecessary astro-* classes */}
<Image {...props} class={className} />

11
node_modules/astro/components/ResponsivePicture.astro generated vendored Normal file
View File

@@ -0,0 +1,11 @@
---
import { default as Picture, type Props as PictureProps } from './Picture.astro';
type Props = PictureProps;
const { class: className, ...props } = Astro.props;
---
{/* Applying class outside of the spread prevents it from applying unnecessary astro-* classes */}
<Picture {...props} class={className} />

2
node_modules/astro/components/env.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
/// <reference path="../client.d.ts" />
/// <reference path="../dev-only.d.ts" />

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.
// @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;
}
}

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

@@ -0,0 +1,14 @@
export declare const ACTIONS_TYPES_FILE = "actions.d.ts";
export declare const VIRTUAL_MODULE_ID = "astro:actions";
export declare const RESOLVED_VIRTUAL_MODULE_ID: string;
export declare const ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID = "virtual:astro:actions/entrypoint";
export declare const ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID: string;
/** Used to pass data from the config to the main virtual module */
export declare const OPTIONS_VIRTUAL_MODULE_ID = "virtual:astro:actions/options";
export declare const RESOLVED_OPTIONS_VIRTUAL_MODULE_ID: string;
export declare const RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID = "\0virtual:astro:actions/noop-entrypoint";
export declare const ACTION_QUERY_PARAMS: {
actionName: string;
actionPayload: string;
};
export declare const ACTION_RPC_ROUTE_PATTERN = "/_actions/[...path]";

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

@@ -0,0 +1,25 @@
const ACTIONS_TYPES_FILE = "actions.d.ts";
const VIRTUAL_MODULE_ID = "astro:actions";
const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
const ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID = "virtual:astro:actions/entrypoint";
const ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID = "\0" + ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID;
const OPTIONS_VIRTUAL_MODULE_ID = "virtual:astro:actions/options";
const RESOLVED_OPTIONS_VIRTUAL_MODULE_ID = "\0" + OPTIONS_VIRTUAL_MODULE_ID;
const RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID = "\0virtual:astro:actions/noop-entrypoint";
const ACTION_QUERY_PARAMS = {
actionName: "_action",
actionPayload: "_astroActionPayload"
};
const ACTION_RPC_ROUTE_PATTERN = "/_actions/[...path]";
export {
ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID,
ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID,
ACTIONS_TYPES_FILE,
ACTION_QUERY_PARAMS,
ACTION_RPC_ROUTE_PATTERN,
OPTIONS_VIRTUAL_MODULE_ID,
RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID,
RESOLVED_OPTIONS_VIRTUAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
VIRTUAL_MODULE_ID
};

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

@@ -0,0 +1,10 @@
import type { AstroSettings } from '../types/astro.js';
import type { AstroIntegration } from '../types/public/integrations.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, filename, }: {
settings: AstroSettings;
filename: string;
}): AstroIntegration;

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

@@ -0,0 +1,44 @@
import { AstroError } from "../core/errors/errors.js";
import { ActionsWithoutServerOutputError } from "../core/errors/errors-data.js";
import { hasNonPrerenderedRoute } from "../core/routing/helpers.js";
import { viteID } from "../core/util.js";
import { ACTION_RPC_ROUTE_PATTERN, ACTIONS_TYPES_FILE, VIRTUAL_MODULE_ID } from "./consts.js";
function astroIntegrationActionsRouteHandler({
settings,
filename
}) {
return {
name: VIRTUAL_MODULE_ID,
hooks: {
async "astro:config:setup"() {
settings.injectedRoutes.push({
pattern: ACTION_RPC_ROUTE_PATTERN,
entrypoint: "astro/actions/runtime/entrypoints/route.js",
prerender: false,
origin: "internal"
});
},
"astro:config:done": async (params) => {
const stringifiedActionsImport = JSON.stringify(
viteID(new URL(`./${filename}`, params.config.srcDir))
);
settings.injectedTypes.push({
filename: ACTIONS_TYPES_FILE,
content: `declare module "astro:actions" {
export const actions: typeof import(${stringifiedActionsImport})["server"];
}`
});
},
"astro:routes:resolved": ({ routes }) => {
if (!settings.config.adapter && !hasNonPrerenderedRoute(routes)) {
const error = new AstroError(ActionsWithoutServerOutputError);
error.stack = void 0;
throw error;
}
}
}
};
}
export {
astroIntegrationActionsRouteHandler as default
};

2
node_modules/astro/dist/actions/noop-actions.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
import type { SSRActions } from '../core/app/types.js';
export declare const NOOP_ACTIONS_MOD: SSRActions;

6
node_modules/astro/dist/actions/noop-actions.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
const NOOP_ACTIONS_MOD = {
server: {}
};
export {
NOOP_ACTIONS_MOD
};

84
node_modules/astro/dist/actions/runtime/client.d.ts generated vendored Normal file
View File

@@ -0,0 +1,84 @@
import type * as z from 'zod/v4/core';
import type { ActionClient, ActionErrorCode, ErrorInferenceObject, SafeResult, SerializedActionResult } from './types.js';
import type { APIContext } from '../../types/public/context.js';
export declare const codeToStatusMap: {
BAD_REQUEST: number;
UNAUTHORIZED: number;
PAYMENT_REQUIRED: number;
FORBIDDEN: number;
NOT_FOUND: number;
METHOD_NOT_ALLOWED: number;
NOT_ACCEPTABLE: number;
PROXY_AUTHENTICATION_REQUIRED: number;
REQUEST_TIMEOUT: number;
CONFLICT: number;
GONE: number;
LENGTH_REQUIRED: number;
PRECONDITION_FAILED: number;
CONTENT_TOO_LARGE: number;
URI_TOO_LONG: number;
UNSUPPORTED_MEDIA_TYPE: number;
RANGE_NOT_SATISFIABLE: number;
EXPECTATION_FAILED: number;
MISDIRECTED_REQUEST: number;
UNPROCESSABLE_CONTENT: number;
LOCKED: number;
FAILED_DEPENDENCY: number;
TOO_EARLY: number;
UPGRADE_REQUIRED: number;
PRECONDITION_REQUIRED: number;
TOO_MANY_REQUESTS: number;
REQUEST_HEADER_FIELDS_TOO_LARGE: number;
UNAVAILABLE_FOR_LEGAL_REASONS: number;
INTERNAL_SERVER_ERROR: number;
NOT_IMPLEMENTED: number;
BAD_GATEWAY: number;
SERVICE_UNAVAILABLE: number;
GATEWAY_TIMEOUT: number;
HTTP_VERSION_NOT_SUPPORTED: number;
VARIANT_ALSO_NEGOTIATES: number;
INSUFFICIENT_STORAGE: number;
LOOP_DETECTED: number;
NETWORK_AUTHENTICATION_REQUIRED: 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 declare class ActionInputError<T extends ErrorInferenceObject> extends ActionError {
type: string;
issues: z.$ZodIssue[];
fields: {
[P in keyof T]?: string[] | undefined;
};
constructor(issues: z.$ZodIssue[]);
}
export declare function deserializeActionResult(res: SerializedActionResult): SafeResult<any, any>;
export declare const actionResultErrorStack: {
set(stack: string | undefined): void;
get(): string | undefined;
};
export declare function getActionQueryString(name: string): string;
export declare function getActionPathFromString({ baseUrl, shouldAppendTrailingSlash, path: input, }: {
baseUrl: string;
shouldAppendTrailingSlash: boolean;
path: string;
}): string;
export declare function createGetActionPath(options: Pick<Parameters<typeof getActionPathFromString>[0], 'baseUrl' | 'shouldAppendTrailingSlash'>): (action: ActionClient<any, any, any>) => string;
export declare function createActionsProxy({ actionCallback, aggregatedPath, handleAction, }: {
actionCallback?: Record<string | symbol, any>;
aggregatedPath?: string;
handleAction: (param: any, path: string, context: APIContext | undefined) => Promise<SafeResult<any, any>>;
}): Record<string | symbol, any>;

240
node_modules/astro/dist/actions/runtime/client.js generated vendored Normal file
View File

@@ -0,0 +1,240 @@
import { parse as devalueParse } from "devalue";
import { ACTION_QUERY_PARAMS } from "../consts.js";
import { appendForwardSlash } from "../../core/path.js";
const codeToStatusMap = {
// Implemented from IANA HTTP Status Code Registry
// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
PAYMENT_REQUIRED: 402,
FORBIDDEN: 403,
NOT_FOUND: 404,
METHOD_NOT_ALLOWED: 405,
NOT_ACCEPTABLE: 406,
PROXY_AUTHENTICATION_REQUIRED: 407,
REQUEST_TIMEOUT: 408,
CONFLICT: 409,
GONE: 410,
LENGTH_REQUIRED: 411,
PRECONDITION_FAILED: 412,
CONTENT_TOO_LARGE: 413,
URI_TOO_LONG: 414,
UNSUPPORTED_MEDIA_TYPE: 415,
RANGE_NOT_SATISFIABLE: 416,
EXPECTATION_FAILED: 417,
MISDIRECTED_REQUEST: 421,
UNPROCESSABLE_CONTENT: 422,
LOCKED: 423,
FAILED_DEPENDENCY: 424,
TOO_EARLY: 425,
UPGRADE_REQUIRED: 426,
PRECONDITION_REQUIRED: 428,
TOO_MANY_REQUESTS: 429,
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
INTERNAL_SERVER_ERROR: 500,
NOT_IMPLEMENTED: 501,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
GATEWAY_TIMEOUT: 504,
HTTP_VERSION_NOT_SUPPORTED: 505,
VARIANT_ALSO_NEGOTIATES: 506,
INSUFFICIENT_STORAGE: 507,
LOOP_DETECTED: 508,
NETWORK_AUTHENTICATION_REQUIRED: 511
};
const statusToCodeMap = Object.fromEntries(
Object.entries(codeToStatusMap).map(([key, value]) => [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);
}
}
}
}
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;
}
};
})();
function getActionQueryString(name) {
const searchParams = new URLSearchParams({ [ACTION_QUERY_PARAMS.actionName]: name });
return `?${searchParams.toString()}`;
}
function getActionPathFromString({
baseUrl,
shouldAppendTrailingSlash,
path: input
}) {
let path = `${baseUrl.replace(/\/$/, "")}/_actions/${new URLSearchParams(input).get(ACTION_QUERY_PARAMS.actionName)}`;
if (shouldAppendTrailingSlash) {
path = appendForwardSlash(path);
}
return path;
}
function createGetActionPath(options) {
return function getActionPath(action) {
return getActionPathFromString({
baseUrl: options.baseUrl,
shouldAppendTrailingSlash: options.shouldAppendTrailingSlash,
path: action.toString()
});
};
}
const ENCODED_DOT = "%2E";
function createActionsProxy({
actionCallback = {},
aggregatedPath = "",
handleAction
}) {
return new Proxy(actionCallback, {
get(target, objKey) {
if (target.hasOwnProperty(objKey) || typeof objKey === "symbol") {
return target[objKey];
}
const path = aggregatedPath + encodeURIComponent(objKey.toString()).replaceAll(".", ENCODED_DOT);
function action(param) {
return handleAction(param, path, this);
}
Object.assign(action, {
queryString: getActionQueryString(path),
toString: () => action.queryString,
// redefine prototype methods as the object's own property, not the prototype's
bind: action.bind,
valueOf: () => action.valueOf,
// Progressive enhancement info for React.
$$FORM_ACTION: function() {
const searchParams = new URLSearchParams(action.toString());
return {
method: "POST",
// `name` creates a hidden input.
// It's unused by Astro, but we can't turn this off.
// At least use a name that won't conflict with a user's formData.
name: "_astroAction",
action: "?" + searchParams.toString()
};
},
// Note: `orThrow` does not have progressive enhancement info.
// If you want to throw exceptions,
// you must handle those exceptions with client JS.
async orThrow(param) {
const { data, error } = await handleAction(param, path, this);
if (error) throw error;
return data;
}
});
return createActionsProxy({
actionCallback: action,
aggregatedPath: path + ".",
handleAction
});
}
});
}
export {
ActionError,
ActionInputError,
actionResultErrorStack,
codeToStatusMap,
createActionsProxy,
createGetActionPath,
deserializeActionResult,
getActionPathFromString,
getActionQueryString,
isActionError,
isInputError
};

View File

@@ -0,0 +1,7 @@
export { ACTION_QUERY_PARAMS } from '../../consts.js';
export { ActionError, isActionError, isInputError, } from '../client.js';
export type { ActionAPIContext, ActionClient, ActionErrorCode, ActionInputSchema, ActionReturnType, SafeResult, } from '../types.js';
export declare function defineAction(): void;
export declare function getActionContext(): void;
export declare const getActionPath: (action: import("../types.js").ActionClient<any, any, any>) => string;
export declare const actions: Record<string | symbol, any>;

View File

@@ -0,0 +1,91 @@
import { shouldAppendTrailingSlash } from "virtual:astro:actions/options";
import { internalFetchHeaders } from "virtual:astro:adapter-config/client";
import {
ActionError,
createActionsProxy,
createGetActionPath,
deserializeActionResult,
getActionPathFromString,
getActionQueryString
} from "../client.js";
import { ACTION_QUERY_PARAMS } from "../../consts.js";
import {
ActionError as ActionError2,
isActionError,
isInputError
} from "../client.js";
function defineAction() {
throw new Error("[astro:actions] `defineAction()` unexpectedly used on the client.");
}
function getActionContext() {
throw new Error("[astro:actions] `getActionContext()` unexpectedly used on the client.");
}
const getActionPath = createGetActionPath({
baseUrl: import.meta.env.BASE_URL,
shouldAppendTrailingSlash
});
const actions = createActionsProxy({
handleAction: async (param, path) => {
const headers = new Headers();
headers.set("Accept", "application/json");
for (const [key, value] of Object.entries(internalFetchHeaders)) {
headers.set(key, value);
}
let body = param;
if (!(body instanceof FormData)) {
try {
body = JSON.stringify(param);
} catch (e) {
throw new ActionError({
code: "BAD_REQUEST",
message: `Failed to serialize request body to JSON. Full error: ${e.message}`
});
}
if (body) {
headers.set("Content-Type", "application/json");
} else {
headers.set("Content-Length", "0");
}
}
const rawResult = await fetch(
getActionPathFromString({
baseUrl: import.meta.env.BASE_URL,
shouldAppendTrailingSlash,
path: getActionQueryString(path)
}),
{
method: "POST",
body,
headers
}
);
if (rawResult.status === 204) {
return deserializeActionResult({ type: "empty", status: 204 });
}
const bodyText = await rawResult.text();
if (rawResult.ok) {
return deserializeActionResult({
type: "data",
body: bodyText,
status: 200,
contentType: "application/json+devalue"
});
}
return deserializeActionResult({
type: "error",
body: bodyText,
status: rawResult.status,
contentType: "application/json"
});
}
});
export {
ACTION_QUERY_PARAMS,
ActionError2 as ActionError,
actions,
defineAction,
getActionContext,
getActionPath,
isActionError,
isInputError
};

View File

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

View File

@@ -0,0 +1,23 @@
import { getActionContext } from "../server.js";
const POST = async (context) => {
const { action, serializeActionResult } = getActionContext(context);
if (action?.calledFrom !== "rpc") {
return new Response("Not found", { status: 404 });
}
const result = await action.handler();
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
};

View File

@@ -0,0 +1,6 @@
export { ACTION_QUERY_PARAMS } from '../../consts.js';
export { ActionError, isActionError, isInputError } from '../client.js';
export { defineAction, getActionContext } from '../server.js';
export type { ActionAPIContext, ActionClient, ActionErrorCode, ActionInputSchema, ActionReturnType, SafeResult, } from '../types.js';
export declare const getActionPath: (action: import("../types.js").ActionClient<any, any, any>) => string;
export declare const actions: Record<string | symbol, any>;

View File

@@ -0,0 +1,33 @@
import { pipelineSymbol } from "../../../core/constants.js";
import { ActionCalledFromServerError } from "../../../core/errors/errors-data.js";
import { AstroError } from "../../../core/errors/errors.js";
import { createGetActionPath, createActionsProxy } from "../client.js";
import { shouldAppendTrailingSlash } from "virtual:astro:actions/options";
import { ACTION_QUERY_PARAMS } from "../../consts.js";
import { ActionError, isActionError, isInputError } from "../client.js";
import { defineAction, getActionContext } from "../server.js";
const getActionPath = createGetActionPath({
baseUrl: import.meta.env.BASE_URL,
shouldAppendTrailingSlash
});
const actions = createActionsProxy({
handleAction: async (param, path, context) => {
const pipeline = context ? Reflect.get(context, pipelineSymbol) : void 0;
if (!pipeline) {
throw new AstroError(ActionCalledFromServerError);
}
const action = await pipeline.getAction(path);
if (!action) throw new Error(`Action not found: ${path}`);
return action.bind(context)(param);
}
});
export {
ACTION_QUERY_PARAMS,
ActionError,
actions,
defineAction,
getActionContext,
getActionPath,
isActionError,
isInputError
};

45
node_modules/astro/dist/actions/runtime/server.d.ts generated vendored Normal file
View File

@@ -0,0 +1,45 @@
import * as z from 'zod/v4/core';
import type { APIContext } from '../../types/public/index.js';
import { deserializeActionResult } from './client.js';
import type { ActionAccept, ActionClient, ActionHandler, SafeResult, SerializedActionResult } from './types.js';
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;
interface AstroActionContext {
/** Information about an incoming action request. */
action?: {
/** Whether an action was called using an RPC function or by using an HTML form action. */
calledFrom: 'rpc' | 'form';
/** The name of the action. Useful to track the source of an action result during a redirect. */
name: string;
/** Programmatically call the action to get the result. */
handler: () => Promise<SafeResult<any, any>>;
};
/**
* Manually set the action result accessed via `getActionResult()`.
* Calling this function from middleware will disable Astro's own action result handling.
*/
setActionResult(actionName: string, actionResult: SerializedActionResult): void;
/**
* Serialize an action result to stored in a cookie or session.
* Also used to pass a result to Astro templates via `setActionResult()`.
*/
serializeActionResult: typeof serializeActionResult;
/**
* Deserialize an action result to access data and error objects.
*/
deserializeActionResult: typeof deserializeActionResult;
}
/**
* Access information about Action requests from middleware.
*/
export declare function getActionContext(context: APIContext): AstroActionContext;
export declare const ACTION_API_CONTEXT_SYMBOL: unique symbol;
/** Transform form data to an object based on a Zod schema. */
export declare function formDataToObject<T extends z.$ZodObject>(formData: FormData, schema: T,
/** @internal */
prefix?: string): Record<string, unknown>;
export declare function serializeActionResult(res: SafeResult<any, any>): SerializedActionResult;
export {};

379
node_modules/astro/dist/actions/runtime/server.js generated vendored Normal file
View File

@@ -0,0 +1,379 @@
import { stringify as devalueStringify } from "devalue";
import * as z from "zod/v4/core";
import { shouldAppendForwardSlash } from "../../core/build/util.js";
import { pipelineSymbol, REDIRECT_STATUS_CODES } from "../../core/constants.js";
import {
ActionCalledFromServerError,
ActionNotFoundError,
ActionsReturnedInvalidDataError
} from "../../core/errors/errors-data.js";
import { AstroError } from "../../core/errors/errors.js";
import { removeTrailingForwardSlash } from "../../core/path.js";
import { BodySizeLimitError, readBodyWithLimit } from "../../core/request-body.js";
import { ACTION_QUERY_PARAMS, ACTION_RPC_ROUTE_PATTERN } from "../consts.js";
import {
ActionError,
ActionInputError,
actionResultErrorStack,
deserializeActionResult
} from "./client.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 parsed = await parseFormInput(inputSchema, unparsedInput);
if (!parsed.success) {
throw new ActionInputError(parsed.error.issues);
}
return await handler(parsed.data, context);
};
}
async function parseFormInput(inputSchema, unparsedInput) {
const baseSchema = unwrapBaseZ4ObjectSchema(inputSchema, unparsedInput);
const input = baseSchema instanceof z.$ZodObject ? formDataToObject(unparsedInput, baseSchema) : unparsedInput;
const parsed = await z.safeParseAsync(inputSchema, input);
return parsed;
}
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 z.safeParseAsync(inputSchema, unparsedInput);
if (!parsed.success) {
throw new ActionInputError(parsed.error.issues);
}
return await handler(parsed.data, context);
};
}
function getActionContext(context) {
const callerInfo = getCallerInfo(context);
const actionResultAlreadySet = Boolean(context.locals._actionPayload);
let action = void 0;
if (callerInfo && context.request.method === "POST" && !actionResultAlreadySet) {
action = {
calledFrom: callerInfo.from,
name: callerInfo.name,
handler: async () => {
const pipeline = Reflect.get(context, pipelineSymbol);
const callerInfoName = shouldAppendForwardSlash(
pipeline.manifest.trailingSlash,
pipeline.manifest.buildFormat
) ? removeTrailingForwardSlash(callerInfo.name) : callerInfo.name;
let baseAction;
try {
baseAction = await pipeline.getAction(callerInfoName);
} catch (error) {
if (error instanceof Error && "name" in error && typeof error.name === "string" && error.name === ActionNotFoundError.name) {
return { data: void 0, error: new ActionError({ code: "NOT_FOUND" }) };
}
throw error;
}
const bodySizeLimit = pipeline.manifest.actionBodySizeLimit;
let input;
try {
input = await parseRequestBody(context.request, bodySizeLimit);
} catch (e) {
if (e instanceof ActionError) {
return { data: void 0, error: e };
}
if (e instanceof TypeError) {
return { data: void 0, error: new ActionError({ code: "UNSUPPORTED_MEDIA_TYPE" }) };
}
throw e;
}
const omitKeys = ["props", "getActionResult", "callAction", "redirect"];
const actionAPIContext = Object.create(
Object.getPrototypeOf(context),
Object.fromEntries(
Object.entries(Object.getOwnPropertyDescriptors(context)).filter(
([key]) => !omitKeys.includes(key)
)
)
);
Reflect.set(actionAPIContext, ACTION_API_CONTEXT_SYMBOL, true);
const handler = baseAction.bind(actionAPIContext);
return handler(input);
}
};
}
function setActionResult(actionName, actionResult) {
context.locals._actionPayload = {
actionResult,
actionName
};
}
return {
action,
setActionResult,
serializeActionResult,
deserializeActionResult
};
}
function getCallerInfo(ctx) {
if (ctx.routePattern === ACTION_RPC_ROUTE_PATTERN) {
return { from: "rpc", name: ctx.url.pathname.replace(/^.*\/_actions\//, "") };
}
const queryParam = ctx.url.searchParams.get(ACTION_QUERY_PARAMS.actionName);
if (queryParam) {
return { from: "form", name: queryParam };
}
return void 0;
}
async function parseRequestBody(request, bodySizeLimit) {
const contentType = request.headers.get("content-type");
const contentLengthHeader = request.headers.get("content-length");
const contentLength = contentLengthHeader ? Number.parseInt(contentLengthHeader, 10) : void 0;
const hasContentLength = typeof contentLength === "number" && Number.isFinite(contentLength);
if (!contentType) return void 0;
if (hasContentLength && contentLength > bodySizeLimit) {
throw new ActionError({
code: "CONTENT_TOO_LARGE",
message: `Request body exceeds ${bodySizeLimit} bytes`
});
}
try {
if (hasContentType(contentType, formContentTypes)) {
if (!hasContentLength) {
const body = await readBodyWithLimit(request.clone(), bodySizeLimit);
const formRequest = new Request(request.url, {
method: request.method,
headers: request.headers,
body: toArrayBuffer(body)
});
return await formRequest.formData();
}
return await request.clone().formData();
}
if (hasContentType(contentType, ["application/json"])) {
if (contentLength === 0) return void 0;
if (!hasContentLength) {
const body = await readBodyWithLimit(request.clone(), bodySizeLimit);
if (body.byteLength === 0) return void 0;
return JSON.parse(new TextDecoder().decode(body));
}
return await request.clone().json();
}
} catch (e) {
if (e instanceof BodySizeLimitError) {
throw new ActionError({
code: "CONTENT_TOO_LARGE",
message: `Request body exceeds ${bodySizeLimit} bytes`
});
}
throw e;
}
throw new TypeError("Unsupported content type");
}
const ACTION_API_CONTEXT_SYMBOL = /* @__PURE__ */ 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;
}
function formDataToObject(formData, schema, prefix = "") {
const formKeys = [...formData.keys()];
const obj = schema._zod.def.catchall ? Object.fromEntries(
[...formData.entries()].filter(([k]) => k.startsWith(prefix)).map(([k, v]) => [k.slice(prefix.length), v])
) : {};
for (const [key, baseValidator] of Object.entries(schema._zod.def.shape)) {
const prefixedKey = prefix + key;
let validator = baseValidator;
while (validator instanceof z.$ZodOptional || validator instanceof z.$ZodNullable || validator instanceof z.$ZodDefault) {
if (validator instanceof z.$ZodDefault && !formDataHasKeyOrPrefix(formKeys, prefixedKey)) {
obj[key] = validator._zod.def.defaultValue instanceof Function ? validator._zod.def.defaultValue() : validator._zod.def.defaultValue;
}
validator = validator._zod.def.innerType;
}
while (validator instanceof z.$ZodPipe) {
validator = validator._zod.def.in;
}
if (validator instanceof z.$ZodDiscriminatedUnion) {
const typeKey = validator._zod.def.discriminator;
const typeValue = formData.get(prefixedKey + "." + typeKey);
if (typeof typeValue === "string") {
const match = validator._zod.def.options.find(
(option) => option.def.shape[typeKey].values.has(typeValue)
);
if (match) {
validator = match;
}
}
}
if (validator instanceof z.$ZodObject) {
const nestedPrefix = prefixedKey + ".";
const hasNestedKeys = formKeys.some((k) => k.startsWith(nestedPrefix));
if (hasNestedKeys) {
obj[key] = formDataToObject(formData, validator, nestedPrefix);
} else if (!(key in obj)) {
obj[key] = baseValidator instanceof z.$ZodNullable ? null : void 0;
}
} else if (!formData.has(prefixedKey) && key in obj) {
continue;
} else if (validator instanceof z.$ZodBoolean) {
const val = formData.get(prefixedKey);
obj[key] = val === "true" ? true : val === "false" ? false : formData.has(prefixedKey);
} else if (validator instanceof z.$ZodArray) {
obj[key] = handleFormDataGetAll(prefixedKey, formData, validator);
} else {
obj[key] = handleFormDataGet(prefixedKey, formData, validator, baseValidator);
}
}
return obj;
}
function formDataHasKeyOrPrefix(formKeys, key) {
const prefix = key + ".";
return formKeys.some((k) => k === key || k.startsWith(prefix));
}
function handleFormDataGetAll(key, formData, validator) {
const entries = Array.from(formData.getAll(key));
const elementValidator = validator._zod.def.element;
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 unwrapBaseZ4ObjectSchema(schema, unparsedInput) {
if (schema instanceof z.$ZodPipe) {
return unwrapBaseZ4ObjectSchema(schema._zod.def.in, unparsedInput);
}
if (schema instanceof z.$ZodDiscriminatedUnion) {
const typeKey = schema._zod.def.discriminator;
const typeValue = unparsedInput.get(typeKey);
if (typeof typeValue !== "string") return schema;
const objSchema = schema._zod.def.options.find(
(option) => option.def.shape[typeKey].values.has(typeValue)
);
if (!objSchema) return schema;
return objSchema;
}
return schema;
}
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 serializeActionResult(res) {
if (res.error) {
if (import.meta.env?.DEV) {
actionResultErrorStack.set(res.error.stack);
}
let body2;
if (res.error instanceof ActionInputError) {
body2 = {
type: res.error.type,
issues: res.error.issues,
fields: res.error.fields
};
} else {
body2 = {
...res.error,
message: res.error.message
};
}
return {
type: "error",
status: res.error.status,
contentType: "application/json",
body: JSON.stringify(body2)
};
}
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 toArrayBuffer(buffer) {
const copy = new Uint8Array(buffer.byteLength);
copy.set(buffer);
return copy.buffer;
}
export {
ACTION_API_CONTEXT_SYMBOL,
defineAction,
formDataToObject,
getActionContext,
serializeActionResult
};

64
node_modules/astro/dist/actions/runtime/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,64 @@
import type * as z from 'zod/v4/core';
import type { APIContext } from '../../types/public/index.js';
import type { ActionError, codeToStatusMap } from './client.js';
export type ActionErrorCode = keyof typeof codeToStatusMap;
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>>;
type InferKey = '__internalInfer';
/**
* Infers the type of an action's input based on its Zod schema
*
* @see https://docs.astro.build/en/reference/modules/astro-actions/#actioninputschema
*/
export type ActionInputSchema<T extends ActionClient<any, any, any>> = T extends {
[key in InferKey]: any;
} ? T[InferKey] : never;
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>>;
} & {
[key in InferKey]: TInputSchema;
} : ((input?: any) => Promise<SafeResult<never, Awaited<TOutput>>>) & {
orThrow: (input?: any) => Promise<Awaited<TOutput>>;
};
export type SafeResult<TInput extends ErrorInferenceObject, TOutput> = {
data: TOutput;
error: undefined;
} | {
data: undefined;
error: ActionError<TInput>;
};
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 interface ActionsLocals {
_actionPayload: {
actionResult: SerializedActionResult;
actionName: string;
};
}
export type ActionAPIContext = Pick<APIContext, 'request' | 'url' | 'isPrerendered' | 'locals' | 'clientAddress' | 'cookies' | 'currentLocale' | 'generator' | 'routePattern' | 'site' | 'params' | 'preferredLocale' | 'preferredLocaleList' | 'originPathname' | 'session' | 'cache' | 'csp'>;
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 {};

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

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

@@ -0,0 +1,10 @@
import type fsMod from 'node:fs';
import type { APIContext } from '../types/public/context.js';
import type { ActionAPIContext, ActionsLocals } from './runtime/types.js';
export declare function hasActionPayload(locals: APIContext['locals']): locals is ActionsLocals;
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<string | false>;

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

@@ -0,0 +1,65 @@
import * as eslexer from "es-module-lexer";
import { deserializeActionResult, getActionQueryString } from "./runtime/client.js";
import { ACTION_API_CONTEXT_SYMBOL } from "./runtime/server.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.url, "utf-8");
} catch {
return false;
}
const [, exports] = eslexer.parse(contents, actionsFile.url.pathname);
for (const exp of exports) {
if (exp.n === "server") {
return actionsFile.filename;
}
}
return false;
}
function search(fs, srcDir) {
const filenames = [
"actions.mjs",
"actions.js",
"actions.mts",
"actions.ts",
"actions/index.mjs",
"actions/index.js",
"actions/index.mts",
"actions/index.ts"
];
for (const filename of filenames) {
const url = new URL(filename, srcDir);
if (fs.existsSync(url)) {
return { filename, url };
}
}
return void 0;
}
export {
createCallAction,
createGetActionResult,
hasActionPayload,
isActionsFilePresent
};

View File

@@ -0,0 +1,15 @@
import type fsMod from 'node:fs';
import type { Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from '../core/build/internal.js';
import type { StaticBuildOptions } from '../core/build/types.js';
import type { AstroSettings } from '../types/astro.js';
/**
* This plugin is used to retrieve the final entry point of the bundled actions.ts file
* @param opts
* @param internals
*/
export declare function vitePluginActionsBuild(opts: StaticBuildOptions, internals: BuildInternals): VitePlugin;
export declare function vitePluginActions({ fs, settings, }: {
fs: typeof fsMod;
settings: AstroSettings;
}): VitePlugin;

113
node_modules/astro/dist/actions/vite-plugin-actions.js generated vendored Normal file
View File

@@ -0,0 +1,113 @@
import { shouldAppendForwardSlash } from "../core/build/util.js";
import { getServerOutputDirectory } from "../prerender/utils.js";
import {
ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID,
ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID,
OPTIONS_VIRTUAL_MODULE_ID,
RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID,
RESOLVED_OPTIONS_VIRTUAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
VIRTUAL_MODULE_ID
} from "./consts.js";
import { isActionsFilePresent } from "./utils.js";
import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../core/constants.js";
function vitePluginActionsBuild(opts, internals) {
return {
name: "@astro/plugin-actions-build",
applyToEnvironment(environment) {
return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.astro;
},
writeBundle(_, bundle) {
for (const [chunkName, chunk] of Object.entries(bundle)) {
if (chunk.type !== "asset" && chunk.facadeModuleId === ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID) {
const outputDirectory = getServerOutputDirectory(opts.settings);
internals.astroActionsEntryPoint = new URL(chunkName, outputDirectory);
}
}
}
};
}
function vitePluginActions({
fs,
settings
}) {
let resolvedActionsId;
return {
name: VIRTUAL_MODULE_ID,
enforce: "pre",
resolveId: {
filter: {
id: new RegExp(
`^(${VIRTUAL_MODULE_ID}|${OPTIONS_VIRTUAL_MODULE_ID}|${ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID})$`
)
},
async handler(id) {
if (id === VIRTUAL_MODULE_ID) {
return RESOLVED_VIRTUAL_MODULE_ID;
}
if (id === OPTIONS_VIRTUAL_MODULE_ID) {
return RESOLVED_OPTIONS_VIRTUAL_MODULE_ID;
}
if (id === ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID) {
const resolvedModule = await this.resolve(
`${decodeURI(new URL("actions", settings.config.srcDir).pathname)}`
);
if (!resolvedModule) {
return RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID;
}
resolvedActionsId = resolvedModule.id;
return ACTIONS_RESOLVED_ENTRYPOINT_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);
},
load: {
filter: {
id: new RegExp(
`^(${RESOLVED_VIRTUAL_MODULE_ID}|${RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID}|${ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID}|${RESOLVED_OPTIONS_VIRTUAL_MODULE_ID})$`
)
},
async handler(id) {
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
if (this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client) {
return {
code: `export * from 'astro/actions/runtime/entrypoints/client.js';`
};
}
return {
code: `export * from 'astro/actions/runtime/entrypoints/server.js';`
};
}
if (id === RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID) {
return { code: "export const server = {}" };
}
if (id === ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID) {
return { code: `export { server } from ${JSON.stringify(resolvedActionsId)};` };
}
if (id === RESOLVED_OPTIONS_VIRTUAL_MODULE_ID) {
return {
code: `
export const shouldAppendTrailingSlash = ${JSON.stringify(
shouldAppendForwardSlash(settings.config.trailingSlash, settings.config.build.format)
)};
`
};
}
}
}
};
}
export {
vitePluginActions,
vitePluginActionsBuild
};

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

@@ -0,0 +1,23 @@
import type { StaticBuildOptions } from '../../core/build/types.js';
import type { AstroLogger } from '../../core/logger/core.js';
import type { MapValue } from '../../type-utils.js';
import type { AstroConfig } from '../../types/public/config.js';
import type { AssetsGlobalStaticImagesList } from '../types.js';
type AssetEnv = {
logger: AstroLogger;
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(options: StaticBuildOptions, totalCount: number): Promise<AssetEnv>;
export declare function generateImagesForPath(originalFilePath: string, transformsAndPath: MapValue<AssetsGlobalStaticImagesList>, env: AssetEnv): Promise<void>;
export declare function getStaticImageList(): AssetsGlobalStaticImagesList;
export {};

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

@@ -0,0 +1,248 @@
import fs, { readFileSync } from "node:fs";
import { basename } from "node:path/posix";
import colors from "piccolore";
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 { getConfiguredImageService } from "../internal.js";
import { isESMImportedImage } from "../utils/imageKind.js";
import { loadRemoteImage, revalidateRemoteImage } from "./remote.js";
async function prepareAssetsGenerationEnv(options, totalCount) {
const { settings, logger } = options;
let useCache = true;
const assetsCacheDir = new URL("assets/", settings.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;
}
const isServerOutput = settings.buildOutput === "server";
let serverRoot, clientRoot;
if (isServerOutput) {
serverRoot = new URL(".prerender/", settings.config.build.server);
clientRoot = settings.config.build.client;
} else {
serverRoot = getOutDirWithinCwd(settings.config.outDir);
clientRoot = settings.config.outDir;
}
return {
logger,
isSSR: isServerOutput,
count,
useCache,
assetsCacheDir,
serverRoot,
clientRoot,
imageConfig: settings.config.image,
assetsFolder: settings.config.build.assets
};
}
function getFullImagePath(originalFilePath, env) {
return new URL(removeLeadingForwardSlash(originalFilePath), env.serverRoot);
}
async function generateImagesForPath(originalFilePath, transformsAndPath, env) {
let originalImage;
for (const [_, transform] of transformsAndPath.transforms) {
await generateImage(transform.finalPath, transform.transform);
}
if (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 !== "miss" ? generationData.cached === "hit" ? `(reused cache entry)` : `(revalidated cache entry)` : `(before: ${generationData.weight.before}kB, after: ${generationData.weight.after}kB)`;
const count = `(${env.count.current}/${env.count.total})`;
env.logger.info(
null,
` ${colors.green("\u25B6")} ${filepath} ${colors.dim(statsText)} ${colors.dim(timeIncrease)} ${colors.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);
const cachedFileURL = new URL(cacheFile, env.assetsCacheDir);
const cacheMetaFile = cacheFile + ".json";
const cachedMetaFileURL = new URL(cacheMetaFile, env.assetsCacheDir);
try {
if (isLocalImage) {
await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
return {
cached: "hit"
};
} else {
const JSONData = JSON.parse(readFileSync(cachedMetaFileURL, "utf-8"));
if (typeof JSONData.expires !== "number") {
await Promise.allSettled([
fs.promises.unlink(cachedFileURL),
fs.promises.unlink(cachedMetaFileURL)
]);
throw new Error(
`Malformed cache entry for ${filepath}, cache will be regenerated for this file.`
);
}
if (JSONData.data) {
const { data, ...meta } = JSONData;
await Promise.all([
fs.promises.writeFile(cachedFileURL, Buffer.from(data, "base64")),
writeCacheMetaFile(cachedMetaFileURL, meta, env)
]);
}
if (JSONData.expires > Date.now()) {
await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
return { cached: "hit" };
}
if (JSONData.etag || JSONData.lastModified) {
try {
const revalidatedData = await revalidateRemoteImage(options.src, {
etag: JSONData.etag,
lastModified: JSONData.lastModified
});
if (revalidatedData.data !== null) {
originalImage = revalidatedData;
} else {
await Promise.all([
writeCacheMetaFile(cachedMetaFileURL, revalidatedData, env),
fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE)
]);
return { cached: "revalidated" };
}
} catch (e) {
env.logger.warn(
null,
`An error was encountered while revalidating a cached remote asset. Proceeding with stale cache. ${e}`
);
await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
return { cached: "hit" };
}
}
await Promise.allSettled([
fs.promises.unlink(cachedFileURL),
fs.promises.unlink(cachedMetaFileURL)
]);
}
} 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,
etag: originalImage.etag,
lastModified: originalImage.lastModified
};
const imageService = await getConfiguredImageService();
try {
resultData.data = (await imageService.transform(
originalImage.data,
{ ...options, src: originalImagePath },
env.imageConfig
)).data;
} catch (e) {
if (AstroError.is(e)) {
throw 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 Promise.all([
fs.promises.writeFile(cachedFileURL, resultData.data),
writeCacheMetaFile(cachedMetaFileURL, resultData, env)
]);
}
}
} 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: "miss",
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)
}
};
}
}
async function writeCacheMetaFile(cachedMetaFileURL, resultData, env) {
try {
return await fs.promises.writeFile(
cachedMetaFileURL,
JSON.stringify({
expires: resultData.expires,
etag: resultData.etag,
lastModified: resultData.lastModified
}),
"utf-8"
);
} catch (e) {
env.logger.warn(
null,
`An error was encountered while writing the cache file for a remote asset. Proceeding without caching this asset. Error: ${e}`
);
}
}
function getStaticImageList() {
if (!globalThis?.astroAsset?.staticImages) {
return /* @__PURE__ */ new Map();
}
return globalThis.astroAsset.staticImages;
}
async function loadImage(path, env) {
if (isRemotePath(path)) {
return await loadRemoteImage(path);
}
return {
data: await fs.promises.readFile(getFullImagePath(path, env)),
expires: 0
};
}
export {
generateImagesForPath,
getStaticImageList,
prepareAssetsGenerationEnv
};

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

@@ -0,0 +1,30 @@
export type RemoteCacheEntry = {
data?: string;
expires: number;
etag?: string;
lastModified?: string;
};
export declare function loadRemoteImage(src: string, fetchFn?: typeof fetch): Promise<{
data: Buffer<ArrayBuffer>;
expires: number;
etag: string | undefined;
lastModified: string | undefined;
}>;
/**
* Revalidate a cached remote asset using its entity-tag or modified date.
* Uses the [If-None-Match](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match) and [If-Modified-Since](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since)
* headers to check with the remote server if the cached version of a remote asset is still up to date.
* The remote server may respond that the cached asset is still up-to-date if the entity-tag or modification time matches (304 Not Modified), or respond with an updated asset (200 OK)
* @param src - url to remote asset
* @param revalidationData - an object containing the stored Entity-Tag of the cached asset and/or the Last Modified time
* @returns An object containing the refreshed expiry time and cache headers. `data` will be a `Buffer` of the new image if the asset was modified (200 OK), or `null` if the cached version is still valid (304 Not Modified).
*/
export declare function revalidateRemoteImage(src: string, revalidationData: {
etag?: string;
lastModified?: string;
}, fetchFn?: typeof fetch): Promise<{
data: Buffer<ArrayBuffer> | null;
expires: number;
etag: string | undefined;
lastModified: string | undefined;
}>;

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

@@ -0,0 +1,75 @@
import CachePolicy from "http-cache-semantics";
async function loadRemoteImage(src, fetchFn = globalThis.fetch) {
const req = new Request(src);
const res = await fetchFn(req, { redirect: "manual" });
if (res.status >= 300 && res.status < 400) {
throw new Error(`Failed to load remote image ${src}. The request was redirected.`);
}
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,
etag: res.headers.get("Etag") ?? void 0,
lastModified: res.headers.get("Last-Modified") ?? void 0
};
}
async function revalidateRemoteImage(src, revalidationData, fetchFn = globalThis.fetch) {
const headers = {
...revalidationData.etag && { "If-None-Match": revalidationData.etag },
...revalidationData.lastModified && { "If-Modified-Since": revalidationData.lastModified }
};
const req = new Request(src, { headers, cache: "no-cache" });
const res = await fetchFn(req, { redirect: "manual" });
if (!res.ok && res.status !== 304) {
if (res.status >= 300 && res.status < 400) {
throw new Error(
`Failed to revalidate cached remote image ${src}. The request was redirected.`
);
}
throw new Error(
`Failed to revalidate cached remote image ${src}. The request did not return a 200 OK / 304 NOT MODIFIED response. (received ${res.status} ${res.statusText})`
);
}
const data = Buffer.from(await res.arrayBuffer());
if (res.ok && !data.length) {
return await loadRemoteImage(src, fetchFn);
}
const policy = new CachePolicy(
webToCachePolicyRequest(req),
webToCachePolicyResponse(
res.ok ? res : new Response(null, { status: 200, headers: res.headers })
)
// 304 responses are not cacheable, so just use its headers to get the refreshed TTL
);
const expires = policy.storable() ? policy.timeToLive() : 0;
return {
data: res.ok ? data : null,
expires: Date.now() + expires,
// While servers should respond with the same headers as a 200 response, if they don't we should reuse the stored value
etag: res.headers.get("Etag") ?? (res.ok ? void 0 : revalidationData.etag),
lastModified: res.headers.get("Last-Modified") ?? (res.ok ? void 0 : revalidationData.lastModified)
};
}
function webToCachePolicyRequest({ url, method, headers }) {
return {
method,
url,
headers: Object.fromEntries(headers.entries())
};
}
function webToCachePolicyResponse({ status, headers }) {
return {
status,
headers: Object.fromEntries(headers.entries())
};
}
export {
loadRemoteImage,
revalidateRemoteImage
};

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

@@ -0,0 +1,16 @@
export declare const VIRTUAL_MODULE_ID = "astro:assets";
export declare const RESOLVED_VIRTUAL_MODULE_ID: string;
export declare const VIRTUAL_SERVICE_ID = "virtual:image-service";
export declare const VIRTUAL_GET_IMAGE_ID = "virtual:astro:get-image";
export declare const RESOLVED_VIRTUAL_GET_IMAGE_ID: string;
export declare const VIRTUAL_IMAGE_STYLES_ID = "virtual:astro:image-styles.css";
export declare const RESOLVED_VIRTUAL_IMAGE_STYLES_ID: string;
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[];

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

@@ -0,0 +1,53 @@
const VIRTUAL_MODULE_ID = "astro:assets";
const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
const VIRTUAL_SERVICE_ID = "virtual:image-service";
const VIRTUAL_GET_IMAGE_ID = "virtual:astro:get-image";
const RESOLVED_VIRTUAL_GET_IMAGE_ID = "\0" + VIRTUAL_GET_IMAGE_ID;
const VIRTUAL_IMAGE_STYLES_ID = "virtual:astro:image-styles.css";
const RESOLVED_VIRTUAL_IMAGE_STYLES_ID = "\0" + VIRTUAL_IMAGE_STYLES_ID;
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",
"fit",
"position",
"background"
];
export {
DEFAULT_HASH_PROPS,
DEFAULT_OUTPUT_FORMAT,
RESOLVED_VIRTUAL_GET_IMAGE_ID,
RESOLVED_VIRTUAL_IMAGE_STYLES_ID,
RESOLVED_VIRTUAL_MODULE_ID,
VALID_INPUT_FORMATS,
VALID_OUTPUT_FORMATS,
VALID_SUPPORTED_FORMATS,
VIRTUAL_GET_IMAGE_ID,
VIRTUAL_IMAGE_STYLES_ID,
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, RoutesList } from '../../types/astro.js';
export declare function injectImageEndpoint(settings: AstroSettings, manifest: RoutesList, mode: 'dev' | 'build', cwd?: string): void;

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

@@ -0,0 +1,20 @@
import { resolveInjectedRoute } from "../../core/routing/create-manifest.js";
import { parseRoute } from "../../core/routing/parse-route.js";
function injectImageEndpoint(settings, manifest, mode, cwd) {
manifest.routes.unshift(getImageEndpointData(settings, mode, cwd));
}
function getImageEndpointData(settings, mode, cwd) {
const endpointEntrypoint = settings.config.image.endpoint.entrypoint === void 0 ? mode === "dev" ? "astro/assets/endpoint/dev" : "astro/assets/endpoint/generic" : settings.config.image.endpoint.entrypoint;
const component = resolveInjectedRoute(endpointEntrypoint, settings.config.root, cwd).component;
return parseRoute(settings.config.image.endpoint.route, settings, {
component,
type: "endpoint",
origin: "internal",
isIndex: false,
prerender: false,
params: []
});
}
export {
injectImageEndpoint
};

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

@@ -0,0 +1,5 @@
import type { APIRoute } from '../../types/public/common.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/dev.js generated vendored Normal file
View File

@@ -0,0 +1,63 @@
import { fsDenyGlob, safeModulePaths, viteFSConfig } from "astro:assets";
import { readFile } from "node:fs/promises";
import os from "node:os";
import { isFileLoadingAllowed } from "vite";
import { handleImageRequest, loadRemoteImage } from "./shared.js";
function replaceFileSystemReferences(src) {
return os.platform().includes("win32") ? src.replace(/^\/@fs\//, "") : src.replace(/^\/@fs/, "");
}
async function loadLocalImage(src, url) {
let returnValue;
let fsPath;
if (src.startsWith("/@fs/")) {
fsPath = replaceFileSystemReferences(src);
}
if (fsPath && isFileLoadingAllowed(
{
fsDenyGlob,
server: { fs: viteFSConfig },
safeModulePaths
},
fsPath
)) {
try {
returnValue = await readFile(fsPath);
} catch {
returnValue = void 0;
}
if (!returnValue) {
try {
const res = await fetch(new URL(src, url));
if (res.ok) {
returnValue = Buffer.from(await res.arrayBuffer());
}
} catch {
returnValue = void 0;
}
}
} else {
const sourceUrl = new URL(src, url.origin);
if (sourceUrl.origin !== url.origin) {
returnValue = void 0;
}
return loadRemoteImage(sourceUrl);
}
return returnValue;
}
const GET = async ({ request }) => {
if (!import.meta.env.DEV) {
console.error("The dev image endpoint can only be used in dev mode.");
return new Response("Invalid endpoint", { status: 500 });
}
try {
return await handleImageRequest({ request, loadLocalImage });
} catch (err) {
console.error("Could not process image request:", err);
return new Response(`Could not process image request: ${err}`, {
status: 500
});
}
};
export {
GET
};

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/public/common.js';
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export declare const GET: APIRoute;

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

@@ -0,0 +1,70 @@
import { imageConfig } from "astro:assets";
import { isRemotePath } from "@astrojs/internal-helpers/path";
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
import * as mime from "mrmime";
import { getConfiguredImageService } from "../internal.js";
import { etag } from "../utils/etag.js";
async function loadRemoteImage(src, headers) {
try {
const res = await fetch(src, {
// Forward all headers from the original request
headers,
redirect: "manual"
});
if (res.status >= 300 && res.status < 400) {
return void 0;
}
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);
if (isRemoteImage && isRemoteAllowed(transform.src, imageConfig) === false) {
return new Response("Forbidden", { status: 403 });
}
const sourceUrl = new URL(transform.src, url.origin);
if (!isRemoteImage && sourceUrl.origin !== url.origin) {
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/public/common.js';
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export declare const GET: APIRoute;

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

@@ -0,0 +1,56 @@
import { outDir, serverDir } from "astro:assets";
import { readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { isParentDirectory } from "@astrojs/internal-helpers/path";
import { handleImageRequest } from "./shared.js";
async function loadLocalImage(src, url) {
const outDirURL = resolveOutDir();
const idx = url.pathname.indexOf("/_image");
if (idx > 0) {
src = src.slice(idx);
}
if (!URL.canParse("." + src, outDirURL)) {
return void 0;
}
const fileUrl = new URL("." + src, outDirURL);
if (fileUrl.protocol !== "file:") {
return void 0;
}
if (!isParentDirectory(fileURLToPath(outDirURL), fileURLToPath(fileUrl))) {
return void 0;
}
try {
return await readFile(fileUrl);
} catch {
return void 0;
}
}
const GET = async ({ request }) => {
try {
return await handleImageRequest({ request, loadLocalImage });
} catch (err) {
console.error("Could not process image request:", err);
return new Response("Internal Server Error", {
status: 500
});
}
};
function resolveOutDir() {
const serverDirPath = fileURLToPath(serverDir);
const rel = path.relative(serverDirPath, fileURLToPath(outDir));
const serverFolder = path.basename(serverDirPath);
let serverEntryFolderURL = path.dirname(import.meta.url);
while (!serverEntryFolderURL.endsWith(serverFolder)) {
serverEntryFolderURL = path.dirname(serverEntryFolderURL);
}
const serverEntryURL = serverEntryFolderURL + "/entry.mjs";
const outDirURL = new URL(appendForwardSlash(rel), serverEntryURL);
return outDirURL;
}
function appendForwardSlash(pth) {
return pth.endsWith("/") ? pth : pth + "/";
}
export {
GET
};

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

@@ -0,0 +1,5 @@
export declare function loadRemoteImage(src: URL): Promise<Buffer | undefined>;
export declare const handleImageRequest: ({ request, loadLocalImage, }: {
request: Request;
loadLocalImage: (src: string, baseUrl: URL) => Promise<Buffer | undefined>;
}) => Promise<Response>;

67
node_modules/astro/dist/assets/endpoint/shared.js generated vendored Normal file
View File

@@ -0,0 +1,67 @@
import { imageConfig } from "astro:assets";
import { isRemotePath, removeQueryString } from "@astrojs/internal-helpers/path";
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
import * as mime from "mrmime";
import { getConfiguredImageService } from "../internal.js";
import { etag } from "../utils/etag.js";
import { inferSourceFormat } from "../utils/inferSourceFormat.js";
async function loadRemoteImage(src) {
try {
const res = await fetch(src, { redirect: "manual" });
if (res.status >= 300 && res.status < 400) {
return void 0;
}
if (!res.ok) {
return void 0;
}
return Buffer.from(await res.arrayBuffer());
} catch {
return void 0;
}
}
const handleImageRequest = async ({
request,
loadLocalImage
}) => {
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) {
return new Response("Invalid request", { status: 400 });
}
if (transform.format === "svg") {
const sourceFormat = inferSourceFormat(transform.src);
if (sourceFormat !== "svg") {
return new Response("Cannot convert non-SVG source to SVG format", { status: 403 });
}
}
let inputBuffer = void 0;
if (isRemotePath(transform.src)) {
if (!isRemoteAllowed(transform.src, imageConfig)) {
return new Response("Forbidden", { status: 403 });
}
inputBuffer = await loadRemoteImage(new URL(transform.src));
} else {
inputBuffer = await loadLocalImage(removeQueryString(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()
}
});
};
export {
handleImageRequest,
loadRemoteImage
};

59
node_modules/astro/dist/assets/fonts/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,59 @@
import * as z from 'zod/v4';
import type { FontProvider } from './types.js';
export declare const WeightSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
export declare const StyleSchema: z.ZodEnum<{
normal: "normal";
italic: "italic";
oblique: "oblique";
}>;
export declare const DisplaySchema: z.ZodEnum<{
optional: "optional";
auto: "auto";
block: "block";
swap: "swap";
fallback: "fallback";
}>;
export declare const FontProviderSchema: z.ZodCustom<FontProvider<never>, FontProvider<never>>;
export declare const FontFamilySchema: z.ZodObject<{
name: z.ZodString;
cssVariable: z.ZodString;
provider: z.ZodCustom<FontProvider<never>, FontProvider<never>>;
weights: z.ZodOptional<z.ZodTuple<[z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>], z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
styles: z.ZodOptional<z.ZodTuple<[z.ZodEnum<{
normal: "normal";
italic: "italic";
oblique: "oblique";
}>], z.ZodEnum<{
normal: "normal";
italic: "italic";
oblique: "oblique";
}>>>;
subsets: z.ZodOptional<z.ZodTuple<[z.ZodString], z.ZodString>>;
formats: z.ZodOptional<z.ZodTuple<[z.ZodEnum<{
woff2: "woff2";
woff: "woff";
otf: "otf";
ttf: "ttf";
eot: "eot";
}>], z.ZodEnum<{
woff2: "woff2";
woff: "woff";
otf: "otf";
ttf: "ttf";
eot: "eot";
}>>>;
fallbacks: z.ZodOptional<z.ZodArray<z.ZodString>>;
optimizedFallbacks: z.ZodOptional<z.ZodBoolean>;
display: z.ZodOptional<z.ZodEnum<{
optional: "optional";
auto: "auto";
block: "block";
swap: "swap";
fallback: "fallback";
}>>;
stretch: z.ZodOptional<z.ZodString>;
featureSettings: z.ZodOptional<z.ZodString>;
variationSettings: z.ZodOptional<z.ZodString>;
unicodeRange: z.ZodOptional<z.ZodTuple<[z.ZodString], z.ZodString>>;
options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
}, z.core.$strict>;

40
node_modules/astro/dist/assets/fonts/config.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
import * as z from "zod/v4";
import { FONT_TYPES } from "./constants.js";
const WeightSchema = z.union([z.string(), z.number()]);
const StyleSchema = z.enum(["normal", "italic", "oblique"]);
const DisplaySchema = z.enum(["auto", "block", "swap", "fallback", "optional"]);
const FormatSchema = z.enum(FONT_TYPES);
const _FontProviderSchema = z.strictObject({
name: z.string(),
config: z.record(z.string(), z.any()).optional(),
init: z.custom((v) => typeof v === "function").optional(),
resolveFont: z.custom((v) => typeof v === "function"),
listFonts: z.custom((v) => typeof v === "function").optional()
});
const FontProviderSchema = z.custom((v) => {
return _FontProviderSchema.safeParse(v).success;
}, "Invalid FontProvider object");
const FontFamilySchema = z.object({
name: z.string(),
cssVariable: z.string(),
provider: FontProviderSchema,
weights: z.tuple([WeightSchema], WeightSchema).optional(),
styles: z.tuple([StyleSchema], StyleSchema).optional(),
subsets: z.tuple([z.string()], z.string()).optional(),
formats: z.tuple([FormatSchema], FormatSchema).optional(),
fallbacks: z.array(z.string()).optional(),
optimizedFallbacks: z.boolean().optional(),
display: DisplaySchema.optional(),
stretch: z.string().optional(),
featureSettings: z.string().optional(),
variationSettings: z.string().optional(),
unicodeRange: z.tuple([z.string()], z.string()).optional(),
options: z.record(z.string(), z.any()).optional()
}).strict();
export {
DisplaySchema,
FontFamilySchema,
FontProviderSchema,
StyleSchema,
WeightSchema
};

15
node_modules/astro/dist/assets/fonts/constants.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import type { Defaults, FontType } from './types.js';
export declare const DEFAULTS: Defaults;
export declare const VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/internal";
export declare const RESOLVED_VIRTUAL_MODULE_ID: string;
export declare const RUNTIME_VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/runtime";
export declare const RESOLVED_RUNTIME_VIRTUAL_MODULE_ID: string;
export declare const ASSETS_DIR = "fonts";
export declare const CACHE_DIR = "./fonts/";
export declare const FONT_TYPES: readonly ["woff2", "woff", "otf", "ttf", "eot"];
export declare const FONT_FORMATS: Array<{
type: FontType;
format: string;
}>;
export declare const GENERIC_FALLBACK_NAMES: readonly ["serif", "sans-serif", "monospace", "cursive", "fantasy", "system-ui", "ui-serif", "ui-sans-serif", "ui-monospace", "ui-rounded", "emoji", "math", "fangsong"];
export declare const FONTS_TYPES_FILE = "fonts.d.ts";

52
node_modules/astro/dist/assets/fonts/constants.js generated vendored Normal file
View File

@@ -0,0 +1,52 @@
const DEFAULTS = {
weights: ["400"],
styles: ["normal", "italic"],
subsets: ["latin"],
// Technically serif is the browser default but most websites these days use sans-serif
fallbacks: ["sans-serif"],
optimizedFallbacks: true,
formats: ["woff2"]
};
const VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/internal";
const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
const RUNTIME_VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/runtime";
const RESOLVED_RUNTIME_VIRTUAL_MODULE_ID = "\0" + RUNTIME_VIRTUAL_MODULE_ID;
const ASSETS_DIR = "fonts";
const CACHE_DIR = "./fonts/";
const FONT_TYPES = ["woff2", "woff", "otf", "ttf", "eot"];
const FONT_FORMATS = [
{ type: "woff2", format: "woff2" },
{ type: "woff", format: "woff" },
{ type: "otf", format: "opentype" },
{ type: "ttf", format: "truetype" },
{ type: "eot", format: "embedded-opentype" }
];
const GENERIC_FALLBACK_NAMES = [
"serif",
"sans-serif",
"monospace",
"cursive",
"fantasy",
"system-ui",
"ui-serif",
"ui-sans-serif",
"ui-monospace",
"ui-rounded",
"emoji",
"math",
"fangsong"
];
const FONTS_TYPES_FILE = "fonts.d.ts";
export {
ASSETS_DIR,
CACHE_DIR,
DEFAULTS,
FONTS_TYPES_FILE,
FONT_FORMATS,
FONT_TYPES,
GENERIC_FALLBACK_NAMES,
RESOLVED_RUNTIME_VIRTUAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
RUNTIME_VIRTUAL_MODULE_ID,
VIRTUAL_MODULE_ID
};

View File

@@ -0,0 +1,9 @@
import type { CssRenderer } from '../definitions.js';
import type { Collaborator, ComponentDataByCssVariable, Defaults, FontFamilyAssets } from '../types.js';
import type { optimizeFallbacks as _optimizeFallbacks } from './optimize-fallbacks.js';
export declare function collectComponentData({ fontFamilyAssets, cssRenderer, defaults, optimizeFallbacks, }: {
fontFamilyAssets: Array<FontFamilyAssets>;
cssRenderer: CssRenderer;
defaults: Pick<Defaults, 'fallbacks' | 'optimizedFallbacks'>;
optimizeFallbacks: Collaborator<typeof _optimizeFallbacks, 'family' | 'fallbacks' | 'collectedFonts'>;
}): Promise<ComponentDataByCssVariable>;

View File

@@ -0,0 +1,47 @@
import { unifontFontFaceDataToProperties } from "../utils.js";
async function collectComponentData({
fontFamilyAssets,
cssRenderer,
defaults,
optimizeFallbacks
}) {
const componentDataByCssVariable = /* @__PURE__ */ new Map();
for (const { family, fonts, collectedFontsForMetricsByUniqueKey, preloads } of fontFamilyAssets) {
let css = "";
for (const data of fonts) {
css += cssRenderer.generateFontFace(
family.uniqueName,
unifontFontFaceDataToProperties({
src: data.src,
weight: data.weight,
style: data.style,
// User settings override the generated font settings
display: data.display ?? family.display,
unicodeRange: data.unicodeRange ?? family.unicodeRange,
stretch: data.stretch ?? family.stretch,
featureSettings: data.featureSettings ?? family.featureSettings,
variationSettings: data.variationSettings ?? family.variationSettings
})
);
}
const fallbacks = family.fallbacks ?? defaults.fallbacks;
const cssVarValues = [family.uniqueName];
const optimizeFallbacksResult = family.optimizedFallbacks ?? defaults.optimizedFallbacks ? await optimizeFallbacks({
family,
fallbacks,
collectedFonts: Array.from(collectedFontsForMetricsByUniqueKey.values())
}) : null;
if (optimizeFallbacksResult) {
css += optimizeFallbacksResult.css;
cssVarValues.push(...optimizeFallbacksResult.fallbacks);
} else {
cssVarValues.push(...fallbacks);
}
css += cssRenderer.generateCssVariable(family.cssVariable, cssVarValues);
componentDataByCssVariable.set(family.cssVariable, { preloads, css });
}
return componentDataByCssVariable;
}
export {
collectComponentData
};

View File

@@ -0,0 +1,17 @@
import type * as unifont from 'unifont';
import type { FontFileIdGenerator, Hasher } from '../definitions.js';
import type { Defaults, FontFileById, PreloadData, ResolvedFontFamily } from '../types.js';
import type { CollectedFontForMetrics } from './optimize-fallbacks.js';
export declare function collectFontAssetsFromFaces({ fonts, fontFileIdGenerator, family, fontFilesIds, collectedFontsIds, hasher, defaults, }: {
fonts: Array<unifont.FontFaceData>;
fontFileIdGenerator: FontFileIdGenerator;
family: Pick<ResolvedFontFamily, 'cssVariable' | 'fallbacks'>;
fontFilesIds: Set<string>;
collectedFontsIds: Set<string>;
hasher: Hasher;
defaults: Pick<Defaults, 'fallbacks'>;
}): {
fontFileById: FontFileById;
preloads: PreloadData[];
collectedFontsForMetricsByUniqueKey: Map<string, CollectedFontForMetrics>;
};

View File

@@ -0,0 +1,71 @@
import { FONT_FORMATS } from "../constants.js";
import { renderFontWeight } from "../utils.js";
function collectFontAssetsFromFaces({
fonts,
fontFileIdGenerator,
family,
fontFilesIds,
collectedFontsIds,
hasher,
defaults
}) {
const fontFileById = /* @__PURE__ */ new Map();
const collectedFontsForMetricsByUniqueKey = /* @__PURE__ */ new Map();
const preloads = [];
for (const font of fonts) {
let index = 0;
for (const source of font.src) {
if ("name" in source) {
continue;
}
const format = FONT_FORMATS.find((e) => e.format === source.format);
const originalUrl = source.originalURL;
const id = fontFileIdGenerator.generate({
cssVariable: family.cssVariable,
font,
originalUrl,
type: format.type
});
if (!fontFilesIds.has(id) && !fontFileById.has(id)) {
fontFileById.set(id, { url: originalUrl, init: font.meta?.init });
if (index === 0) {
preloads.push({
style: font.style,
subset: font.meta?.subset,
type: format.type,
url: source.url,
weight: renderFontWeight(font.weight)
});
}
}
const collected = {
id,
url: originalUrl,
init: font.meta?.init,
data: {
weight: font.weight,
style: font.style,
meta: {
subset: font.meta?.subset
}
}
};
const collectedKey = hasher.hashObject(collected.data);
const fallbacks = family.fallbacks ?? defaults.fallbacks;
if (fallbacks.length > 0 && // If the same data has already been sent for this family, we don't want to have
// duplicated fallbacks. Such scenario can occur with unicode ranges.
!collectedFontsIds.has(collectedKey) && !collectedFontsForMetricsByUniqueKey.has(collectedKey)) {
collectedFontsForMetricsByUniqueKey.set(collectedKey, collected);
}
index++;
}
}
return {
fontFileById,
preloads,
collectedFontsForMetricsByUniqueKey
};
}
export {
collectFontAssetsFromFaces
};

View File

@@ -0,0 +1,4 @@
import type { FontDataByCssVariable, FontFamilyAssets } from '../types.js';
export declare function collectFontData(fontFamilyAssets: Array<Pick<FontFamilyAssets, 'fonts'> & {
family: Pick<FontFamilyAssets['family'], 'cssVariable'>;
}>): FontDataByCssVariable;

View File

@@ -0,0 +1,23 @@
import { renderFontWeight } from "../utils.js";
function collectFontData(fontFamilyAssets) {
const fontDataByCssVariable = {};
for (const { family, fonts } of fontFamilyAssets) {
const fontData = [];
for (const data of fonts) {
fontData.push({
weight: renderFontWeight(data.weight),
style: data.style,
src: data.src.filter((src) => "url" in src).map((src) => ({
url: src.url,
format: src.format,
tech: src.tech
}))
});
}
fontDataByCssVariable[family.cssVariable] = fontData;
}
return fontDataByCssVariable;
}
export {
collectFontData
};

View File

@@ -0,0 +1,20 @@
import type { AstroLogger } from '../../../core/logger/core.js';
import type { FontResolver, StringMatcher } from '../definitions.js';
import type { Collaborator, Defaults, FontFileById, ResolvedFontFamily } from '../types.js';
import type { collectFontAssetsFromFaces as _collectFontAssetsFromFaces } from './collect-font-assets-from-faces.js';
import type { filterAndTransformFontFaces as _filterAndTransformFontFaces } from './filter-and-transform-font-faces.js';
import type { getOrCreateFontFamilyAssets as _getOrCreateFontFamilyAssets } from './get-or-create-font-family-assets.js';
export declare function computeFontFamiliesAssets({ resolvedFamilies, fontResolver, logger, bold, defaults, stringMatcher, getOrCreateFontFamilyAssets, collectFontAssetsFromFaces, filterAndTransformFontFaces, }: {
resolvedFamilies: Array<ResolvedFontFamily>;
fontResolver: FontResolver;
logger: AstroLogger;
bold: (input: string) => string;
defaults: Defaults;
stringMatcher: StringMatcher;
getOrCreateFontFamilyAssets: Collaborator<typeof _getOrCreateFontFamilyAssets, 'family' | 'fontFamilyAssetsByUniqueKey'>;
filterAndTransformFontFaces: Collaborator<typeof _filterAndTransformFontFaces, 'family' | 'fonts'>;
collectFontAssetsFromFaces: Collaborator<typeof _collectFontAssetsFromFaces, 'family' | 'fonts' | 'collectedFontsIds' | 'fontFilesIds'>;
}): Promise<{
fontFamilyAssets: import("../types.js").FontFamilyAssets[];
fontFileById: FontFileById;
}>;

View File

@@ -0,0 +1,67 @@
async function computeFontFamiliesAssets({
resolvedFamilies,
fontResolver,
logger,
bold,
defaults,
stringMatcher,
getOrCreateFontFamilyAssets,
collectFontAssetsFromFaces,
filterAndTransformFontFaces
}) {
const fontFamilyAssetsByUniqueKey = /* @__PURE__ */ new Map();
const fontFileById = /* @__PURE__ */ new Map();
for (const family of resolvedFamilies) {
const fontAssets = getOrCreateFontFamilyAssets({
fontFamilyAssetsByUniqueKey,
family
});
const _fonts = await fontResolver.resolveFont({
familyName: family.name,
provider: family.provider,
// We do not merge the defaults, we only provide defaults as a fallback
weights: family.weights ?? defaults.weights,
styles: family.styles ?? defaults.styles,
subsets: family.subsets ?? defaults.subsets,
formats: family.formats ?? defaults.formats,
options: family.options
});
if (_fonts.length === 0) {
logger.warn(
"assets",
`No data found for font family ${bold(family.name)}. Review your configuration`
);
const availableFamilies = await fontResolver.listFonts({ provider: family.provider });
if (availableFamilies && availableFamilies.length > 0 && !availableFamilies.includes(family.name)) {
logger.warn(
"assets",
`${bold(family.name)} font family cannot be retrieved by the provider. Did you mean ${bold(stringMatcher.getClosestMatch(family.name, availableFamilies))}?`
);
}
continue;
}
fontAssets.fonts.push(
...filterAndTransformFontFaces({
fonts: _fonts,
family
})
);
const result = collectFontAssetsFromFaces({
fonts: fontAssets.fonts,
family,
fontFilesIds: new Set(fontFileById.keys()),
collectedFontsIds: new Set(fontAssets.collectedFontsForMetricsByUniqueKey.keys())
});
for (const [key, value] of result.fontFileById.entries()) {
fontFileById.set(key, value);
}
for (const [key, value] of result.collectedFontsForMetricsByUniqueKey.entries()) {
fontAssets.collectedFontsForMetricsByUniqueKey.set(key, value);
}
fontAssets.preloads.push(...result.preloads);
}
return { fontFamilyAssets: Array.from(fontFamilyAssetsByUniqueKey.values()), fontFileById };
}
export {
computeFontFamiliesAssets
};

View File

@@ -0,0 +1,20 @@
import type * as unifont from 'unifont';
import type { FontFileIdGenerator, FontTypeExtractor, UrlResolver } from '../definitions.js';
import type { ResolvedFontFamily } from '../types.js';
export declare function filterAndTransformFontFaces({ fonts, fontTypeExtractor, fontFileIdGenerator, urlResolver, family, }: {
fonts: Array<unifont.FontFaceData>;
fontTypeExtractor: FontTypeExtractor;
fontFileIdGenerator: FontFileIdGenerator;
urlResolver: UrlResolver;
family: Pick<ResolvedFontFamily, 'cssVariable'>;
}): {
src: (unifont.LocalFontSource | unifont.RemoteFontSource)[];
display?: "auto" | "block" | "swap" | "fallback" | "optional";
weight?: string | number | [number, number];
stretch?: string;
style?: string;
unicodeRange?: string[];
featureSettings?: string;
variationSettings?: string;
meta?: unifont.FontFaceMeta;
}[];

View File

@@ -0,0 +1,39 @@
import { FONT_FORMATS } from "../constants.js";
function filterAndTransformFontFaces({
fonts,
fontTypeExtractor,
fontFileIdGenerator,
urlResolver,
family
}) {
return fonts.filter((font) => typeof font.meta?.priority === "number" ? font.meta.priority <= 1 : true).map((font) => ({
...font,
src: font.src.map((source) => {
if ("name" in source) {
return source;
}
const originalUrl = source.url.startsWith("//") ? `https:${source.url}` : source.url;
let format = FONT_FORMATS.find((e) => e.format === source.format);
if (!format) {
format = FONT_FORMATS.find((e) => e.type === fontTypeExtractor.extract(source.url));
}
const id = fontFileIdGenerator.generate({
cssVariable: family.cssVariable,
font,
originalUrl,
type: format.type
});
const url = urlResolver.resolve(id);
const newSource = {
originalURL: originalUrl,
url,
format: format.format,
tech: source.tech
};
return newSource;
})
}));
}
export {
filterAndTransformFontFaces
};

View File

@@ -0,0 +1,2 @@
import type { PreloadData, PreloadFilter } from '../types.js';
export declare function filterPreloads(data: Array<PreloadData>, preload: PreloadFilter): Array<PreloadData> | null;

View File

@@ -0,0 +1,37 @@
function filterPreloads(data, preload) {
if (!preload) {
return null;
}
if (preload === true) {
return data;
}
return data.filter(
({ weight, style, subset }) => preload.some((p) => {
if (p.weight !== void 0 && weight !== void 0 && !checkWeight(p.weight.toString(), weight)) {
return false;
}
if (p.style !== void 0 && p.style !== style) {
return false;
}
if (p.subset !== void 0 && p.subset !== subset) {
return false;
}
return true;
})
);
}
function checkWeight(input, target) {
const trimmedInput = input.trim();
if (trimmedInput.includes(" ")) {
return trimmedInput === target;
}
if (target.includes(" ")) {
const [a, b] = target.split(" ");
const parsedInput = Number.parseInt(input);
return parsedInput >= Number.parseInt(a) && parsedInput <= Number.parseInt(b);
}
return input === target;
}
export {
filterPreloads
};

View File

@@ -0,0 +1,8 @@
import type { AstroLogger } from '../../../core/logger/core.js';
import type { FontFamilyAssetsByUniqueKey, ResolvedFontFamily } from '../types.js';
export declare function getOrCreateFontFamilyAssets({ fontFamilyAssetsByUniqueKey, logger, bold, family, }: {
fontFamilyAssetsByUniqueKey: FontFamilyAssetsByUniqueKey;
logger: AstroLogger;
bold: (input: string) => string;
family: ResolvedFontFamily;
}): import("../types.js").FontFamilyAssets;

View File

@@ -0,0 +1,34 @@
function getOrCreateFontFamilyAssets({
fontFamilyAssetsByUniqueKey,
logger,
bold,
family
}) {
const key = `${family.cssVariable}:${family.name}:${family.provider.name}`;
let fontAssets = fontFamilyAssetsByUniqueKey.get(key);
if (!fontAssets) {
if (Array.from(fontFamilyAssetsByUniqueKey.keys()).find(
(k) => k.startsWith(`${family.cssVariable}:`)
)) {
logger.warn(
"assets",
`Several font families have been registered for the ${bold(family.cssVariable)} cssVariable but they do not share the same name and provider.`
);
logger.warn(
"assets",
"These families will not be merged together. The last occurrence will override previous families for this cssVariable. Review your Astro configuration."
);
}
fontAssets = {
family,
fonts: [],
collectedFontsForMetricsByUniqueKey: /* @__PURE__ */ new Map(),
preloads: []
};
fontFamilyAssetsByUniqueKey.set(key, fontAssets);
}
return fontAssets;
}
export {
getOrCreateFontFamilyAssets
};

View File

@@ -0,0 +1,16 @@
import type * as unifont from 'unifont';
import type { FontMetricsResolver, SystemFallbacksProvider } from '../definitions.js';
import type { FontFileData, ResolvedFontFamily } from '../types.js';
export interface CollectedFontForMetrics extends FontFileData {
data: Partial<unifont.FontFaceData>;
}
export declare function optimizeFallbacks({ family, fallbacks: _fallbacks, collectedFonts, systemFallbacksProvider, fontMetricsResolver, }: {
family: Pick<ResolvedFontFamily, 'name' | 'uniqueName'>;
fallbacks: Array<string>;
collectedFonts: Array<CollectedFontForMetrics>;
systemFallbacksProvider: SystemFallbacksProvider;
fontMetricsResolver: FontMetricsResolver;
}): Promise<null | {
css: string;
fallbacks: Array<string>;
}>;

View File

@@ -0,0 +1,46 @@
import { isGenericFontFamily, unifontFontFaceDataToProperties } from "../utils.js";
async function optimizeFallbacks({
family,
fallbacks: _fallbacks,
collectedFonts,
systemFallbacksProvider,
fontMetricsResolver
}) {
let fallbacks = [..._fallbacks];
if (fallbacks.length === 0 || collectedFonts.length === 0) {
return null;
}
const lastFallback = fallbacks[fallbacks.length - 1];
if (!isGenericFontFamily(lastFallback)) {
return null;
}
const localFonts = systemFallbacksProvider.getLocalFonts(lastFallback);
if (!localFonts || localFonts.length === 0) {
return null;
}
if (localFonts.includes(family.name)) {
return null;
}
const localFontsMappings = localFonts.map((font) => ({
font,
// We mustn't wrap in quote because that's handled by the CSS renderer
name: `${family.uniqueName} fallback: ${font}`
}));
fallbacks = [...localFontsMappings.map((m) => m.name), ...fallbacks];
let css = "";
for (const { font, name } of localFontsMappings) {
for (const collected of collectedFonts) {
css += fontMetricsResolver.generateFontFace({
metrics: await fontMetricsResolver.getMetrics(family.name, collected),
fallbackMetrics: systemFallbacksProvider.getMetricsForLocalFont(font),
font,
name,
properties: unifontFontFaceDataToProperties(collected.data)
});
}
}
return { css, fallbacks };
}
export {
optimizeFallbacks
};

View File

@@ -0,0 +1,6 @@
import type { Hasher } from '../definitions.js';
import type { FontFamily, ResolvedFontFamily } from '../types.js';
export declare function resolveFamily({ family, hasher, }: {
family: FontFamily;
hasher: Hasher;
}): ResolvedFontFamily;

View File

@@ -0,0 +1,23 @@
import { dedupe, withoutQuotes } from "../utils.js";
function resolveFamily({
family,
hasher
}) {
const name = withoutQuotes(family.name);
return {
...family,
name,
// This will be used in CSS font faces. Quotes are added by the CSS renderer if
// this value contains a space.
uniqueName: `${name}-${hasher.hashObject(family)}`,
weights: family.weights ? dedupe(family.weights.map((weight) => weight.toString())) : void 0,
styles: family.styles ? dedupe(family.styles) : void 0,
subsets: family.subsets ? dedupe(family.subsets) : void 0,
formats: family.formats ? dedupe(family.formats) : void 0,
fallbacks: family.fallbacks ? dedupe(family.fallbacks) : void 0,
unicodeRange: family.unicodeRange ? dedupe(family.unicodeRange) : void 0
};
}
export {
resolveFamily
};

72
node_modules/astro/dist/assets/fonts/definitions.d.ts generated vendored Normal file
View File

@@ -0,0 +1,72 @@
import type * as unifont from 'unifont';
import type { CollectedFontForMetrics } from './core/optimize-fallbacks.js';
import type { CssProperties, FontFaceMetrics, FontFileData, FontProvider, FontType, GenericFallbackName, ResolveFontOptions, Style } from './types.js';
export interface Hasher {
hashString: (input: string) => string;
hashObject: (input: Record<string, any>) => string;
}
export interface UrlResolver {
resolve: (id: string) => string;
readonly cspResources: Array<string>;
}
export interface FontFileContentResolver {
resolve: (url: string) => string;
}
export interface CssRenderer {
generateFontFace: (family: string, properties: CssProperties) => string;
generateCssVariable: (key: string, values: Array<string>) => string;
}
export interface FontMetricsResolver {
getMetrics: (name: string, font: CollectedFontForMetrics) => Promise<FontFaceMetrics>;
generateFontFace: (input: {
metrics: FontFaceMetrics;
fallbackMetrics: FontFaceMetrics;
name: string;
font: string;
properties: CssProperties;
}) => string;
}
export interface SystemFallbacksProvider {
getLocalFonts: (fallback: GenericFallbackName) => Array<string> | null;
getMetricsForLocalFont: (family: string) => FontFaceMetrics;
}
export interface FontFetcher {
fetch: (input: FontFileData) => Promise<Buffer>;
}
export interface FontTypeExtractor {
extract: (url: string) => FontType;
}
export interface FontFileReader {
extract: (input: {
family: string;
url: string;
}) => {
weight: string;
style: Style;
};
}
export interface FontFileIdGenerator {
generate: (input: {
originalUrl: string;
type: FontType;
cssVariable: string;
font: unifont.FontFaceData;
}) => string;
}
export interface StringMatcher {
getClosestMatch: (target: string, candidates: Array<string>) => string;
}
export interface Storage {
getItem: (key: string) => Promise<any | null>;
getItemRaw: (key: string) => Promise<Buffer | null>;
setItem: (key: string, value: any) => Promise<void>;
setItemRaw: (key: string, value: any) => Promise<void>;
}
export interface FontResolver {
resolveFont: (options: ResolveFontOptions<Record<string, any>> & {
provider: FontProvider;
}) => Promise<Array<unifont.FontFaceData>>;
listFonts: (options: {
provider: FontProvider;
}) => Promise<string[] | undefined>;
}

0
node_modules/astro/dist/assets/fonts/definitions.js generated vendored Normal file
View File

View File

@@ -0,0 +1,13 @@
import type { FontFileContentResolver, FontFileIdGenerator, Hasher } from '../definitions.js';
import type { FontType } from '../types.js';
export declare class BuildFontFileIdGenerator implements FontFileIdGenerator {
#private;
constructor({ hasher, contentResolver, }: {
hasher: Hasher;
contentResolver: FontFileContentResolver;
});
generate({ originalUrl, type }: {
originalUrl: string;
type: FontType;
}): string;
}

View File

@@ -0,0 +1,17 @@
class BuildFontFileIdGenerator {
#hasher;
#contentResolver;
constructor({
hasher,
contentResolver
}) {
this.#hasher = hasher;
this.#contentResolver = contentResolver;
}
generate({ originalUrl, type }) {
return `${this.#hasher.hashString(this.#contentResolver.resolve(originalUrl))}.${type}`;
}
}
export {
BuildFontFileIdGenerator
};

View File

@@ -0,0 +1,12 @@
import type { AssetsPrefix } from '../../../types/public/index.js';
import type { UrlResolver } from '../definitions.js';
export declare class BuildUrlResolver implements UrlResolver {
#private;
constructor({ base, assetsPrefix, searchParams, }: {
base: string;
assetsPrefix: AssetsPrefix;
searchParams: URLSearchParams;
});
resolve(id: string): string;
get cspResources(): Array<string>;
}

View File

@@ -0,0 +1,40 @@
import { fileExtension, joinPaths, prependForwardSlash } from "../../../core/path.js";
import { getAssetsPrefix } from "../../utils/getAssetsPrefix.js";
import { createPlaceholderURL, stringifyPlaceholderURL } from "../../utils/url.js";
class BuildUrlResolver {
#resources = /* @__PURE__ */ new Set();
#base;
#assetsPrefix;
#searchParams;
constructor({
base,
assetsPrefix,
searchParams
}) {
this.#base = base;
this.#assetsPrefix = assetsPrefix;
this.#searchParams = searchParams;
}
resolve(id) {
const prefix = this.#assetsPrefix ? getAssetsPrefix(fileExtension(id), this.#assetsPrefix) : void 0;
let urlPath;
if (prefix) {
this.#resources.add(prefix);
urlPath = joinPaths(prefix, this.#base, id);
} else {
this.#resources.add("'self'");
urlPath = prependForwardSlash(joinPaths(this.#base, id));
}
const url = createPlaceholderURL(urlPath);
this.#searchParams.forEach((value, key) => {
url.searchParams.set(key, value);
});
return stringifyPlaceholderURL(url);
}
get cspResources() {
return Array.from(this.#resources);
}
}
export {
BuildUrlResolver
};

View File

@@ -0,0 +1,11 @@
import type { FontFetcher, Storage } from '../definitions.js';
import type { FontFileData } from '../types.js';
export declare class CachedFontFetcher implements FontFetcher {
#private;
constructor({ storage, fetch, readFile, }: {
storage: Storage;
fetch: (url: string, init?: RequestInit) => Promise<Response>;
readFile: (url: string) => Promise<Buffer>;
});
fetch({ id, url, init }: FontFileData): Promise<Buffer>;
}

View File

@@ -0,0 +1,50 @@
import { isAbsolute } from "node:path";
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
class CachedFontFetcher {
#storage;
#fetch;
#readFile;
constructor({
storage,
fetch,
readFile
}) {
this.#storage = storage;
this.#fetch = fetch;
this.#readFile = readFile;
}
async #cache(storage, key, cb) {
const existing = await storage.getItemRaw(key);
if (existing) {
return existing;
}
const data = await cb();
await storage.setItemRaw(key, data);
return data;
}
async fetch({ id, url, init }) {
return await this.#cache(this.#storage, id, async () => {
try {
if (isAbsolute(url)) {
return await this.#readFile(url);
}
const response = await this.#fetch(url, init ?? void 0);
if (!response.ok) {
throw new Error(`Response was not successful, received status code ${response.status}`);
}
return Buffer.from(await response.arrayBuffer());
} catch (cause) {
throw new AstroError(
{
...AstroErrorData.CannotFetchFontFile,
message: AstroErrorData.CannotFetchFontFile.message(url)
},
{ cause }
);
}
});
}
}
export {
CachedFontFetcher
};

View File

@@ -0,0 +1,18 @@
import type { CollectedFontForMetrics } from '../core/optimize-fallbacks.js';
import type { CssRenderer, FontFetcher, FontMetricsResolver } from '../definitions.js';
import type { CssProperties, FontFaceMetrics } from '../types.js';
export declare class CapsizeFontMetricsResolver implements FontMetricsResolver {
#private;
constructor({ fontFetcher, cssRenderer, }: {
fontFetcher: FontFetcher;
cssRenderer: CssRenderer;
});
getMetrics(name: string, font: CollectedFontForMetrics): Promise<FontFaceMetrics>;
generateFontFace({ metrics, fallbackMetrics, name: fallbackName, font: fallbackFontName, properties, }: {
metrics: FontFaceMetrics;
fallbackMetrics: FontFaceMetrics;
name: string;
font: string;
properties: CssProperties;
}): string;
}

View File

@@ -0,0 +1,71 @@
import { fromBuffer } from "@capsizecss/unpack";
import { renderFontSrc } from "../utils.js";
function filterRequiredMetrics({
ascent,
descent,
lineGap,
unitsPerEm,
xWidthAvg
}) {
return {
ascent,
descent,
lineGap,
unitsPerEm,
xWidthAvg
};
}
function round(value) {
return Number.parseFloat(value.toFixed(4));
}
function toPercentString(value) {
return `${round(value * 100)}%`;
}
class CapsizeFontMetricsResolver {
#cache = {};
#fontFetcher;
#cssRenderer;
constructor({
fontFetcher,
cssRenderer
}) {
this.#fontFetcher = fontFetcher;
this.#cssRenderer = cssRenderer;
}
async getMetrics(name, font) {
return this.#cache[name] ??= filterRequiredMetrics(
await fromBuffer(await this.#fontFetcher.fetch(font))
);
}
// Adapted from Capsize
// Source: https://github.com/seek-oss/capsize/blob/b752693428b45994442433f7e3476ca4e3e3c507/packages/core/src/createFontStack.ts
generateFontFace({
metrics,
fallbackMetrics,
name: fallbackName,
font: fallbackFontName,
properties
}) {
const preferredFontXAvgRatio = metrics.xWidthAvg / metrics.unitsPerEm;
const fallbackFontXAvgRatio = fallbackMetrics.xWidthAvg / fallbackMetrics.unitsPerEm;
const sizeAdjust = preferredFontXAvgRatio && fallbackFontXAvgRatio ? preferredFontXAvgRatio / fallbackFontXAvgRatio : 1;
const adjustedEmSquare = metrics.unitsPerEm * sizeAdjust;
const ascentOverride = metrics.ascent / adjustedEmSquare;
const descentOverride = Math.abs(metrics.descent) / adjustedEmSquare;
const lineGapOverride = metrics.lineGap / adjustedEmSquare;
const fallbackAscentOverride = fallbackMetrics.ascent / adjustedEmSquare;
const fallbackDescentOverride = Math.abs(fallbackMetrics.descent) / adjustedEmSquare;
const fallbackLineGapOverride = fallbackMetrics.lineGap / adjustedEmSquare;
return this.#cssRenderer.generateFontFace(fallbackName, {
...properties,
src: renderFontSrc([{ name: fallbackFontName }]),
"size-adjust": sizeAdjust && sizeAdjust !== 1 ? toPercentString(sizeAdjust) : void 0,
"ascent-override": ascentOverride && ascentOverride !== fallbackAscentOverride ? toPercentString(ascentOverride) : void 0,
"descent-override": descentOverride && descentOverride !== fallbackDescentOverride ? toPercentString(descentOverride) : void 0,
"line-gap-override": lineGapOverride !== fallbackLineGapOverride ? toPercentString(lineGapOverride) : void 0
});
}
}
export {
CapsizeFontMetricsResolver
};

View File

@@ -0,0 +1,16 @@
import type * as unifont from 'unifont';
import type { FontFileContentResolver, FontFileIdGenerator, Hasher } from '../definitions.js';
import type { FontType } from '../types.js';
export declare class DevFontFileIdGenerator implements FontFileIdGenerator {
#private;
constructor({ hasher, contentResolver, }: {
hasher: Hasher;
contentResolver: FontFileContentResolver;
});
generate({ cssVariable, originalUrl, type, font, }: {
originalUrl: string;
type: FontType;
cssVariable: string;
font: unifont.FontFaceData;
}): string;
}

View File

@@ -0,0 +1,40 @@
class DevFontFileIdGenerator {
#hasher;
#contentResolver;
constructor({
hasher,
contentResolver
}) {
this.#hasher = hasher;
this.#contentResolver = contentResolver;
}
#formatWeight(weight) {
if (Array.isArray(weight)) {
return weight.join("-");
}
if (typeof weight === "number") {
return weight.toString();
}
return weight?.replace(/\s+/g, "-");
}
#formatStyle(style) {
return style?.replace(/\s+/g, "-");
}
generate({
cssVariable,
originalUrl,
type,
font
}) {
return [
cssVariable.slice(2),
this.#formatWeight(font.weight),
this.#formatStyle(font.style),
font.meta?.subset,
`${this.#hasher.hashString(this.#contentResolver.resolve(originalUrl))}.${type}`
].filter(Boolean).join("-");
}
}
export {
DevFontFileIdGenerator
};

View File

@@ -0,0 +1,10 @@
import type { UrlResolver } from '../definitions.js';
export declare class DevUrlResolver implements UrlResolver {
#private;
constructor({ base, searchParams, }: {
base: string;
searchParams: URLSearchParams;
});
resolve(id: string): string;
get cspResources(): Array<string>;
}

View File

@@ -0,0 +1,29 @@
import { joinPaths, prependForwardSlash } from "../../../core/path.js";
import { createPlaceholderURL, stringifyPlaceholderURL } from "../../utils/url.js";
class DevUrlResolver {
#resolved = false;
#base;
#searchParams;
constructor({
base,
searchParams
}) {
this.#base = base;
this.#searchParams = searchParams;
}
resolve(id) {
this.#resolved ||= true;
const urlPath = prependForwardSlash(joinPaths(this.#base, id));
const url = createPlaceholderURL(urlPath);
this.#searchParams.forEach((value, key) => {
url.searchParams.set(key, value);
});
return stringifyPlaceholderURL(url);
}
get cspResources() {
return this.#resolved ? ["'self'"] : [];
}
}
export {
DevUrlResolver
};

View File

@@ -0,0 +1,11 @@
import type { FontFileReader } from '../definitions.js';
import type { Style } from '../types.js';
export declare class FontaceFontFileReader implements FontFileReader {
extract({ family, url }: {
family: string;
url: string;
}): {
weight: string;
style: Style;
};
}

View File

@@ -0,0 +1,25 @@
import { readFileSync } from "node:fs";
import { fontace } from "fontace";
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
class FontaceFontFileReader {
extract({ family, url }) {
try {
const data = fontace(readFileSync(url));
return {
weight: data.weight,
style: data.style
};
} catch (cause) {
throw new AstroError(
{
...AstroErrorData.CannotDetermineWeightAndStyleFromFontFile,
message: AstroErrorData.CannotDetermineWeightAndStyleFromFontFile.message(family, url)
},
{ cause }
);
}
}
}
export {
FontaceFontFileReader
};

View File

@@ -0,0 +1,10 @@
import type { FontFileContentResolver } from '../definitions.js';
type ReadFileSync = (path: string) => string;
export declare class FsFontFileContentResolver implements FontFileContentResolver {
#private;
constructor({ readFileSync }: {
readFileSync: ReadFileSync;
});
resolve(url: string): string;
}
export {};

View File

@@ -0,0 +1,21 @@
import { isAbsolute } from "node:path";
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
class FsFontFileContentResolver {
#readFileSync;
constructor({ readFileSync }) {
this.#readFileSync = readFileSync;
}
resolve(url) {
if (!isAbsolute(url)) {
return url;
}
try {
return url + this.#readFileSync(url);
} catch (cause) {
throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause });
}
}
}
export {
FsFontFileContentResolver
};

View File

@@ -0,0 +1,5 @@
import type { StringMatcher } from '../definitions.js';
export declare class LevenshteinStringMatcher implements StringMatcher {
#private;
getClosestMatch(target: string, candidates: Array<string>): string;
}

View File

@@ -0,0 +1,145 @@
class LevenshteinStringMatcher {
#peq = new Uint32Array(65536);
#myers_32(a, b) {
const n = a.length;
const m = b.length;
const lst = 1 << n - 1;
let pv = -1;
let mv = 0;
let sc = n;
let i = n;
while (i--) {
this.#peq[a.charCodeAt(i)] |= 1 << i;
}
for (i = 0; i < m; i++) {
let eq = this.#peq[b.charCodeAt(i)];
const xv = eq | mv;
eq |= (eq & pv) + pv ^ pv;
mv |= ~(eq | pv);
pv &= eq;
if (mv & lst) {
sc++;
}
if (pv & lst) {
sc--;
}
mv = mv << 1 | 1;
pv = pv << 1 | ~(xv | mv);
mv &= xv;
}
i = n;
while (i--) {
this.#peq[a.charCodeAt(i)] = 0;
}
return sc;
}
#myers_x(b, a) {
const n = a.length;
const m = b.length;
const mhc = [];
const phc = [];
const hsize = Math.ceil(n / 32);
const vsize = Math.ceil(m / 32);
for (let i = 0; i < hsize; i++) {
phc[i] = -1;
mhc[i] = 0;
}
let j = 0;
for (; j < vsize - 1; j++) {
let mv2 = 0;
let pv2 = -1;
const start2 = j * 32;
const vlen2 = Math.min(32, m) + start2;
for (let k = start2; k < vlen2; k++) {
this.#peq[b.charCodeAt(k)] |= 1 << k;
}
for (let i = 0; i < n; i++) {
const eq = this.#peq[a.charCodeAt(i)];
const pb = phc[i / 32 | 0] >>> i & 1;
const mb = mhc[i / 32 | 0] >>> i & 1;
const xv = eq | mv2;
const xh = ((eq | mb) & pv2) + pv2 ^ pv2 | eq | mb;
let ph = mv2 | ~(xh | pv2);
let mh = pv2 & xh;
if (ph >>> 31 ^ pb) {
phc[i / 32 | 0] ^= 1 << i;
}
if (mh >>> 31 ^ mb) {
mhc[i / 32 | 0] ^= 1 << i;
}
ph = ph << 1 | pb;
mh = mh << 1 | mb;
pv2 = mh | ~(xv | ph);
mv2 = ph & xv;
}
for (let k = start2; k < vlen2; k++) {
this.#peq[b.charCodeAt(k)] = 0;
}
}
let mv = 0;
let pv = -1;
const start = j * 32;
const vlen = Math.min(32, m - start) + start;
for (let k = start; k < vlen; k++) {
this.#peq[b.charCodeAt(k)] |= 1 << k;
}
let score = m;
for (let i = 0; i < n; i++) {
const eq = this.#peq[a.charCodeAt(i)];
const pb = phc[i / 32 | 0] >>> i & 1;
const mb = mhc[i / 32 | 0] >>> i & 1;
const xv = eq | mv;
const xh = ((eq | mb) & pv) + pv ^ pv | eq | mb;
let ph = mv | ~(xh | pv);
let mh = pv & xh;
score += ph >>> m - 1 & 1;
score -= mh >>> m - 1 & 1;
if (ph >>> 31 ^ pb) {
phc[i / 32 | 0] ^= 1 << i;
}
if (mh >>> 31 ^ mb) {
mhc[i / 32 | 0] ^= 1 << i;
}
ph = ph << 1 | pb;
mh = mh << 1 | mb;
pv = mh | ~(xv | ph);
mv = ph & xv;
}
for (let k = start; k < vlen; k++) {
this.#peq[b.charCodeAt(k)] = 0;
}
return score;
}
#distance(a, b) {
if (a.length < b.length) {
const tmp = b;
b = a;
a = tmp;
}
if (b.length === 0) {
return a.length;
}
if (a.length <= 32) {
return this.#myers_32(a, b);
}
return this.#myers_x(a, b);
}
#closest(str, arr) {
let min_distance = Number.POSITIVE_INFINITY;
let min_index = 0;
for (let i = 0; i < arr.length; i++) {
const dist = this.#distance(str, arr[i]);
if (dist < min_distance) {
min_distance = dist;
min_index = i;
}
}
return arr[min_index];
}
getClosestMatch(target, candidates) {
return this.#closest(target, candidates);
}
}
export {
LevenshteinStringMatcher
};

View File

@@ -0,0 +1,15 @@
import type { CssRenderer } from '../definitions.js';
import type { CssProperties } from '../types.js';
export declare function renderFontFace(properties: CssProperties, minify: boolean): string;
export declare function renderCssVariable(key: string, values: Array<string>, minify: boolean): string;
export declare function withFamily(family: string, properties: CssProperties): CssProperties;
/** If the value contains spaces (which would be incorrectly interpreted), we wrap it in quotes. */
export declare function handleValueWithSpaces(value: string): string;
export declare class MinifiableCssRenderer implements CssRenderer {
#private;
constructor({ minify }: {
minify: boolean;
});
generateFontFace(family: string, properties: CssProperties): string;
generateCssVariable(key: string, values: Array<string>): string;
}

View File

@@ -0,0 +1,44 @@
function renderFontFace(properties, minify) {
const lf = minify ? "" : `
`;
const sp = minify ? "" : " ";
return `@font-face${sp}{${lf}${Object.entries(properties).filter(([, value]) => Boolean(value)).map(([key, value]) => `${sp}${sp}${key}:${sp}${value};`).join(lf)}${lf}}${lf}`;
}
function renderCssVariable(key, values, minify) {
const lf = minify ? "" : `
`;
const sp = minify ? "" : " ";
return `:root${sp}{${lf}${sp}${sp}${key}:${sp}${values.map((v) => handleValueWithSpaces(v)).join(`,${sp}`)};${lf}}${lf}`;
}
function withFamily(family, properties) {
return {
"font-family": handleValueWithSpaces(family),
...properties
};
}
const SPACE_RE = /\s/;
function handleValueWithSpaces(value) {
if (SPACE_RE.test(value)) {
return JSON.stringify(value);
}
return value;
}
class MinifiableCssRenderer {
#minify;
constructor({ minify }) {
this.#minify = minify;
}
generateFontFace(family, properties) {
return renderFontFace(withFamily(family, properties), this.#minify);
}
generateCssVariable(key, values) {
return renderCssVariable(key, values, this.#minify);
}
}
export {
MinifiableCssRenderer,
handleValueWithSpaces,
renderCssVariable,
renderFontFace,
withFamily
};

View File

@@ -0,0 +1,5 @@
import type { FontTypeExtractor } from '../definitions.js';
import type { FontType } from '../types.js';
export declare class NodeFontTypeExtractor implements FontTypeExtractor {
extract(url: string): FontType;
}

View File

@@ -0,0 +1,21 @@
import { extname } from "node:path";
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
import { isFontType } from "../utils.js";
class NodeFontTypeExtractor {
extract(url) {
const extension = extname(url).slice(1);
if (!isFontType(extension)) {
throw new AstroError(
{
...AstroErrorData.CannotExtractFontType,
message: AstroErrorData.CannotExtractFontType.message(url)
},
{ cause: `Unexpected extension, got "${extension}"` }
);
}
return extension;
}
}
export {
NodeFontTypeExtractor
};

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