Initial commit

This commit is contained in:
Alejandro Martinez
2026-02-12 02:04:10 +01:00
commit f09af719cf
13433 changed files with 2193445 additions and 0 deletions

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

@@ -0,0 +1,17 @@
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;
/** Used to expose shared utilities, with server or client specific implementations */
export declare const RUNTIME_VIRTUAL_MODULE_ID = "virtual:astro:actions/runtime";
export declare const RESOLVED_RUNTIME_VIRTUAL_MODULE_ID: string;
export declare const ENTRYPOINT_VIRTUAL_MODULE_ID = "virtual:astro:actions/entrypoint";
export declare const 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]";

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

@@ -0,0 +1,29 @@
const ACTIONS_TYPES_FILE = "actions.d.ts";
const VIRTUAL_MODULE_ID = "astro:actions";
const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
const RUNTIME_VIRTUAL_MODULE_ID = "virtual:astro:actions/runtime";
const RESOLVED_RUNTIME_VIRTUAL_MODULE_ID = "\0" + RUNTIME_VIRTUAL_MODULE_ID;
const ENTRYPOINT_VIRTUAL_MODULE_ID = "virtual:astro:actions/entrypoint";
const RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID = "\0" + 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_TYPES_FILE,
ACTION_QUERY_PARAMS,
ACTION_RPC_ROUTE_PATTERN,
ENTRYPOINT_VIRTUAL_MODULE_ID,
OPTIONS_VIRTUAL_MODULE_ID,
RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID,
RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID,
RESOLVED_OPTIONS_VIRTUAL_MODULE_ID,
RESOLVED_RUNTIME_VIRTUAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
RUNTIME_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;

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

@@ -0,0 +1,43 @@
import { AstroError } from "../core/errors/errors.js";
import { ActionsWithoutServerOutputError } from "../core/errors/errors-data.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/route.js",
prerender: false,
origin: "internal"
});
},
"astro:config:done": async (params) => {
if (params.buildOutput === "static") {
const error = new AstroError(ActionsWithoutServerOutputError);
error.stack = void 0;
throw error;
}
const stringifiedActionsImport = JSON.stringify(
viteID(new URL(`./${filename}`, params.config.srcDir))
);
settings.injectedTypes.push({
filename: ACTIONS_TYPES_FILE,
content: `declare module "astro:actions" {
type Actions = typeof import(${stringifiedActionsImport})["server"];
export const actions: Actions;
}`
});
}
}
};
}
export {
astroIntegrationActionsRouteHandler as default
};

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

@@ -0,0 +1,8 @@
import type { SSRActions } from '../core/app/types.js';
import type { ModuleLoader } from '../core/module-loader/index.js';
/**
* It accepts a module loader and the astro settings, and it attempts to load the middlewares defined in the configuration.
*
* If not middlewares were not set, the function returns an empty array.
*/
export declare function loadActions(moduleLoader: ModuleLoader): Promise<SSRActions>;

13
node_modules/astro/dist/actions/loadActions.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import { ActionsCantBeLoaded } from "../core/errors/errors-data.js";
import { AstroError } from "../core/errors/index.js";
import { ENTRYPOINT_VIRTUAL_MODULE_ID } from "./consts.js";
async function loadActions(moduleLoader) {
try {
return await moduleLoader.import(ENTRYPOINT_VIRTUAL_MODULE_ID);
} catch (error) {
throw new AstroError(ActionsCantBeLoaded, { cause: error });
}
}
export {
loadActions
};

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
};

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

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

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

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

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

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

23
node_modules/astro/dist/actions/runtime/route.js generated vendored Normal file
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
};

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

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

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

@@ -0,0 +1,225 @@
import { z } from "zod";
import { shouldAppendForwardSlash } from "../../core/build/util.js";
import { AstroError } from "../../core/errors/errors.js";
import { ActionCalledFromServerError, ActionNotFoundError } from "../../core/errors/errors-data.js";
import { removeTrailingForwardSlash } from "../../core/path.js";
import { apiContextRoutesSymbol } from "../../core/render-context.js";
import { ACTION_RPC_ROUTE_PATTERN } from "../consts.js";
import {
ACTION_QUERY_PARAMS,
ActionError,
ActionInputError,
callSafely,
deserializeActionResult,
serializeActionResult
} from "./shared.js";
import {
ACTION_API_CONTEXT_SYMBOL,
formContentTypes,
hasContentType,
isActionAPIContext
} from "./utils.js";
export * from "./shared.js";
function defineAction({
accept,
input: inputSchema,
handler
}) {
const serverHandler = accept === "form" ? getFormServerHandler(handler, inputSchema) : getJsonServerHandler(handler, inputSchema);
async function safeServerHandler(unparsedInput) {
if (typeof this === "function" || !isActionAPIContext(this)) {
throw new AstroError(ActionCalledFromServerError);
}
return callSafely(() => serverHandler(unparsedInput, this));
}
Object.assign(safeServerHandler, {
orThrow(unparsedInput) {
if (typeof this === "function") {
throw new AstroError(ActionCalledFromServerError);
}
return serverHandler(unparsedInput, this);
}
});
return safeServerHandler;
}
function getFormServerHandler(handler, inputSchema) {
return async (unparsedInput, context) => {
if (!(unparsedInput instanceof FormData)) {
throw new ActionError({
code: "UNSUPPORTED_MEDIA_TYPE",
message: "This action only accepts FormData."
});
}
if (!inputSchema) return await handler(unparsedInput, context);
const baseSchema = unwrapBaseObjectSchema(inputSchema, unparsedInput);
const parsed = await inputSchema.safeParseAsync(
baseSchema instanceof z.ZodObject ? formDataToObject(unparsedInput, baseSchema) : unparsedInput
);
if (!parsed.success) {
throw new ActionInputError(parsed.error.issues);
}
return await handler(parsed.data, context);
};
}
function getJsonServerHandler(handler, inputSchema) {
return async (unparsedInput, context) => {
if (unparsedInput instanceof FormData) {
throw new ActionError({
code: "UNSUPPORTED_MEDIA_TYPE",
message: "This action only accepts JSON."
});
}
if (!inputSchema) return await handler(unparsedInput, context);
const parsed = await inputSchema.safeParseAsync(unparsedInput);
if (!parsed.success) {
throw new ActionInputError(parsed.error.issues);
}
return await handler(parsed.data, context);
};
}
function formDataToObject(formData, schema) {
const obj = schema._def.unknownKeys === "passthrough" ? Object.fromEntries(formData.entries()) : {};
for (const [key, baseValidator] of Object.entries(schema.shape)) {
let validator = baseValidator;
while (validator instanceof z.ZodOptional || validator instanceof z.ZodNullable || validator instanceof z.ZodDefault) {
if (validator instanceof z.ZodDefault && !formData.has(key)) {
obj[key] = validator._def.defaultValue();
}
validator = validator._def.innerType;
}
if (!formData.has(key) && key in obj) {
continue;
} else if (validator instanceof z.ZodBoolean) {
const val = formData.get(key);
obj[key] = val === "true" ? true : val === "false" ? false : formData.has(key);
} else if (validator instanceof z.ZodArray) {
obj[key] = handleFormDataGetAll(key, formData, validator);
} else {
obj[key] = handleFormDataGet(key, formData, validator, baseValidator);
}
}
return obj;
}
function handleFormDataGetAll(key, formData, validator) {
const entries = Array.from(formData.getAll(key));
const elementValidator = validator._def.type;
if (elementValidator instanceof z.ZodNumber) {
return entries.map(Number);
} else if (elementValidator instanceof z.ZodBoolean) {
return entries.map(Boolean);
}
return entries;
}
function handleFormDataGet(key, formData, validator, baseValidator) {
const value = formData.get(key);
if (!value) {
return baseValidator instanceof z.ZodOptional ? void 0 : null;
}
return validator instanceof z.ZodNumber ? Number(value) : value;
}
function unwrapBaseObjectSchema(schema, unparsedInput) {
while (schema instanceof z.ZodEffects || schema instanceof z.ZodPipeline) {
if (schema instanceof z.ZodEffects) {
schema = schema._def.schema;
}
if (schema instanceof z.ZodPipeline) {
schema = schema._def.in;
}
}
if (schema instanceof z.ZodDiscriminatedUnion) {
const typeKey = schema._def.discriminator;
const typeValue = unparsedInput.get(typeKey);
if (typeof typeValue !== "string") return schema;
const objSchema = schema._def.optionsMap.get(typeValue);
if (!objSchema) return schema;
return objSchema;
}
return schema;
}
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, apiContextRoutesSymbol);
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;
}
let input;
try {
input = await parseRequestBody(context.request);
} catch (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) {
const contentType = request.headers.get("content-type");
const contentLength = request.headers.get("Content-Length");
if (!contentType) return void 0;
if (hasContentType(contentType, formContentTypes)) {
return await request.clone().formData();
}
if (hasContentType(contentType, ["application/json"])) {
return contentLength === "0" ? void 0 : await request.clone().json();
}
throw new TypeError("Unsupported content type");
}
export {
defineAction,
formDataToObject,
getActionContext
};

