mirror of
https://github.com/withastro/astro.git
synced 2024-12-30 22:03:56 -05:00
feat: port astro-actions poc
This commit is contained in:
parent
10c5b039f9
commit
deb38c8cf2
12 changed files with 493 additions and 1 deletions
3
packages/actions/index.d.ts
vendored
Normal file
3
packages/actions/index.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/// <reference path="./virtual.d.ts" />
|
||||
|
||||
export { default } from './src/index.js';
|
65
packages/actions/package.json
Normal file
65
packages/actions/package.json
Normal file
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"name": "@astrojs/actions",
|
||||
"version": "0.0.1",
|
||||
"description": "Add RPC actions to your Astro projects",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/withastro/astro.git",
|
||||
"directory": "packages/actions"
|
||||
},
|
||||
"bugs": "https://github.com/withastro/astro/issues",
|
||||
"homepage": "https://docs.astro.build/",
|
||||
"type": "module",
|
||||
"author": "withastro",
|
||||
"types": "./index.d.ts",
|
||||
"main": "./dist/index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./config": {
|
||||
"types": "./dist/runtime/config.d.ts",
|
||||
"import": "./dist/runtime/config.js"
|
||||
},
|
||||
"./route.js": "./dist/runtime/route.js",
|
||||
"./middleware.js": "./dist/runtime/middleware.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
".": [
|
||||
"./index.d.ts"
|
||||
],
|
||||
"config": [
|
||||
"./dist/config.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"virtual.d.ts",
|
||||
"dist"
|
||||
],
|
||||
"keywords": [
|
||||
"withastro",
|
||||
"astro-integration"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
|
||||
"build:ci": "astro-scripts build \"src/**/*.ts\"",
|
||||
"dev": "astro-scripts dev \"src/**/*.ts\"",
|
||||
"test": "mocha --exit --timeout 20000 \"test/*.js\" \"test/unit/**/*.js\"",
|
||||
"test:match": "mocha --timeout 20000 \"test/*.js\" \"test/unit/*.js\" -g"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro-integration-kit": "^0.11.0",
|
||||
"zod": "^3.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"astro": "workspace:*",
|
||||
"astro-scripts": "workspace:*",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
60
packages/actions/src/index.ts
Normal file
60
packages/actions/src/index.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
import type { AstroIntegration } from 'astro';
|
||||
import { addDts, addVitePlugin } from 'astro-integration-kit';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
|
||||
const VIRTUAL_MODULE_ID = 'astro:actions';
|
||||
const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
|
||||
|
||||
export default function astroActions(): AstroIntegration {
|
||||
return {
|
||||
name: 'astro-actions',
|
||||
hooks: {
|
||||
async 'astro:config:setup'(params) {
|
||||
const stringifiedActionsPath = JSON.stringify(
|
||||
new URL('actions', params.config.srcDir).pathname
|
||||
);
|
||||
params.updateConfig({
|
||||
vite: {
|
||||
define: {
|
||||
'import.meta.env.ACTIONS_PATH': stringifiedActionsPath,
|
||||
},
|
||||
},
|
||||
});
|
||||
params.injectRoute({
|
||||
pattern: '/_actions/[...path]',
|
||||
entrypoint: '@astrojs/actions/route.js',
|
||||
prerender: false,
|
||||
});
|
||||
params.addMiddleware({
|
||||
entrypoint: '@astrojs/actions/middleware.js',
|
||||
order: 'pre',
|
||||
});
|
||||
addDts(params, {
|
||||
name: 'astro-actions',
|
||||
content: `declare module "astro:actions" {
|
||||
type Actions = typeof import(${stringifiedActionsPath})["default"];
|
||||
|
||||
export const actions: Actions;
|
||||
}`,
|
||||
});
|
||||
|
||||
addVitePlugin(params, {
|
||||
plugin: {
|
||||
name: 'astro-actions',
|
||||
enforce: 'pre',
|
||||
resolveId(id) {
|
||||
if (id === VIRTUAL_MODULE_ID) {
|
||||
return RESOLVED_VIRTUAL_MODULE_ID;
|
||||
}
|
||||
},
|
||||
async load(id) {
|
||||
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
|
||||
return await readFile(new URL('./virtual.js', import.meta.url), 'utf-8');
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
88
packages/actions/src/runtime/config.ts
Normal file
88
packages/actions/src/runtime/config.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import type { APIContext } from 'astro';
|
||||
import { z } from 'zod';
|
||||
import { ApiContextStorage } from './utils.js';
|
||||
|
||||
export function enhanceProps<T extends Function>(action: T) {
|
||||
return {
|
||||
type: 'hidden',
|
||||
name: '_astroAction',
|
||||
value: action.toString(),
|
||||
} as const;
|
||||
}
|
||||
|
||||
type MaybePromise<T> = T | Promise<T>;
|
||||
|
||||
export function defineAction<TOutput, TInputSchema extends z.ZodType>({
|
||||
input: inputSchema,
|
||||
handler,
|
||||
enhance,
|
||||
}: {
|
||||
input?: TInputSchema;
|
||||
handler: (input: z.infer<TInputSchema>, context: APIContext) => MaybePromise<TOutput>;
|
||||
enhance?: boolean;
|
||||
}): (input: z.input<TInputSchema>) => Promise<Awaited<TOutput>> {
|
||||
return async (unparsedInput): Promise<Awaited<TOutput>> => {
|
||||
const context = ApiContextStorage.getStore()!;
|
||||
const ContentType = context.request.headers.get('content-type');
|
||||
if (!enhance && (ContentType !== 'application/json' || unparsedInput instanceof FormData)) {
|
||||
// TODO: prettify dev server error
|
||||
throw new Response(
|
||||
'This action only accepts JSON. To enhance this action to accept form data, add `enhance: true` to your `defineAction()` config.',
|
||||
{
|
||||
status: 400,
|
||||
headers: {
|
||||
'Content-Type': 'text/plain',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (!inputSchema) return await handler(unparsedInput, context);
|
||||
|
||||
if (enhance && unparsedInput instanceof FormData) {
|
||||
if (!(inputSchema instanceof z.ZodObject)) {
|
||||
throw new Response(
|
||||
'`input` must use a Zod object schema (z.object) when `enhance` is enabled.',
|
||||
{
|
||||
status: 400,
|
||||
headers: {
|
||||
'Content-Type': 'text/plain',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
unparsedInput = enhanceFormData(unparsedInput, inputSchema);
|
||||
}
|
||||
|
||||
const parsed = inputSchema.safeParse(unparsedInput);
|
||||
if (!parsed.success) {
|
||||
throw new Response(JSON.stringify(parsed.error), {
|
||||
status: 400,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
}
|
||||
return await handler(parsed.data, context);
|
||||
};
|
||||
}
|
||||
|
||||
function enhanceFormData<T extends z.AnyZodObject>(
|
||||
formData: FormData,
|
||||
schema: T
|
||||
): Record<string, unknown> {
|
||||
const obj: Record<string, unknown> = {};
|
||||
for (const [key, validator] of Object.entries(schema.shape)) {
|
||||
// TODO: refine, unit test
|
||||
if (validator instanceof z.ZodBoolean) {
|
||||
obj[key] = formData.has(key);
|
||||
} else if (validator instanceof z.ZodArray) {
|
||||
obj[key] = Array.from(formData.getAll(key));
|
||||
} else if (validator instanceof z.ZodNumber) {
|
||||
obj[key] = Number(formData.get(key));
|
||||
} else {
|
||||
obj[key] = formData.get(key);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
2
packages/actions/src/runtime/env.d.ts
vendored
Normal file
2
packages/actions/src/runtime/env.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// <reference types="astro/client" />
|
||||
/// <reference path="../../virtual.d.ts" />
|
30
packages/actions/src/runtime/middleware.ts
Normal file
30
packages/actions/src/runtime/middleware.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { defineMiddleware } from 'astro:middleware';
|
||||
import { ApiContextStorage, formContentTypes, getAction } from './utils.js';
|
||||
|
||||
export const onRequest = defineMiddleware(async (context, next) => {
|
||||
context.locals.getActionResult = (action) => undefined;
|
||||
|
||||
const { request } = context;
|
||||
const contentType = request.headers.get('Content-Type');
|
||||
if (!formContentTypes.some((f) => contentType?.startsWith(f))) return next();
|
||||
|
||||
const formData = await request.clone().formData();
|
||||
const actionPath = formData.get('_astroAction');
|
||||
if (typeof actionPath !== 'string') return next();
|
||||
|
||||
const actionPathKeys = actionPath.replace('/_actions/', '').split('.');
|
||||
const action = await getAction(actionPathKeys);
|
||||
let result: any;
|
||||
try {
|
||||
result = await ApiContextStorage.run(context, () => action(formData));
|
||||
} catch (e) {
|
||||
if (e instanceof Response) {
|
||||
return e;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
context.locals.getActionResult = (action) => {
|
||||
if (action.toString() === actionPath) return result;
|
||||
};
|
||||
return next();
|
||||
});
|
33
packages/actions/src/runtime/route.ts
Normal file
33
packages/actions/src/runtime/route.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import type { APIRoute } from 'astro';
|
||||
import { ApiContextStorage, formContentTypes, getAction } from './utils.js';
|
||||
|
||||
export const POST: APIRoute = async (context) => {
|
||||
const { request, url, redirect } = context;
|
||||
if (request.method !== 'POST') {
|
||||
return new Response(null, { status: 405 });
|
||||
}
|
||||
const actionPathKeys = url.pathname.replace('/_actions/', '').split('.');
|
||||
const action = await getAction(actionPathKeys);
|
||||
const contentType = request.headers.get('Content-Type');
|
||||
let args: any;
|
||||
if (contentType === 'application/json') {
|
||||
args = await request.clone().json();
|
||||
}
|
||||
if (formContentTypes.some((f) => contentType?.startsWith(f))) {
|
||||
args = await request.clone().formData();
|
||||
}
|
||||
let result: unknown;
|
||||
try {
|
||||
result = await ApiContextStorage.run(context, () => action(args));
|
||||
} catch (e) {
|
||||
if (e instanceof Response) {
|
||||
return e;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return new Response(JSON.stringify(result), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
};
|
20
packages/actions/src/runtime/utils.ts
Normal file
20
packages/actions/src/runtime/utils.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import type { APIContext } from 'astro';
|
||||
import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
|
||||
export const ApiContextStorage = new AsyncLocalStorage<APIContext>();
|
||||
|
||||
export const formContentTypes = ['application/x-www-form-urlencoded', 'multipart/form-data'];
|
||||
|
||||
export async function getAction(pathKeys: string[]): Promise<Function> {
|
||||
let { default: actionLookup } = await import(import.meta.env.ACTIONS_PATH);
|
||||
for (const key of pathKeys) {
|
||||
if (!(key in actionLookup)) {
|
||||
throw new Error('Action not found');
|
||||
}
|
||||
actionLookup = actionLookup[key];
|
||||
}
|
||||
if (typeof actionLookup !== 'function') {
|
||||
throw new Error('Action not found');
|
||||
}
|
||||
return actionLookup;
|
||||
}
|
34
packages/actions/src/virtual.ts
Normal file
34
packages/actions/src/virtual.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
function toActionProxy(
|
||||
actionCallback = {},
|
||||
aggregatedPath = '/_actions/'
|
||||
): Record<string | symbol, any> {
|
||||
return new Proxy(actionCallback, {
|
||||
get(target: Record<string | symbol, any>, objKey) {
|
||||
const path = aggregatedPath + objKey.toString();
|
||||
if (objKey in target) {
|
||||
return target[objKey];
|
||||
}
|
||||
async function action(param?: BodyInit) {
|
||||
const headers = new Headers();
|
||||
headers.set('Accept', 'application/json');
|
||||
let body = param;
|
||||
if (!(body instanceof FormData)) {
|
||||
body = JSON.stringify(param);
|
||||
headers.set('Content-Type', 'application/json');
|
||||
}
|
||||
const res = await fetch(path, {
|
||||
method: 'POST',
|
||||
body,
|
||||
headers,
|
||||
});
|
||||
return res.json();
|
||||
}
|
||||
action.toString = () => path;
|
||||
// recurse to construct queries for nested object paths
|
||||
// ex. actions.user.admins.auth()
|
||||
return toActionProxy(action, path + '.');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const actions = toActionProxy();
|
7
packages/actions/tsconfig.json
Normal file
7
packages/actions/tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
}
|
||||
}
|
7
packages/actions/virtual.d.ts
vendored
Normal file
7
packages/actions/virtual.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
declare namespace App {
|
||||
interface Locals {
|
||||
getActionResult: <T extends (...args: any) => any>(
|
||||
action: T
|
||||
) => Awaited<ReturnType<T>> | undefined;
|
||||
}
|
||||
}
|
145
pnpm-lock.yaml
145
pnpm-lock.yaml
|
@ -501,6 +501,70 @@ importers:
|
|||
specifier: ^1.5.0
|
||||
version: 1.5.0(@types/node@18.19.31)
|
||||
|
||||
packages/actions:
|
||||
dependencies:
|
||||
astro-integration-kit:
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0(astro@packages+astro)
|
||||
zod:
|
||||
specifier: ^3.23.0
|
||||
version: 3.23.0
|
||||
devDependencies:
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../astro
|
||||
astro-scripts:
|
||||
specifier: workspace:*
|
||||
version: link:../../scripts
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
|
||||
packages/actions/test/fixtures/basics:
|
||||
dependencies:
|
||||
'@astrojs/actions':
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
'@astrojs/check':
|
||||
specifier: ^0.5.10
|
||||
version: 0.5.10(prettier-plugin-astro@0.13.0)(prettier@3.2.5)(typescript@5.4.5)
|
||||
'@astrojs/db':
|
||||
specifier: ^0.10.5
|
||||
version: link:../../../../db
|
||||
'@astrojs/mdx':
|
||||
specifier: ^2.3.1
|
||||
version: link:../../../../integrations/mdx
|
||||
'@astrojs/node':
|
||||
specifier: ^8.2.5
|
||||
version: link:../../../../integrations/node
|
||||
'@astrojs/react':
|
||||
specifier: ^3.3.0
|
||||
version: link:../../../../integrations/react
|
||||
'@astrojs/rss':
|
||||
specifier: ^4.0.5
|
||||
version: link:../../../../astro-rss
|
||||
'@astrojs/sitemap':
|
||||
specifier: ^3.1.4
|
||||
version: link:../../../../integrations/sitemap
|
||||
'@types/react':
|
||||
specifier: ^18.2.79
|
||||
version: 18.2.79
|
||||
'@types/react-dom':
|
||||
specifier: ^18.2.25
|
||||
version: 18.2.25
|
||||
astro:
|
||||
specifier: ^4.6.3
|
||||
version: link:../../../../astro
|
||||
react:
|
||||
specifier: 18.3.0-canary-670811593-20240322
|
||||
version: 18.3.0-canary-670811593-20240322
|
||||
react-dom:
|
||||
specifier: 18.3.0-canary-670811593-20240322
|
||||
version: 18.3.0-canary-670811593-20240322(react@18.3.0-canary-670811593-20240322)
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
|
||||
packages/astro:
|
||||
dependencies:
|
||||
'@astrojs/compiler':
|
||||
|
@ -8071,13 +8135,14 @@ packages:
|
|||
/@types/react-dom@18.2.25:
|
||||
resolution: {integrity: sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==}
|
||||
dependencies:
|
||||
'@types/react': 18.2.78
|
||||
'@types/react': 18.2.79
|
||||
|
||||
/@types/react@18.2.78:
|
||||
resolution: {integrity: sha512-qOwdPnnitQY4xKlKayt42q5W5UQrSHjgoXNVEtxeqdITJ99k4VXJOP3vt8Rkm9HmgJpH50UNU+rlqfkfWOqp0A==}
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.12
|
||||
csstype: 3.1.3
|
||||
dev: false
|
||||
|
||||
/@types/react@18.2.79:
|
||||
resolution: {integrity: sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==}
|
||||
|
@ -8963,6 +9028,13 @@ packages:
|
|||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/ast-types@0.16.1:
|
||||
resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/astring@1.8.6:
|
||||
resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==}
|
||||
hasBin: true
|
||||
|
@ -8991,6 +9063,41 @@ packages:
|
|||
astro: link:packages/astro
|
||||
dev: false
|
||||
|
||||
/astro-integration-kit@0.11.0(astro@packages+astro):
|
||||
resolution: {integrity: sha512-P41igJUY63W6iWq6Rtw0FnERVUdJhkpAa9jothRQ+AXl56B/6PMes/jcYPo3Zr6KwlMPT8TOHMoasHL0CfqglQ==}
|
||||
peerDependencies:
|
||||
'@astrojs/db': ^0.9.0
|
||||
'@vitejs/plugin-react': ^4.2.1
|
||||
astro: '*'
|
||||
preact: ^10.19.4
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
solid-js: ^1.8.15
|
||||
svelte: ^4.2.11
|
||||
vue: ^3.4.19
|
||||
peerDependenciesMeta:
|
||||
'@astrojs/db':
|
||||
optional: true
|
||||
'@vitejs/plugin-react':
|
||||
optional: true
|
||||
preact:
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
solid-js:
|
||||
optional: true
|
||||
svelte:
|
||||
optional: true
|
||||
vue:
|
||||
optional: true
|
||||
dependencies:
|
||||
astro: link:packages/astro
|
||||
pathe: 1.1.2
|
||||
recast: 0.23.6
|
||||
dev: false
|
||||
|
||||
/astro-remote@0.2.4:
|
||||
resolution: {integrity: sha512-iMFOuEVaLPWixNhx4acQc7h9ODMsLElb8itVpyREC/xPsUVf+124Nt80LIdFGV93lmYhIiFu2yf87cdsOxoubg==}
|
||||
dependencies:
|
||||
|
@ -14461,6 +14568,18 @@ packages:
|
|||
react: 18.2.0
|
||||
scheduler: 0.23.0
|
||||
|
||||
/react-dom@18.3.0-canary-670811593-20240322(react@18.3.0-canary-670811593-20240322):
|
||||
resolution: {integrity: sha512-AHxCnyDzZueXIHY4WA2Uba1yaL7/vbjhO3D3TWPQeruKD5MwgD0/xExZi0T104gBr6Thv6MEsLSxFjBAHhHKKg==}
|
||||
peerDependencies:
|
||||
react: 18.3.0-canary-670811593-20240322
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
dependencies:
|
||||
react: 18.3.0-canary-670811593-20240322
|
||||
scheduler: 0.24.0-canary-670811593-20240322
|
||||
dev: false
|
||||
|
||||
/react-is@18.2.0:
|
||||
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||
dev: false
|
||||
|
@ -14476,6 +14595,11 @@ packages:
|
|||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
/react@18.3.0-canary-670811593-20240322:
|
||||
resolution: {integrity: sha512-EI6+q3tOT+0z4OkB2sz842Ra/n/yz7b3jOJhSK1HQwi4Ng29VJzLGngWmSuxQ94YfdE3EBhpUKDfgNgzoKM9Vg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/read-cache@1.0.0:
|
||||
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
|
||||
dependencies:
|
||||
|
@ -14528,6 +14652,17 @@ packages:
|
|||
/reading-time@1.5.0:
|
||||
resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==}
|
||||
|
||||
/recast@0.23.6:
|
||||
resolution: {integrity: sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==}
|
||||
engines: {node: '>= 4'}
|
||||
dependencies:
|
||||
ast-types: 0.16.1
|
||||
esprima: 4.0.1
|
||||
source-map: 0.6.1
|
||||
tiny-invariant: 1.3.3
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/redent@3.0.0:
|
||||
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -14969,6 +15104,10 @@ packages:
|
|||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
/scheduler@0.24.0-canary-670811593-20240322:
|
||||
resolution: {integrity: sha512-IGX6Fq969h1L0X7jV0sJ/EdI4fr+mRetbBNJl55nn+/RsCuQSVwgKnZG6Q3NByixDNbkRI8nRmWuhOm8NQowGQ==}
|
||||
dev: false
|
||||
|
||||
/scslre@0.3.0:
|
||||
resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
|
||||
engines: {node: ^14.0.0 || >=16.0.0}
|
||||
|
@ -15812,6 +15951,10 @@ packages:
|
|||
globrex: 0.1.2
|
||||
dev: true
|
||||
|
||||
/tiny-invariant@1.3.3:
|
||||
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
|
||||
dev: false
|
||||
|
||||
/tinybench@2.7.0:
|
||||
resolution: {integrity: sha512-Qgayeb106x2o4hNzNjsZEfFziw8IbKqtbXBjVh7VIZfBxfD5M4gWtpyx5+YTae2gJ6Y6Dz/KLepiv16RFeQWNA==}
|
||||
dev: false
|
||||
|
|
Loading…
Reference in a new issue