mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-07-28 00:15:01 +00:00
Core: Add orama-cloud-legacy search integration for old Orama Cloud users
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"fumadocs-core": patch
|
||||
---
|
||||
|
||||
Add `orama-cloud-legacy` search integration for old Orama Cloud users
|
||||
@@ -143,6 +143,7 @@
|
||||
"@mdx-js/mdx": "^3.1.1",
|
||||
"@mixedbread/sdk": "^0.46.0",
|
||||
"@orama/core": "^1.2.16",
|
||||
"@oramacloud/client": "^2.1.4",
|
||||
"@tanstack/react-router": "1.144.0",
|
||||
"@types/estree-jsx": "^1.0.5",
|
||||
"@types/hast": "^3.0.4",
|
||||
@@ -172,6 +173,7 @@
|
||||
"peerDependencies": {
|
||||
"@mixedbread/sdk": "^0.46.0",
|
||||
"@orama/core": "1.x.x",
|
||||
"@oramacloud/client": "2.x.x",
|
||||
"@tanstack/react-router": "1.x.x",
|
||||
"@types/react": "*",
|
||||
"algoliasearch": "5.x.x",
|
||||
@@ -193,6 +195,9 @@
|
||||
"@orama/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@oramacloud/client": {
|
||||
"optional": true
|
||||
},
|
||||
"algoliasearch": {
|
||||
"optional": true
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useOnChange } from '@/utils/use-on-change';
|
||||
import { type StaticOptions } from '@/search/client/static';
|
||||
import { type AlgoliaOptions } from '@/search/client/algolia';
|
||||
import { type OramaCloudOptions } from '@/search/client/orama-cloud';
|
||||
import { type OramaCloudLegacyOptions } from '@/search/client/orama-cloud-legacy';
|
||||
import { type MixedbreadOptions } from '@/search/client/mixedbread';
|
||||
import type { SortedResult } from '@/search';
|
||||
|
||||
@@ -31,6 +32,9 @@ export type Client =
|
||||
| ({
|
||||
type: 'orama-cloud';
|
||||
} & OramaCloudOptions)
|
||||
| ({
|
||||
type: 'orama-cloud-legacy';
|
||||
} & OramaCloudLegacyOptions)
|
||||
| ({
|
||||
type: 'mixedbread';
|
||||
} & MixedbreadOptions);
|
||||
@@ -106,33 +110,34 @@ export function useDocsSearch(
|
||||
|
||||
async function run(): Promise<SortedResult[] | 'empty'> {
|
||||
if (debouncedValue.length === 0 && !allowEmpty) return 'empty';
|
||||
|
||||
if (client.type === 'fetch') {
|
||||
const { fetchDocs } = await import('./client/fetch');
|
||||
return fetchDocs(debouncedValue, client);
|
||||
switch (client.type) {
|
||||
case 'fetch': {
|
||||
const { fetchDocs } = await import('./client/fetch');
|
||||
return fetchDocs(debouncedValue, client);
|
||||
}
|
||||
case 'algolia': {
|
||||
const { searchDocs } = await import('./client/algolia');
|
||||
return searchDocs(debouncedValue, client);
|
||||
}
|
||||
case 'orama-cloud': {
|
||||
const { searchDocs } = await import('./client/orama-cloud');
|
||||
return searchDocs(debouncedValue, client);
|
||||
}
|
||||
case 'orama-cloud-legacy': {
|
||||
const { searchDocs } = await import('./client/orama-cloud-legacy');
|
||||
return searchDocs(debouncedValue, client);
|
||||
}
|
||||
case 'mixedbread': {
|
||||
const { search } = await import('./client/mixedbread');
|
||||
return search(debouncedValue, client);
|
||||
}
|
||||
case 'static': {
|
||||
const { search } = await import('./client/static');
|
||||
return search(debouncedValue, client);
|
||||
}
|
||||
default:
|
||||
throw new Error('unknown search client');
|
||||
}
|
||||
|
||||
if (client.type === 'algolia') {
|
||||
const { searchDocs } = await import('./client/algolia');
|
||||
return searchDocs(debouncedValue, client);
|
||||
}
|
||||
|
||||
if (client.type === 'orama-cloud') {
|
||||
const { searchDocs } = await import('./client/orama-cloud');
|
||||
return searchDocs(debouncedValue, client);
|
||||
}
|
||||
|
||||
if (client.type === 'static') {
|
||||
const { search } = await import('./client/static');
|
||||
return search(debouncedValue, client);
|
||||
}
|
||||
|
||||
if (client.type === 'mixedbread') {
|
||||
const { search } = await import('./client/mixedbread');
|
||||
return search(debouncedValue, client);
|
||||
}
|
||||
|
||||
throw new Error('unknown search client');
|
||||
}
|
||||
|
||||
void run()
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import type { ClientSearchParams, OramaClient } from '@oramacloud/client';
|
||||
import { removeUndefined } from '@/utils/remove-undefined';
|
||||
import type { OramaIndex } from '@/search/orama-cloud-legacy';
|
||||
import { createContentHighlighter, type SortedResult } from '@/search';
|
||||
|
||||
interface CrawlerIndex {
|
||||
path: string;
|
||||
title: string;
|
||||
content: string;
|
||||
section: string;
|
||||
category: string;
|
||||
}
|
||||
|
||||
export interface OramaCloudLegacyOptions {
|
||||
client: OramaClient;
|
||||
/**
|
||||
* The type of your index.
|
||||
*
|
||||
* You can set it to `crawler` if you use crawler instead of the JSON index with schema provided by Fumadocs
|
||||
*/
|
||||
index?: 'default' | 'crawler';
|
||||
params?: ClientSearchParams;
|
||||
|
||||
/**
|
||||
* Filter results with specific tag.
|
||||
*/
|
||||
tag?: string;
|
||||
|
||||
/**
|
||||
* Filter by locale (unsupported at the moment)
|
||||
*/
|
||||
locale?: string;
|
||||
}
|
||||
|
||||
export async function searchDocs(
|
||||
query: string,
|
||||
options: OramaCloudLegacyOptions,
|
||||
): Promise<SortedResult[]> {
|
||||
const highlighter = createContentHighlighter(query);
|
||||
const list: SortedResult[] = [];
|
||||
const { index = 'default', client, params: extraParams = {}, tag } = options;
|
||||
|
||||
if (index === 'crawler') {
|
||||
const result = await client.search({
|
||||
...extraParams,
|
||||
term: query,
|
||||
where: {
|
||||
category: tag
|
||||
? {
|
||||
eq: tag.slice(0, 1).toUpperCase() + tag.slice(1),
|
||||
}
|
||||
: undefined,
|
||||
...extraParams.where,
|
||||
},
|
||||
limit: 10,
|
||||
});
|
||||
if (!result) return list;
|
||||
|
||||
for (const hit of result.hits) {
|
||||
const doc = hit.document as unknown as CrawlerIndex;
|
||||
|
||||
list.push(
|
||||
{
|
||||
id: hit.id,
|
||||
type: 'page',
|
||||
content: doc.title,
|
||||
contentWithHighlights: highlighter.highlight(doc.title),
|
||||
url: doc.path,
|
||||
},
|
||||
{
|
||||
id: 'page' + hit.id,
|
||||
type: 'text',
|
||||
content: doc.content,
|
||||
contentWithHighlights: highlighter.highlight(doc.content),
|
||||
url: doc.path,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
const params: ClientSearchParams = {
|
||||
...extraParams,
|
||||
term: query,
|
||||
where: removeUndefined({
|
||||
tag,
|
||||
...extraParams.where,
|
||||
}),
|
||||
groupBy: {
|
||||
properties: ['page_id'],
|
||||
maxResult: 7,
|
||||
...extraParams.groupBy,
|
||||
},
|
||||
};
|
||||
|
||||
const result = await client.search(params);
|
||||
if (!result || !result.groups) return list;
|
||||
|
||||
for (const item of result.groups) {
|
||||
let addedHead = false;
|
||||
|
||||
for (const hit of item.result) {
|
||||
const doc = hit.document as unknown as OramaIndex;
|
||||
|
||||
if (!addedHead) {
|
||||
list.push({
|
||||
id: doc.page_id,
|
||||
type: 'page',
|
||||
content: doc.title,
|
||||
breadcrumbs: doc.breadcrumbs,
|
||||
contentWithHighlights: highlighter.highlight(doc.title),
|
||||
url: doc.url,
|
||||
});
|
||||
addedHead = true;
|
||||
}
|
||||
|
||||
list.push({
|
||||
id: doc.id,
|
||||
content: doc.content,
|
||||
contentWithHighlights: highlighter.highlight(doc.content),
|
||||
type: doc.content === doc.section ? 'heading' : 'text',
|
||||
url: doc.section_id ? `${doc.url}#${doc.section_id}` : doc.url,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
import type { CloudManager } from '@oramacloud/client';
|
||||
import type { StructuredData } from '@/mdx-plugins';
|
||||
|
||||
export interface SyncOptions {
|
||||
/**
|
||||
* Index name to sync
|
||||
*/
|
||||
index: string;
|
||||
|
||||
documents: OramaDocument[];
|
||||
|
||||
/**
|
||||
* Deploy changes
|
||||
*
|
||||
* @defaultValue true
|
||||
*/
|
||||
autoDeploy?: boolean;
|
||||
}
|
||||
|
||||
export interface I18nSyncOptions extends Omit<SyncOptions, 'index' | 'documents'> {
|
||||
/**
|
||||
* Indexes to sync.
|
||||
*
|
||||
* Pairs of `locale`-`index`.
|
||||
**/
|
||||
indexes: Record<string, string>;
|
||||
|
||||
documents: {
|
||||
locale: string;
|
||||
items: OramaDocument[];
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface OramaDocument {
|
||||
/**
|
||||
* The ID of document, must be unique
|
||||
*/
|
||||
id: string;
|
||||
|
||||
title: string;
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* URL to the page
|
||||
*/
|
||||
url: string;
|
||||
structured: StructuredData;
|
||||
|
||||
/**
|
||||
* Tag to filter results
|
||||
*/
|
||||
tag?: string;
|
||||
|
||||
/**
|
||||
* Data to be added to each section index
|
||||
*/
|
||||
extra_data?: object;
|
||||
breadcrumbs?: string[];
|
||||
}
|
||||
|
||||
export interface OramaIndex {
|
||||
id: string;
|
||||
|
||||
title: string;
|
||||
url: string;
|
||||
|
||||
tag?: string;
|
||||
|
||||
/**
|
||||
* The id of page, used for `group by`
|
||||
*/
|
||||
page_id: string;
|
||||
|
||||
/**
|
||||
* Heading content
|
||||
*/
|
||||
section?: string;
|
||||
|
||||
breadcrumbs?: string[];
|
||||
|
||||
/**
|
||||
* Heading (anchor) id
|
||||
*/
|
||||
section_id?: string;
|
||||
|
||||
content: string;
|
||||
}
|
||||
|
||||
export async function sync(cloudManager: CloudManager, options: SyncOptions): Promise<void> {
|
||||
const { autoDeploy = true } = options;
|
||||
const index = cloudManager.index(options.index);
|
||||
|
||||
await index.snapshot(options.documents.flatMap(toIndex));
|
||||
if (autoDeploy) await index.deploy();
|
||||
}
|
||||
|
||||
export async function syncI18n(
|
||||
cloudManager: CloudManager,
|
||||
options: I18nSyncOptions,
|
||||
): Promise<void> {
|
||||
const { autoDeploy = true } = options;
|
||||
|
||||
const tasks = options.documents.map(async (document) => {
|
||||
const index = cloudManager.index(options.indexes[document.locale]);
|
||||
|
||||
await index.snapshot(document.items.flatMap(toIndex));
|
||||
if (autoDeploy) await index.deploy();
|
||||
});
|
||||
|
||||
await Promise.all(tasks);
|
||||
}
|
||||
|
||||
function toIndex(page: OramaDocument): OramaIndex[] {
|
||||
let id = 0;
|
||||
const indexes: OramaIndex[] = [];
|
||||
const scannedHeadings = new Set<string>();
|
||||
|
||||
function createIndex(
|
||||
section: string | undefined,
|
||||
sectionId: string | undefined,
|
||||
content: string,
|
||||
): OramaIndex {
|
||||
return {
|
||||
id: `${page.id}-${(id++).toString()}`,
|
||||
title: page.title,
|
||||
url: page.url,
|
||||
page_id: page.id,
|
||||
tag: page.tag,
|
||||
section,
|
||||
section_id: sectionId,
|
||||
content,
|
||||
breadcrumbs: page.breadcrumbs,
|
||||
...page.extra_data,
|
||||
};
|
||||
}
|
||||
|
||||
if (page.description) indexes.push(createIndex(undefined, undefined, page.description));
|
||||
|
||||
page.structured.contents.forEach((p) => {
|
||||
const heading = p.heading ? page.structured.headings.find((h) => p.heading === h.id) : null;
|
||||
|
||||
const index = createIndex(heading?.content, heading?.id, p.content);
|
||||
|
||||
if (heading && !scannedHeadings.has(heading.id)) {
|
||||
scannedHeadings.add(heading.id);
|
||||
|
||||
indexes.push(createIndex(heading.content, heading.id, heading.content));
|
||||
}
|
||||
|
||||
indexes.push(index);
|
||||
});
|
||||
|
||||
return indexes;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export interface SyncOptions {
|
||||
autoDeploy?: boolean;
|
||||
}
|
||||
|
||||
export type I18nSyncOptions = Omit<SyncOptions, 'index' | 'documents'> & {
|
||||
export interface I18nSyncOptions extends Omit<SyncOptions, 'index' | 'documents'> {
|
||||
/**
|
||||
* Indexes to sync.
|
||||
*
|
||||
@@ -29,7 +29,7 @@ export type I18nSyncOptions = Omit<SyncOptions, 'index' | 'documents'> & {
|
||||
locale: string;
|
||||
items: OramaDocument[];
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface OramaDocument {
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ export default defineConfig({
|
||||
'src/source/{index,schema}.ts',
|
||||
'src/source/client/*.{ts,tsx}',
|
||||
'src/source/plugins/{lucide-icons,slugs}.ts',
|
||||
'src/search/{index,client,server,algolia,orama-cloud}.ts',
|
||||
'src/search/{index,client,server,algolia,orama-cloud,orama-cloud-legacy}.ts',
|
||||
'src/utils/use-on-change.ts',
|
||||
'src/utils/use-effect-event.ts',
|
||||
'src/utils/use-media-query.ts',
|
||||
|
||||
Generated
+18
-5
@@ -945,7 +945,7 @@ importers:
|
||||
version: 19.2.3(@types/react@19.2.7)
|
||||
'@vitejs/plugin-rsc':
|
||||
specifier: ^0.5.7
|
||||
version: 0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
version: 0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
react-router-devtools:
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react-router@7.11.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
@@ -1593,6 +1593,9 @@ importers:
|
||||
'@orama/core':
|
||||
specifier: ^1.2.16
|
||||
version: 1.2.16
|
||||
'@oramacloud/client':
|
||||
specifier: ^2.1.4
|
||||
version: 2.1.4
|
||||
'@tanstack/react-router':
|
||||
specifier: 1.144.0
|
||||
version: 1.144.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||
@@ -2161,7 +2164,7 @@ importers:
|
||||
version: 5.1.2(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
'@vitejs/plugin-rsc':
|
||||
specifier: ^0.5.7
|
||||
version: 0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
version: 0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
commander:
|
||||
specifier: ^14.0.2
|
||||
version: 14.0.2
|
||||
@@ -4032,6 +4035,9 @@ packages:
|
||||
resolution: {integrity: sha512-Ra4dFddWZ7hCGPAehnd/6QZjlzQvczYSt1y1Fq4HteJqRu2yvfR6fXvxiUnKi+HIgJYPxKhebJEjvJdF8LYQWg==}
|
||||
engines: {node: '>= 20.0.0'}
|
||||
|
||||
'@oramacloud/client@2.1.4':
|
||||
resolution: {integrity: sha512-uNPFs4wq/iOPbggCwTkVNbIr64Vfd7ZS/h+cricXVnzXWocjDTfJ3wLL4lr0qiSu41g8z+eCAGBqJ30RO2O4AA==}
|
||||
|
||||
'@oslojs/encoding@1.1.0':
|
||||
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
|
||||
|
||||
@@ -6535,6 +6541,7 @@ packages:
|
||||
|
||||
bun@1.3.5:
|
||||
resolution: {integrity: sha512-c1YHIGUfgvYPJmLug5QiLzNWlX2Dg7X/67JWu1Va+AmMXNXzC/KQn2lgQ7rD+n1u1UqDpJMowVGGxTNpbPydNw==}
|
||||
cpu: [arm64, x64]
|
||||
os: [darwin, linux, win32]
|
||||
hasBin: true
|
||||
|
||||
@@ -13051,6 +13058,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@orama/orama': 3.1.18
|
||||
|
||||
'@oramacloud/client@2.1.4':
|
||||
dependencies:
|
||||
'@orama/cuid2': 2.2.3
|
||||
'@orama/orama': 3.1.18
|
||||
lodash: 4.17.21
|
||||
|
||||
'@oslojs/encoding@1.1.0': {}
|
||||
|
||||
'@oven/bun-darwin-aarch64@1.3.5':
|
||||
@@ -13769,7 +13782,7 @@ snapshots:
|
||||
vite-node: 3.2.4(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
|
||||
optionalDependencies:
|
||||
'@react-router/serve': 7.11.0(react-router@7.11.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
|
||||
'@vitejs/plugin-rsc': 0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
'@vitejs/plugin-rsc': 0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
react-server-dom-webpack: 19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
@@ -15226,7 +15239,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-rsc@0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
|
||||
'@vitejs/plugin-rsc@0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
|
||||
dependencies:
|
||||
es-module-lexer: 2.0.0
|
||||
estree-walker: 3.0.3
|
||||
@@ -21283,7 +21296,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@hono/node-server': 1.19.7(hono@4.11.3)
|
||||
'@vitejs/plugin-react': 5.1.2(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
'@vitejs/plugin-rsc': 0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
'@vitejs/plugin-rsc': 0.5.9(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.0(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
dotenv: 17.2.3
|
||||
hono: 4.11.3
|
||||
magic-string: 0.30.21
|
||||
|
||||
Reference in New Issue
Block a user