60
node_modules/astro/dist/actions/runtime/shared.d.ts generated vendored Normal file
View File

@@ -0,0 +1,60 @@
import type { z } from 'zod';
import { AstroError } from '../../core/errors/errors.js';
import { appendForwardSlash as _appendForwardSlash } from '../../core/path.js';
import type { ActionAPIContext as _ActionAPIContext, ErrorInferenceObject, MaybePromise } from './utils.js';
export type ActionAPIContext = _ActionAPIContext;
export declare const ACTION_QUERY_PARAMS: {
actionName: string;
actionPayload: string;
};
export declare const appendForwardSlash: typeof _appendForwardSlash;
export declare const ACTION_ERROR_CODES: readonly ["BAD_REQUEST", "UNAUTHORIZED", "PAYMENT_REQUIRED", "FORBIDDEN", "NOT_FOUND", "METHOD_NOT_ALLOWED", "NOT_ACCEPTABLE", "PROXY_AUTHENTICATION_REQUIRED", "REQUEST_TIMEOUT", "CONFLICT", "GONE", "LENGTH_REQUIRED", "PRECONDITION_FAILED", "CONTENT_TOO_LARGE", "URI_TOO_LONG", "UNSUPPORTED_MEDIA_TYPE", "RANGE_NOT_SATISFIABLE", "EXPECTATION_FAILED", "MISDIRECTED_REQUEST", "UNPROCESSABLE_CONTENT", "LOCKED", "FAILED_DEPENDENCY", "TOO_EARLY", "UPGRADE_REQUIRED", "PRECONDITION_REQUIRED", "TOO_MANY_REQUESTS", "REQUEST_HEADER_FIELDS_TOO_LARGE", "UNAVAILABLE_FOR_LEGAL_REASONS", "INTERNAL_SERVER_ERROR", "NOT_IMPLEMENTED", "BAD_GATEWAY", "SERVICE_UNAVAILABLE", "GATEWAY_TIMEOUT", "HTTP_VERSION_NOT_SUPPORTED", "VARIANT_ALSO_NEGOTIATES", "INSUFFICIENT_STORAGE", "LOOP_DETECTED", "NETWORK_AUTHENTICATION_REQUIRED"];
export type ActionErrorCode = (typeof ACTION_ERROR_CODES)[number];
export declare class ActionError<_T extends ErrorInferenceObject = ErrorInferenceObject> extends Error {
type: string;
code: ActionErrorCode;
status: number;
constructor(params: {
message?: string;
code: ActionErrorCode;
stack?: string;
});
static codeToStatus(code: ActionErrorCode): number;
static statusToCode(status: number): ActionErrorCode;
static fromJson(body: any): ActionError<ErrorInferenceObject>;
}
export declare function isActionError(error?: unknown): error is ActionError;
export declare function isInputError<T extends ErrorInferenceObject>(error?: ActionError<T>): error is ActionInputError<T>;
export declare function isInputError(error?: unknown): error is ActionInputError<ErrorInferenceObject>;
export type SafeResult<TInput extends ErrorInferenceObject, TOutput> = {
data: TOutput;
error: undefined;
} | {
data: undefined;
error: ActionError<TInput>;
};
export declare class ActionInputError<T extends ErrorInferenceObject> extends ActionError {
type: string;
issues: z.ZodIssue[];
fields: z.ZodError<T>['formErrors']['fieldErrors'];
constructor(issues: z.ZodIssue[]);
}
export declare function callSafely<TOutput>(handler: () => MaybePromise<TOutput>): Promise<SafeResult<z.ZodType, TOutput>>;
export declare function getActionQueryString(name: string): string;
export type SerializedActionResult = {
type: 'data';
contentType: 'application/json+devalue';
status: 200;
body: string;
} | {
type: 'error';
contentType: 'application/json';
status: number;
body: string;
} | {
type: 'empty';
status: 204;
};
export declare function serializeActionResult(res: SafeResult<any, any>): SerializedActionResult;
export declare function deserializeActionResult(res: SerializedActionResult): SafeResult<any, any>;
export declare function astroCalledServerError(): AstroError;

296
node_modules/astro/dist/actions/runtime/shared.js generated vendored Normal file
View File

@@ -0,0 +1,296 @@
import { parse as devalueParse, stringify as devalueStringify } from "devalue";
import { REDIRECT_STATUS_CODES } from "../../core/constants.js";
import { AstroError } from "../../core/errors/errors.js";
import {
ActionCalledFromServerError,
ActionsReturnedInvalidDataError
} from "../../core/errors/errors-data.js";
import { appendForwardSlash as _appendForwardSlash } from "../../core/path.js";
import { ACTION_QUERY_PARAMS as _ACTION_QUERY_PARAMS } from "../consts.js";
const ACTION_QUERY_PARAMS = _ACTION_QUERY_PARAMS;
const appendForwardSlash = _appendForwardSlash;
const ACTION_ERROR_CODES = [
"BAD_REQUEST",
"UNAUTHORIZED",
"PAYMENT_REQUIRED",
"FORBIDDEN",
"NOT_FOUND",
"METHOD_NOT_ALLOWED",
"NOT_ACCEPTABLE",
"PROXY_AUTHENTICATION_REQUIRED",
"REQUEST_TIMEOUT",
"CONFLICT",
"GONE",
"LENGTH_REQUIRED",
"PRECONDITION_FAILED",
"CONTENT_TOO_LARGE",
"URI_TOO_LONG",
"UNSUPPORTED_MEDIA_TYPE",
"RANGE_NOT_SATISFIABLE",
"EXPECTATION_FAILED",
"MISDIRECTED_REQUEST",
"UNPROCESSABLE_CONTENT",
"LOCKED",
"FAILED_DEPENDENCY",
"TOO_EARLY",
"UPGRADE_REQUIRED",
"PRECONDITION_REQUIRED",
"TOO_MANY_REQUESTS",
"REQUEST_HEADER_FIELDS_TOO_LARGE",
"UNAVAILABLE_FOR_LEGAL_REASONS",
"INTERNAL_SERVER_ERROR",
"NOT_IMPLEMENTED",
"BAD_GATEWAY",
"SERVICE_UNAVAILABLE",
"GATEWAY_TIMEOUT",
"HTTP_VERSION_NOT_SUPPORTED",
"VARIANT_ALSO_NEGOTIATES",
"INSUFFICIENT_STORAGE",
"LOOP_DETECTED",
"NETWORK_AUTHENTICATION_REQUIRED"
];
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.entries(codeToStatusMap).reduce(
// reverse the key-value pairs
(acc, [key, value]) => ({ ...acc, [value]: key }),
{}
);
class ActionError extends Error {
type = "AstroActionError";
code = "INTERNAL_SERVER_ERROR";
status = 500;
constructor(params) {
super(params.message);
this.code = params.code;
this.status = ActionError.codeToStatus(params.code);
if (params.stack) {
this.stack = params.stack;
}
}
static codeToStatus(code) {
return codeToStatusMap[code];
}
static statusToCode(status) {
return statusToCodeMap[status] ?? "INTERNAL_SERVER_ERROR";
}
static fromJson(body) {
if (isInputError(body)) {
return new ActionInputError(body.issues);
}
if (isActionError(body)) {
return new ActionError(body);
}
return new ActionError({
code: "INTERNAL_SERVER_ERROR"
});
}
}
function isActionError(error) {
return typeof error === "object" && error != null && "type" in error && error.type === "AstroActionError";
}
function isInputError(error) {
return typeof error === "object" && error != null && "type" in error && error.type === "AstroActionInputError" && "issues" in error && Array.isArray(error.issues);
}
class ActionInputError extends ActionError {
type = "AstroActionInputError";
// We don't expose all ZodError properties.
// Not all properties will serialize from server to client,
// and we don't want to import the full ZodError object into the client.
issues;
fields;
constructor(issues) {
super({
message: `Failed to validate: ${JSON.stringify(issues, null, 2)}`,
code: "BAD_REQUEST"
});
this.issues = issues;
this.fields = {};
for (const issue of issues) {
if (issue.path.length > 0) {
const key = issue.path[0].toString();
this.fields[key] ??= [];
this.fields[key]?.push(issue.message);
}
}
}
}
async function callSafely(handler) {
try {
const data = await handler();
return { data, error: void 0 };
} catch (e) {
if (e instanceof ActionError) {
return { data: void 0, error: e };
}
return {
data: void 0,
error: new ActionError({
message: e instanceof Error ? e.message : "Unknown error",
code: "INTERNAL_SERVER_ERROR"
})
};
}
}
function getActionQueryString(name) {
const searchParams = new URLSearchParams({ [_ACTION_QUERY_PARAMS.actionName]: name });
return `?${searchParams.toString()}`;
}
function serializeActionResult(res) {
if (res.error) {
if (import.meta.env?.DEV) {
actionResultErrorStack.set(res.error.stack);
}
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 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 astroCalledServerError() {
return new AstroError(ActionCalledFromServerError);
}
export {
ACTION_ERROR_CODES,
ACTION_QUERY_PARAMS,
ActionError,
ActionInputError,
appendForwardSlash,
astroCalledServerError,
callSafely,
deserializeActionResult,
getActionQueryString,
isActionError,
isInputError,
serializeActionResult
};

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

@@ -0,0 +1,31 @@
import type { APIContext, AstroSharedContext } from '../../types/public/context.js';
import type { SerializedActionResult } from './shared.js';
export type ActionPayload = {
actionResult: SerializedActionResult;
actionName: string;
};
export type Locals = {
_actionPayload: ActionPayload;
};
export declare const ACTION_API_CONTEXT_SYMBOL: unique symbol;
export declare const formContentTypes: string[];
export declare function hasContentType(contentType: string, expected: string[]): boolean;
export type ActionAPIContext = Pick<APIContext, 'rewrite' | 'request' | 'url' | 'isPrerendered' | 'locals' | 'clientAddress' | 'cookies' | 'currentLocale' | 'generator' | 'routePattern' | 'site' | 'params' | 'preferredLocale' | 'preferredLocaleList' | 'originPathname' | 'session' | 'csp'> & {
/**
* @deprecated
* The use of `rewrite` in Actions is deprecated
*/
rewrite: AstroSharedContext['rewrite'];
};
export type MaybePromise<T> = T | Promise<T>;
/**
* Used to preserve the input schema type in the error object.
* This allows for type inference on the `fields` property
* when type narrowed to an `ActionInputError`.
*
* Example: Action has an input schema of `{ name: z.string() }`.
* When calling the action and checking `isInputError(result.error)`,
* `result.error.fields` will be typed with the `name` field.
*/
export type ErrorInferenceObject = Record<string, any>;
export declare function isActionAPIContext(ctx: ActionAPIContext): boolean;

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

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

4
node_modules/astro/dist/actions/runtime/virtual.d.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
import type { ActionClient } from './server.js';
export * from 'virtual:astro:actions/runtime';
export declare function getActionPath(action: ActionClient<any, any, any>): string;
export declare const actions: Record<string | symbol, any>;

127
node_modules/astro/dist/actions/runtime/virtual.js generated vendored Normal file
View File

@@ -0,0 +1,127 @@
import { shouldAppendTrailingSlash } from "virtual:astro:actions/options";
import { internalFetchHeaders } from "virtual:astro:adapter-config/client";
import {
ACTION_QUERY_PARAMS,
ActionError,
appendForwardSlash,
astroCalledServerError,
deserializeActionResult,
getActionQueryString
} from "./shared.js";
export * from "virtual:astro:actions/runtime";
const apiContextRoutesSymbol = Symbol.for("context.routes");
const ENCODED_DOT = "%2E";
function toActionProxy(actionCallback = {}, aggregatedPath = "") {
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 toActionProxy(action, path + ".");
}
});
}
function _getActionPath(toString) {
let path = `${import.meta.env.BASE_URL.replace(/\/$/, "")}/_actions/${new URLSearchParams(toString()).get(ACTION_QUERY_PARAMS.actionName)}`;
if (shouldAppendTrailingSlash) {
path = appendForwardSlash(path);
}
return path;
}
function getActionPath(action) {
return _getActionPath(action.toString);
}
async function handleAction(param, path, context) {
if (import.meta.env.SSR && context) {
const pipeline = Reflect.get(context, apiContextRoutesSymbol);
if (!pipeline) {
throw astroCalledServerError();
}
const action = await pipeline.getAction(path);
if (!action) throw new Error(`Action not found: ${path}`);
return action.bind(context)(param);
}
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(
_getActionPath(() => 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"
});
}
const actions = toActionProxy();
export {
actions,
getActionPath
};

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, type Locals } from './runtime/utils.js';
export declare function hasActionPayload(locals: APIContext['locals']): locals is Locals;
export declare function createGetActionResult(locals: APIContext['locals']): APIContext['getActionResult'];
export declare function createCallAction(context: ActionAPIContext): APIContext['callAction'];
/**
* Check whether the Actions config file is present.
*/
export declare function isActionsFilePresent(fs: typeof fsMod, srcDir: URL): Promise<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/shared.js";
import { ACTION_API_CONTEXT_SYMBOL } from "./runtime/utils.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;

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

@@ -0,0 +1,102 @@
import { addRollupInput } from "../core/build/add-rollup-input.js";
import { shouldAppendForwardSlash } from "../core/build/util.js";
import { getServerOutputDirectory } from "../prerender/utils.js";
import {
ENTRYPOINT_VIRTUAL_MODULE_ID,
OPTIONS_VIRTUAL_MODULE_ID,
RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID,
RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID,
RESOLVED_OPTIONS_VIRTUAL_MODULE_ID,
RESOLVED_RUNTIME_VIRTUAL_MODULE_ID,
RESOLVED_VIRTUAL_MODULE_ID,
RUNTIME_VIRTUAL_MODULE_ID,
VIRTUAL_MODULE_ID
} from "./consts.js";
import { isActionsFilePresent } from "./utils.js";
function vitePluginActionsBuild(opts, internals) {
return {
name: "@astro/plugin-actions-build",
options(options) {
return addRollupInput(options, [ENTRYPOINT_VIRTUAL_MODULE_ID]);
},
writeBundle(_, bundle) {
for (const [chunkName, chunk] of Object.entries(bundle)) {
if (chunk.type !== "asset" && chunk.facadeModuleId === 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",
async resolveId(id) {
if (id === VIRTUAL_MODULE_ID) {
return RESOLVED_VIRTUAL_MODULE_ID;
}
if (id === RUNTIME_VIRTUAL_MODULE_ID) {
return RESOLVED_RUNTIME_VIRTUAL_MODULE_ID;
}
if (id === OPTIONS_VIRTUAL_MODULE_ID) {
return RESOLVED_OPTIONS_VIRTUAL_MODULE_ID;
}
if (id === 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 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);
},
async load(id, opts) {
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
return { code: `export * from 'astro/actions/runtime/virtual.js';` };
}
if (id === RESOLVED_NOOP_ENTRYPOINT_VIRTUAL_MODULE_ID) {
return { code: "export const server = {}" };
}
if (id === RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID) {
return { code: `export { server } from ${JSON.stringify(resolvedActionsId)};` };
}
if (id === RESOLVED_RUNTIME_VIRTUAL_MODULE_ID) {
return {
code: `export * from 'astro/actions/runtime/${opts?.ssr ? "server" : "client"}.js';`
};
}
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 { BuildPipeline } from '../../core/build/pipeline.js';
import type { Logger } 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: Logger;
isSSR: boolean;
count: {
total: number;
current: number;
};
useCache: boolean;
assetsCacheDir: URL;
serverRoot: URL;
clientRoot: URL;
imageConfig: AstroConfig['image'];
assetsFolder: AstroConfig['build']['assets'];
};
export declare function prepareAssetsGenerationEnv(pipeline: BuildPipeline, totalCount: number): Promise<AssetEnv>;
export declare function generateImagesForPath(originalFilePath: string, transformsAndPath: MapValue<AssetsGlobalStaticImagesList>, env: AssetEnv): Promise<void>;
export declare function getStaticImageList(): AssetsGlobalStaticImagesList;
export {};

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

@@ -0,0 +1,250 @@
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(pipeline, totalCount) {
const { config, logger, settings } = pipeline;
let useCache = true;
const assetsCacheDir = new URL("assets/", config.cacheDir);
const count = { total: totalCount, current: 1 };
try {
await fs.promises.mkdir(assetsCacheDir, { recursive: true });
} catch (err) {
logger.warn(
null,
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}`
);
useCache = false;
}
const isServerOutput = settings.buildOutput === "server";
let serverRoot, clientRoot;
if (isServerOutput) {
serverRoot = config.build.server;
clientRoot = config.build.client;
} else {
serverRoot = getOutDirWithinCwd(config.outDir);
clientRoot = config.outDir;
}
return {
logger,
isSSR: isServerOutput,
count,
useCache,
assetsCacheDir,
serverRoot,
clientRoot,
imageConfig: config.image,
assetsFolder: config.build.assets
};
}
function getFullImagePath(originalFilePath, env) {
return new URL(removeLeadingForwardSlash(originalFilePath), env.serverRoot);
}
async function generateImagesForPath(originalFilePath, transformsAndPath, env) {
let originalImage;
for (const [_, transform] of transformsAndPath.transforms) {
await generateImage(transform.finalPath, transform.transform);
}
if (!env.isSSR && transformsAndPath.originalSrcPath && !globalThis.astroAsset.referencedImages?.has(transformsAndPath.originalSrcPath)) {
try {
if (transformsAndPath.originalSrcPath) {
env.logger.debug(
"assets",
`Deleting ${originalFilePath} as it's not referenced outside of image processing.`
);
await fs.promises.unlink(getFullImagePath(originalFilePath, env));
}
} catch {
}
}
async function generateImage(filepath, options) {
const timeStart = performance.now();
const generationData = await generateImageInternal(filepath, options);
const timeEnd = performance.now();
const timeChange = getTimeStat(timeStart, timeEnd);
const timeIncrease = `(+${timeChange})`;
const statsText = generationData.cached !== "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 (!JSONData.expires) {
try {
await fs.promises.unlink(cachedFileURL);
} catch {
}
await 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.length) {
originalImage = revalidatedData;
} else {
await writeCacheMetaFile(cachedMetaFileURL, revalidatedData, env);
await 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 fs.promises.unlink(cachedFileURL);
await 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
})
);
} 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): 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 ImageData object containing the asset data, a new expiry time, and the asset's etag. The data buffer will be empty if the asset was not modified.
*/
export declare function revalidateRemoteImage(src: string, revalidationData: {
etag?: string;
lastModified?: string;
}): Promise<{
data: Buffer<ArrayBuffer>;
expires: number;
etag: string | undefined;
lastModified: string | undefined;
}>;

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

@@ -0,0 +1,77 @@
import CachePolicy from "http-cache-semantics";
async function loadRemoteImage(src) {
const req = new Request(src);
const res = await fetch(req);
if (!res.ok) {
throw new Error(
`Failed to load remote image ${src}. The request did not return a 200 OK response. (received ${res.status}))`
);
}
const policy = new CachePolicy(webToCachePolicyRequest(req), webToCachePolicyResponse(res));
const expires = policy.storable() ? policy.timeToLive() : 0;
return {
data: Buffer.from(await res.arrayBuffer()),
expires: Date.now() + expires,
etag: res.headers.get("Etag") ?? void 0,
lastModified: res.headers.get("Last-Modified") ?? void 0
};
}
async function revalidateRemoteImage(src, revalidationData) {
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 fetch(req);
if (!res.ok && res.status !== 304) {
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);
}
const policy = new CachePolicy(
webToCachePolicyRequest(req),
webToCachePolicyResponse(
res.ok ? res : new Response(null, { status: 200, headers: res.headers })
)
// 304 responses themselves are not cacheable, so just pretend to get the refreshed TTL
);
const expires = policy.storable() ? policy.timeToLive() : 0;
return {
data,
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: _headers }) {
let headers = {};
try {
headers = Object.fromEntries(_headers.entries());
} catch {
}
return {
method,
url,
headers
};
}
function webToCachePolicyResponse({ status, headers: _headers }) {
let headers = {};
try {
headers = Object.fromEntries(_headers.entries());
} catch {
}
return {
status,
headers
};
}
export {
loadRemoteImage,
revalidateRemoteImage
};

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

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

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

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

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

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

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

@@ -0,0 +1,40 @@
import {
removeLeadingForwardSlash,
removeTrailingForwardSlash
} from "@astrojs/internal-helpers/path";
import { resolveInjectedRoute } from "../../core/routing/manifest/create.js";
import { getPattern } from "../../core/routing/manifest/pattern.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 segments = [
[
{
content: removeTrailingForwardSlash(
removeLeadingForwardSlash(settings.config.image.endpoint.route)
),
dynamic: false,
spread: false
}
]
];
return {
type: "endpoint",
isIndex: false,
route: settings.config.image.endpoint.route,
pattern: getPattern(segments, settings.config.base, settings.config.trailingSlash),
segments,
params: [],
component: resolveInjectedRoute(endpointEntrypoint, settings.config.root, cwd).component,
generate: () => "",
pathname: settings.config.image.endpoint.route,
prerender: false,
fallbackRoutes: [],
origin: "internal"
};
}
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;

76
node_modules/astro/dist/assets/endpoint/dev.js generated vendored Normal file
View File

@@ -0,0 +1,76 @@
import { safeModulePaths, viteFSConfig } from "astro:assets";
import { readFile } from "node:fs/promises";
import os from "node:os";
import picomatch from "picomatch";
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: picomatch(
// matchBase: true does not work as it's documented
// https://github.com/micromatch/picomatch/issues/89
// convert patterns without `/` on our side for now
viteFSConfig.deny.map(
(pattern) => pattern.includes("/") ? pattern : `**/${pattern}`
),
{
matchBase: false,
nocase: true,
dot: true
}
),
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;

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

@@ -0,0 +1,66 @@
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
});
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>;

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

@@ -0,0 +1,57 @@
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";
async function loadRemoteImage(src) {
try {
const res = await fetch(src);
if (!res.ok) {
return void 0;
}
return Buffer.from(await res.arrayBuffer());
} catch {
return void 0;
}
}
const 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 });
}
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
};

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

@@ -0,0 +1,55 @@
import { z } from 'zod';
import type { FontProvider } from './types.js';
export declare const weightSchema: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
export declare const styleSchema: z.ZodEnum<["normal", "italic", "oblique"]>;
export declare const displaySchema: z.ZodEnum<["auto", "block", "swap", "fallback", "optional"]>;
export declare const fontProviderSchema: z.ZodType<FontProvider<never>, z.ZodTypeDef, FontProvider<never>>;
export declare const fontFamilySchema: z.ZodObject<{
provider: z.ZodType<FontProvider<never>, z.ZodTypeDef, FontProvider<never>>;
options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
weights: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber]>, "atleastone">>;
styles: z.ZodOptional<z.ZodArray<z.ZodEnum<["normal", "italic", "oblique"]>, "atleastone">>;
subsets: z.ZodOptional<z.ZodArray<z.ZodString, "atleastone">>;
formats: z.ZodOptional<z.ZodArray<z.ZodEnum<["woff2", "woff", "otf", "ttf", "eot"]>, "atleastone">>;
display: z.ZodOptional<z.ZodEnum<["auto", "block", "swap", "fallback", "optional"]>>;
stretch: z.ZodOptional<z.ZodString>;
featureSettings: z.ZodOptional<z.ZodString>;
variationSettings: z.ZodOptional<z.ZodString>;
unicodeRange: z.ZodOptional<z.ZodArray<z.ZodString, "atleastone">>;
fallbacks: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
optimizedFallbacks: z.ZodOptional<z.ZodBoolean>;
name: z.ZodString;
cssVariable: z.ZodString;
}, "strict", z.ZodTypeAny, {
name: string;
cssVariable: string;
provider: FontProvider<never>;
weights?: [string | number, ...(string | number)[]] | undefined;
styles?: ["normal" | "italic" | "oblique", ...("normal" | "italic" | "oblique")[]] | undefined;
subsets?: [string, ...string[]] | undefined;
fallbacks?: string[] | undefined;
optimizedFallbacks?: boolean | undefined;
formats?: ["woff2" | "woff" | "otf" | "ttf" | "eot", ...("woff2" | "woff" | "otf" | "ttf" | "eot")[]] | undefined;
display?: "auto" | "block" | "swap" | "fallback" | "optional" | undefined;
stretch?: string | undefined;
featureSettings?: string | undefined;
variationSettings?: string | undefined;
unicodeRange?: [string, ...string[]] | undefined;
options?: Record<string, any> | undefined;
}, {
name: string;
cssVariable: string;
provider: FontProvider<never>;
weights?: [string | number, ...(string | number)[]] | undefined;
styles?: ["normal" | "italic" | "oblique", ...("normal" | "italic" | "oblique")[]] | undefined;
subsets?: [string, ...string[]] | undefined;
fallbacks?: string[] | undefined;
optimizedFallbacks?: boolean | undefined;
formats?: ["woff2" | "woff" | "otf" | "ttf" | "eot", ...("woff2" | "woff" | "otf" | "ttf" | "eot")[]] | undefined;
display?: "auto" | "block" | "swap" | "fallback" | "optional" | undefined;
stretch?: string | undefined;
featureSettings?: string | undefined;
variationSettings?: string | undefined;
unicodeRange?: [string, ...string[]] | undefined;
options?: Record<string, any> | undefined;
}>;

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

@@ -0,0 +1,53 @@
import { z } from "zod";
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 familyPropertiesSchema = z.object({
weight: weightSchema.optional(),
style: styleSchema.optional(),
display: displaySchema.optional(),
stretch: z.string().optional(),
featureSettings: z.string().optional(),
variationSettings: z.string().optional(),
unicodeRange: z.array(z.string()).nonempty().optional()
});
const fallbacksSchema = z.object({
fallbacks: z.array(z.string()).optional(),
optimizedFallbacks: z.boolean().optional()
});
const requiredFamilyAttributesSchema = z.object({
name: z.string(),
cssVariable: z.string()
});
const _fontProviderSchema = z.object({
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()
}).strict();
const fontProviderSchema = z.custom((v) => {
return _fontProviderSchema.safeParse(v).success;
}, "Invalid FontProvider object");
const fontFamilySchema = z.object({
...requiredFamilyAttributesSchema.shape,
...fallbacksSchema.shape,
...familyPropertiesSchema.omit({
weight: true,
style: true
}).shape,
provider: fontProviderSchema,
options: z.record(z.string(), z.any()).optional(),
weights: z.array(weightSchema).nonempty().optional(),
styles: z.array(styleSchema).nonempty().optional(),
subsets: z.array(z.string()).nonempty().optional(),
formats: z.array(z.enum(FONT_TYPES)).nonempty().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 { Logger } 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: Logger;
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 { Logger } from '../../../core/logger/core.js';
import type { FontFamilyAssetsByUniqueKey, ResolvedFontFamily } from '../types.js';
export declare function getOrCreateFontFamilyAssets({ fontFamilyAssetsByUniqueKey, logger, bold, family, }: {
fontFamilyAssetsByUniqueKey: FontFamilyAssetsByUniqueKey;
logger: Logger;
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 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,37 @@
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, "-");
}
generate({
cssVariable,
originalUrl,
type,
font
}) {
return [
cssVariable.slice(2),
this.#formatWeight(font.weight),
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 = 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
};

View File

@@ -0,0 +1,6 @@
import type { SystemFallbacksProvider } from '../definitions.js';
import type { FontFaceMetrics, GenericFallbackName } from '../types.js';
export declare class RealSystemFallbacksProvider implements SystemFallbacksProvider {
getLocalFonts(fallback: GenericFallbackName): Array<string> | null;
getMetricsForLocalFont(family: string): FontFaceMetrics;
}

View File

@@ -0,0 +1,71 @@
const SYSTEM_METRICS = {
"Times New Roman": {
ascent: 1825,
descent: -443,
lineGap: 87,
unitsPerEm: 2048,
xWidthAvg: 832
},
Arial: {
ascent: 1854,
descent: -434,
lineGap: 67,
unitsPerEm: 2048,
xWidthAvg: 913
},
"Courier New": {
ascent: 1705,
descent: -615,
lineGap: 0,
unitsPerEm: 2048,
xWidthAvg: 1229
},
BlinkMacSystemFont: {
ascent: 1980,
descent: -432,
lineGap: 0,
unitsPerEm: 2048,
xWidthAvg: 853
},
"Segoe UI": {
ascent: 2210,
descent: -514,
lineGap: 0,
unitsPerEm: 2048,
xWidthAvg: 908
},
Roboto: {
ascent: 1900,
descent: -500,
lineGap: 0,
unitsPerEm: 2048,
xWidthAvg: 911
},
"Helvetica Neue": {
ascent: 952,
descent: -213,
lineGap: 28,
unitsPerEm: 1e3,
xWidthAvg: 450
}
};
const DEFAULT_FALLBACKS = {
serif: ["Times New Roman"],
"sans-serif": ["Arial"],
monospace: ["Courier New"],
"system-ui": ["BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial"],
"ui-serif": ["Times New Roman"],
"ui-sans-serif": ["Arial"],
"ui-monospace": ["Courier New"]
};
class RealSystemFallbacksProvider {
getLocalFonts(fallback) {
return DEFAULT_FALLBACKS[fallback] ?? null;
}
getMetricsForLocalFont(family) {
return SYSTEM_METRICS[family];
}
}
export {
RealSystemFallbacksProvider
};

View File

@@ -0,0 +1,34 @@
import type { FontFaceData, Provider } from 'unifont';
import type { FontResolver, Hasher, Storage } from '../definitions.js';
import type { FontProvider, ResolvedFontFamily, ResolveFontOptions } from '../types.js';
type NonEmptyProviders = [
Provider<string, Record<string, any>>,
...Array<Provider<string, Record<string, any>>>
];
export declare class UnifontFontResolver implements FontResolver {
#private;
private constructor();
static idFromProvider({ hasher, provider }: {
hasher: Hasher;
provider: FontProvider;
}): string;
static astroToUnifontProvider(astroProvider: FontProvider, root: URL): Provider;
static extractUnifontProviders({ families, hasher, root, }: {
families: Array<ResolvedFontFamily>;
hasher: Hasher;
root: URL;
}): NonEmptyProviders;
static create({ families, hasher, storage, root, }: {
families: Array<ResolvedFontFamily>;
hasher: Hasher;
storage: Storage;
root: URL;
}): Promise<UnifontFontResolver>;
resolveFont({ familyName, provider, options, ...rest }: ResolveFontOptions<Record<string, any>> & {
provider: FontProvider;
}): Promise<Array<FontFaceData>>;
listFonts({ provider }: {
provider: FontProvider;
}): Promise<string[] | undefined>;
}
export {};

View File

@@ -0,0 +1,98 @@
import { createUnifont, defineFontProvider } from "unifont";
class UnifontFontResolver {
#unifont;
#hasher;
constructor({
unifont,
hasher
}) {
this.#unifont = unifont;
this.#hasher = hasher;
}
static idFromProvider({ hasher, provider }) {
const hash = hasher.hashObject({
name: provider.name,
...provider.config
});
return `${provider.name}-${hash}`;
}
static astroToUnifontProvider(astroProvider, root) {
return defineFontProvider(astroProvider.name, async (_options, ctx) => {
await astroProvider?.init?.({ ...ctx, root });
return {
async resolveFont(familyName, { options, ...rest }) {
return await astroProvider.resolveFont({ familyName, options, ...rest });
},
async listFonts() {
return astroProvider.listFonts?.();
}
};
})(astroProvider.config);
}
static extractUnifontProviders({
families,
hasher,
root
}) {
const providers = /* @__PURE__ */ new Map();
for (const { provider } of families) {
const id = this.idFromProvider({ hasher, provider });
if (!providers.has(id)) {
const unifontProvider = this.astroToUnifontProvider(provider, root);
unifontProvider._name = this.idFromProvider({ hasher, provider });
providers.set(id, unifontProvider);
}
}
return Array.from(providers.values());
}
static async create({
families,
hasher,
storage,
root
}) {
return new UnifontFontResolver({
unifont: await createUnifont(this.extractUnifontProviders({ families, hasher, root }), {
storage,
// TODO: consider enabling, would require new astro errors
throwOnError: false
}),
hasher
});
}
async resolveFont({
familyName,
provider,
options,
...rest
}) {
const id = UnifontFontResolver.idFromProvider({
hasher: this.#hasher,
provider
});
const { fonts } = await this.#unifont.resolveFont(
familyName,
{
// Options are currently namespaced by provider name, it may change in
// https://github.com/unjs/unifont/pull/287
options: {
[id]: options
},
...rest
},
[id]
);
return fonts;
}
async listFonts({ provider }) {
return await this.#unifont.listFonts([
UnifontFontResolver.idFromProvider({
hasher: this.#hasher,
provider
})
]);
}
}
export {
UnifontFontResolver
};

View File

@@ -0,0 +1,11 @@
import type { Storage } from '../definitions.js';
export declare class UnstorageFsStorage implements Storage {
#private;
constructor({ base }: {
base: URL;
});
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>;
}

View File

@@ -0,0 +1,26 @@
import { fileURLToPath } from "node:url";
import * as unstorage from "unstorage";
import fsLiteDriver from "unstorage/drivers/fs-lite";
class UnstorageFsStorage {
#unstorage;
constructor({ base }) {
this.#unstorage = unstorage.createStorage({
driver: fsLiteDriver({ base: fileURLToPath(base) })
});
}
async getItem(key) {
return await this.#unstorage.getItem(key);
}
async getItemRaw(key) {
return await this.#unstorage.getItemRaw(key);
}
async setItem(key, value) {
return await this.#unstorage.setItem(key, value);
}
async setItemRaw(key, value) {
return await this.#unstorage.setItemRaw(key, value);
}
}
export {
UnstorageFsStorage
};

View File

@@ -0,0 +1,7 @@
import type { Hasher } from '../definitions.js';
export declare class XxhashHasher implements Hasher {
hashString: (input: string) => string;
private constructor();
static create(): Promise<XxhashHasher>;
hashObject(input: Record<string, any>): string;
}

View File

@@ -0,0 +1,18 @@
import xxhash from "xxhash-wasm";
import { sortObjectByKey } from "../utils.js";
class XxhashHasher {
hashString;
constructor(hashString) {
this.hashString = hashString;
}
static async create() {
const { h64ToString } = await xxhash();
return new XxhashHasher(h64ToString);
}
hashObject(input) {
return this.hashString(JSON.stringify(sortObjectByKey(input)));
}
}
export {
XxhashHasher
};

View File

@@ -0,0 +1,37 @@
import { type AdobeProviderOptions, type GoogleFamilyOptions, type GoogleiconsFamilyOptions } from 'unifont';
import type { FontProvider } from '../types.js';
import { type LocalFamilyOptions } from './local.js';
/** [Adobe](https://fonts.adobe.com/) */
declare function adobe(config: AdobeProviderOptions): FontProvider;
/** [Bunny](https://fonts.bunny.net/) */
declare function bunny(): FontProvider;
/** [Fontshare](https://www.fontshare.com/) */
declare function fontshare(): FontProvider;
/** [Fontsource](https://fontsource.org/) */
declare function fontsource(): FontProvider;
/** [Google](https://fonts.google.com/) */
declare function google(): FontProvider<GoogleFamilyOptions | undefined>;
/** [Google Icons](https://fonts.google.com/icons) */
declare function googleicons(): FontProvider<GoogleiconsFamilyOptions | undefined>;
/** A provider that handles local files. */
declare function local(): FontProvider<LocalFamilyOptions>;
/**
* Astro exports a few built-in providers:
* - [Adobe](https://fonts.adobe.com/)
* - [Bunny](https://fonts.bunny.net/)
* - [Fontshare](https://www.fontshare.com/)
* - [Fontsource](https://fontsource.org/)
* - [Google](https://fonts.google.com/)
* - [Google Icons](https://fonts.google.com/icons)
* - Local
*/
export declare const fontProviders: {
adobe: typeof adobe;
bunny: typeof bunny;
fontshare: typeof fontshare;
fontsource: typeof fontsource;
google: typeof google;
googleicons: typeof googleicons;
local: typeof local;
};
export {};

119
node_modules/astro/dist/assets/fonts/providers/index.js generated vendored Normal file
View File

@@ -0,0 +1,119 @@
import {
providers
} from "unifont";
import { FontaceFontFileReader } from "../infra/fontace-font-file-reader.js";
import { LocalFontProvider } from "./local.js";
function adobe(config) {
const provider = providers.adobe(config);
let initializedProvider;
return {
name: provider._name,
config,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function bunny() {
const provider = providers.bunny();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function fontshare() {
const provider = providers.fontshare();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function fontsource() {
const provider = providers.fontsource();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function google() {
const provider = providers.google();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function googleicons() {
const provider = providers.googleicons();
let initializedProvider;
return {
name: provider._name,
async init(context) {
initializedProvider = await provider(context);
},
async resolveFont({ familyName, ...rest }) {
return await initializedProvider?.resolveFont(familyName, rest);
},
async listFonts() {
return await initializedProvider?.listFonts?.();
}
};
}
function local() {
return new LocalFontProvider({
fontFileReader: new FontaceFontFileReader()
});
}
const fontProviders = {
adobe,
bunny,
fontshare,
fontsource,
google,
googleicons,
local
};
export {
fontProviders
};

View File

@@ -0,0 +1,44 @@
import type * as unifont from 'unifont';
import type { FontFileReader } from '../definitions.js';
import type { FamilyProperties, FontProvider, FontProviderInitContext, ResolveFontOptions, Style, Weight } from '../types.js';
type RawSource = string | URL | {
url: string | URL;
tech?: string | undefined;
};
interface Variant extends FamilyProperties {
/**
* Font [sources](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src). It can be a path relative to the root, a package import or a URL. URLs are particularly useful if you inject local fonts through an integration.
*/
src: [RawSource, ...Array<RawSource>];
/**
* A [font weight](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight). If the associated font is a [variable font](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_fonts/Variable_fonts_guide), you can specify a range of weights:
*
* ```js
* weight: "100 900"
* ```
*/
weight?: Weight | undefined;
/**
* A [font style](https://developer.mozilla.org/en-US/docs/Web/CSS/font-style).
*/
style?: Style | undefined;
}
export interface LocalFamilyOptions {
/**
* Each variant represents a [`@font-face` declaration](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/).
*/
variants: [Variant, ...Array<Variant>];
}
export declare class LocalFontProvider implements FontProvider<LocalFamilyOptions> {
#private;
name: string;
config?: Record<string, any> | undefined;
constructor({ fontFileReader, }: {
fontFileReader: FontFileReader;
});
init(context: Pick<FontProviderInitContext, 'root'>): void;
resolveFont(options: ResolveFontOptions<LocalFamilyOptions>): {
fonts: Array<unifont.FontFaceData>;
};
}
export {};

View File

@@ -0,0 +1,69 @@
import { createRequire } from "node:module";
import { fileURLToPath, pathToFileURL } from "node:url";
class LocalFontProvider {
name = "local";
config;
#fontFileReader;
#root;
constructor({
fontFileReader
}) {
this.config = void 0;
this.#fontFileReader = fontFileReader;
this.#root = void 0;
}
init(context) {
this.#root = context.root;
}
#resolveEntrypoint(root, entrypoint) {
const require2 = createRequire(root);
try {
return pathToFileURL(require2.resolve(entrypoint));
} catch {
return new URL(entrypoint, root);
}
}
#normalizeSource(value) {
const isValue = typeof value === "string" || value instanceof URL;
const url = (isValue ? value : value.url).toString();
const tech = isValue ? void 0 : value.tech;
return {
url: fileURLToPath(this.#resolveEntrypoint(this.#root ?? new URL(import.meta.url), url)),
tech
};
}
resolveFont(options) {
return {
fonts: options.options?.variants.map((variant) => {
const shouldInfer = variant.weight === void 0 || variant.style === void 0;
const data = {
// If it should be inferred, we don't want to set the value
weight: variant.weight,
style: variant.style,
src: [],
unicodeRange: variant.unicodeRange,
display: variant.display,
stretch: variant.stretch,
featureSettings: variant.featureSettings,
variationSettings: variant.variationSettings
};
data.src = variant.src.map((rawSource, index) => {
const source = this.#normalizeSource(rawSource);
if (shouldInfer && index === 0) {
const result = this.#fontFileReader.extract({
family: options.familyName,
url: source.url
});
if (variant.weight === void 0) data.weight = result.weight;
if (variant.style === void 0) data.style = result.style;
}
return source;
});
return data;
}) ?? []
};
}
}
export {
LocalFontProvider
};

1
node_modules/astro/dist/assets/fonts/runtime.d.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export declare const fontData: import("./types.js").FontDataByCssVariable;

5
node_modules/astro/dist/assets/fonts/runtime.js generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import * as fontsMod from "virtual:astro:assets/fonts/internal";
const fontData = fontsMod.fontDataByCssVariable ?? {};
export {
fontData
};

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