refactor(stage-web,stage-ui): replace warpdrive plugin with unplugin-basemove (#1818)
This commit is contained in:
@@ -56,7 +56,7 @@ Use `To developers` for external developer impact:
|
||||
|
||||
Use `To contributors` for internal project work:
|
||||
|
||||
- `vishot`, `vite-plugin-warpdrive`, `cap-vite`, CI, dev scripts, repo build/test/lint workflow, docs generation, internal-only packages, release automation, test harnesses, screenshots, evaluation tools.
|
||||
- `vishot`, `cap-vite`, CI, dev scripts, repo build/test/lint workflow, docs generation, internal-only packages, release automation, test harnesses, screenshots, evaluation tools.
|
||||
- Include relevant `chore` commits even when changelogithub does not surface them prominently.
|
||||
|
||||
## End-User Writing
|
||||
|
||||
@@ -34,7 +34,6 @@ Concise but detailed reference for contributors working across the `moeru-ai/air
|
||||
- **IPC/Eventa**: Always use `@moeru/eventa` for type-safe, framework/runtime-agnostic IPC/RPC. Define contracts centrally (e.g., `apps/stage-tamagotchi/src/shared`) and follow usage patterns in `apps/stage-tamagotchi/src/main/services/electron` for main/renderer integration.
|
||||
- **Dependency Injection**: Use `injeca` for services/electron modules/plugins/frontend; see `apps/stage-tamagotchi/src/main/index.ts` for composition patterns.
|
||||
- **Build/CI/Lint**: `.github/workflows` for pipelines; `eslint.config.js` for lint rules.
|
||||
- **Bundling libs**: Use `tsdown` for new modules (see `packages/vite-plugin-warpdrive`).
|
||||
- **Styles**: UnoCSS config at `uno.config.ts`; check `apps/stage-web/src/styles` for existing animations; prefer UnoCSS over Tailwind.
|
||||
|
||||
## Key Path Index (what lives where)
|
||||
@@ -60,7 +59,6 @@ Concise but detailed reference for contributors working across the `moeru-ai/air
|
||||
- Styles: `uno.config.ts` (UnoCSS), `apps/stage-web/src/styles` (animations/reference).
|
||||
- Build pipeline refs: `.github/workflows`; lint rules in `eslint.config.js`.
|
||||
- Tailwind/UnoCSS: prefer UnoCSS; if standardizing styles, add shortcuts/rules/plugins in `uno.config.ts`.
|
||||
- Bundling pattern: `packages/vite-plugin-warpdrive` (tsdown example).
|
||||
|
||||
## Commands (pnpm with filters)
|
||||
|
||||
|
||||
@@ -124,7 +124,6 @@
|
||||
"@proj-airi/lobe-icons": "^1.0.19",
|
||||
"@proj-airi/unplugin-fetch": "catalog:",
|
||||
"@proj-airi/unplugin-live2d-sdk": "^0.1.7",
|
||||
"@proj-airi/vite-plugin-warpdrive": "workspace:*",
|
||||
"@shikijs/markdown-it": "^4.0.2",
|
||||
"@types/audioworklet": "catalog:",
|
||||
"@types/culori": "^4.0.1",
|
||||
|
||||
@@ -120,7 +120,6 @@
|
||||
"@proj-airi/lobe-icons": "^1.0.19",
|
||||
"@proj-airi/unplugin-fetch": "catalog:",
|
||||
"@proj-airi/unplugin-live2d-sdk": "^0.1.7",
|
||||
"@proj-airi/vite-plugin-warpdrive": "workspace:*",
|
||||
"@shikijs/markdown-it": "^4.0.2",
|
||||
"@types/audioworklet": "catalog:",
|
||||
"@types/culori": "^4.0.1",
|
||||
@@ -136,6 +135,7 @@
|
||||
"csstype": "^3.2.3",
|
||||
"hfup": "^1.0.4",
|
||||
"less": "^4.6.4",
|
||||
"unplugin-basemove": "0.0.1",
|
||||
"unplugin-info": "^1.3.2",
|
||||
"unplugin-yaml": "^4.1.0",
|
||||
"vite": "catalog:",
|
||||
|
||||
@@ -7,6 +7,7 @@ import VueI18n from '@intlify/unplugin-vue-i18n/vite'
|
||||
import templateCompilerOptions from '@tresjs/core/template-compiler-options'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import Unocss from 'unocss/vite'
|
||||
import Basemove, { createS3Provider } from 'unplugin-basemove/vite'
|
||||
import Info from 'unplugin-info/vite'
|
||||
import Yaml from 'unplugin-yaml/vite'
|
||||
import Mkcert from 'vite-plugin-mkcert'
|
||||
@@ -18,7 +19,6 @@ import VueRouter from 'vue-router/vite'
|
||||
import { tryCatch } from '@moeru/std'
|
||||
import { Download } from '@proj-airi/unplugin-fetch/vite'
|
||||
import { DownloadLive2DSDK } from '@proj-airi/unplugin-live2d-sdk/vite'
|
||||
import { createS3Provider, WarpDrivePlugin } from '@proj-airi/vite-plugin-warpdrive'
|
||||
import { LFS, SpaceCard } from 'hfup/vite'
|
||||
import { defineConfig } from 'vite'
|
||||
import { VitePWA } from 'vite-plugin-pwa'
|
||||
@@ -275,7 +275,7 @@ export default defineConfig({
|
||||
...((!env.S3_ENDPOINT || !env.S3_ACCESS_KEY_ID || !env.S3_SECRET_ACCESS_KEY)
|
||||
? []
|
||||
: [
|
||||
WarpDrivePlugin({
|
||||
Basemove({
|
||||
prefix: env.STAGE_WEB_WARP_DRIVE_PREFIX || 'proj-airi/stage-web/main/',
|
||||
include: [/\.wasm$/i, /\.ttf$/i, /\.vrm$/i, /\.zip$/i], // in existing assets, wasm, ttf, vrm files are the largest ones
|
||||
manifest: true,
|
||||
|
||||
+1
-1
@@ -32,6 +32,7 @@ words:
|
||||
- baichuan
|
||||
- baiducloud
|
||||
- bailian
|
||||
- Basemove
|
||||
- bestmove
|
||||
- bigserial
|
||||
- bilibili
|
||||
@@ -345,7 +346,6 @@ words:
|
||||
- vueuse
|
||||
- waapi
|
||||
- Waifu
|
||||
- warpdrive
|
||||
- Warudo
|
||||
- wavefile
|
||||
- webgpu
|
||||
|
||||
@@ -182,7 +182,6 @@
|
||||
"@pinia/testing": "catalog:",
|
||||
"@proj-airi/lobe-icons": "^1.0.19",
|
||||
"@proj-airi/stream-kit": "workspace:*",
|
||||
"@proj-airi/vite-plugin-warpdrive": "workspace:*",
|
||||
"@types/audioworklet": "catalog:",
|
||||
"@types/culori": "^4.0.1",
|
||||
"@types/d3": "catalog:",
|
||||
@@ -197,6 +196,7 @@
|
||||
"histoire": "catalog:",
|
||||
"is-network-error": "catalog:",
|
||||
"unocss": "^66.6.8",
|
||||
"unplugin-basemove": "0.0.1",
|
||||
"unplugin-info": "catalog:",
|
||||
"unplugin-yaml": "^4.1.0",
|
||||
"vite": "^6.4.2",
|
||||
|
||||
@@ -5,10 +5,10 @@ import { env } from 'node:process'
|
||||
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import Unocss from 'unocss/vite'
|
||||
import Basemove, { createS3Provider } from 'unplugin-basemove/vite'
|
||||
import Yaml from 'unplugin-yaml/vite'
|
||||
import Inspect from 'vite-plugin-inspect'
|
||||
|
||||
import { createS3Provider, WarpDrivePlugin } from '@proj-airi/vite-plugin-warpdrive'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
// For Histoire
|
||||
@@ -61,7 +61,7 @@ export default defineConfig({
|
||||
...((!env.S3_ENDPOINT || !env.S3_ACCESS_KEY_ID || !env.S3_SECRET_ACCESS_KEY)
|
||||
? []
|
||||
: [
|
||||
WarpDrivePlugin({
|
||||
Basemove({
|
||||
prefix: env.STAGE_UI_WARP_DRIVE_PREFIX || 'proj-airi/stage-ui/main/',
|
||||
include: [/\.wasm$/i, /\.ttf$/i, /\.vrm$/i, /\.zip$/i], // in existing assets, wasm, ttf, vrm files are the largest ones
|
||||
manifest: true,
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
# @proj-airi/vite-plugin-warpdrive
|
||||
|
||||
Vite plugin that rewrites selected build assets (large WASM/TTF/VRM, etc.) to remote object storage and uploads them after build. It uses Vite's `renderBuiltUrl` hook so the generated bundles reference the remote URL while keeping the local file for upload.
|
||||
|
||||
## Why
|
||||
|
||||
- Keep HTML/JS bundles lean while serving heavy assets (WASM, fonts, models) from object storage/CDN.
|
||||
- Simple provider abstraction; ships with an S3-compatible implementation via [`s3mini`](https://github.com/good-lly/s3mini).
|
||||
- Emits an optional manifest (`remote-assets.manifest.json`) that maps built filenames to remote URLs plus hostId/hostType for debugging.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
pnpm add -D @proj-airi/vite-plugin-warpdrive
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { createS3Provider, WarpDrivePlugin } from '@proj-airi/vite-plugin-warpdrive'
|
||||
// vite.config.ts
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
WarpDrivePlugin({
|
||||
prefix: 'remote-assets', // path prefix in the bucket (default: remote-assets)
|
||||
include: [/\.wasm$/i, /\.ttf$/i, /\.vrm$/i], // which assets to rewrite/upload (required)
|
||||
// includeBy: (file, ctx) => ctx.hostId?.includes('duckdb'), // extra predicate with host info
|
||||
// contentTypeBy: (file) => file.endsWith('.wasm') ? 'application/wasm' : undefined,
|
||||
manifest: true, // emit remote-assets.manifest.json in dist
|
||||
delete: true, // delete local uploaded assets (default: true)
|
||||
clean: true, // clean remote prefix before upload (default: true if provider supports it)
|
||||
skipNotModified: true, // skip uploads if provider supports it (default: true)
|
||||
// dryRun: true, // rewrite URLs/manifest only; skip cleaning/uploading
|
||||
provider: createS3Provider({
|
||||
endpoint: process.env.S3_ENDPOINT!,
|
||||
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
|
||||
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
|
||||
region: process.env.S3_REGION,
|
||||
publicBaseUrl: process.env.WARP_DRIVE_PUBLIC_BASE, // defaults to endpoint
|
||||
}),
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
- `provider` (required): object implementing `UploadProvider` (see below).
|
||||
- `prefix`: string path prefix for uploaded keys and URLs (default: `remote-assets`; e.g. `remote-assets/assets/foo.wasm`).
|
||||
- `include`: array of regex or predicate functions to decide which assets to rewrite/upload (empty array means nothing is rewritten).
|
||||
- `includeBy`: optional `(filename, ctx) => boolean` for finer control (`ctx` has `hostId`, `hostType`).
|
||||
- `contentTypeBy`: optional `(filename) => string | Promise<string | undefined> | undefined` resolver passed to `provider.upload`.
|
||||
- `manifest`: when true, emits `remote-assets.manifest.json` describing fileName/key/url/hostId/hostType/size.
|
||||
- `delete`: when true (default), delete uploaded local assets from disk after upload.
|
||||
- `clean`: when true (default), call `provider.cleanPrefix(prefix)` before uploading; skipped if no prefix or provider lacks `cleanPrefix`.
|
||||
- `skipNotModified`: when true (default), skip uploads if `provider.shouldSkipUpload` returns true.
|
||||
- `dryRun`: when true, rewrite URLs/emit manifest without cleaning or uploading.
|
||||
|
||||
#### UploadProvider interface
|
||||
|
||||
```ts
|
||||
interface UploadProvider {
|
||||
getPublicUrl: (key: string) => string
|
||||
upload: (localPath: string, key: string, contentType?: string) => Promise<void>
|
||||
cleanPrefix?: (prefix: string) => Promise<void>
|
||||
shouldSkipUpload?: (localPath: string, key: string) => Promise<boolean>
|
||||
}
|
||||
```
|
||||
|
||||
### createS3Provider
|
||||
|
||||
Light wrapper around `s3mini`. Required fields:
|
||||
|
||||
- `endpoint`: full bucket URL (e.g. `https://s3.example.com/my-bucket`).
|
||||
- `accessKeyId`, `secretAccessKey`: credentials.
|
||||
- Optional: `region`, `requestSizeInBytes`, `requestAbortTimeout`, `publicBaseUrl` (override public URL base), `skipNotModified` (default: true; uses ETag/MD5 to skip uploads).
|
||||
|
||||
## How it works
|
||||
|
||||
1. `renderBuiltUrl` returns the remote URL for matching assets while remembering the key/hostId/hostType.
|
||||
2. `generateBundle` records assets to upload, emits the optional manifest, and leaves the local files in `dist/`.
|
||||
3. `closeBundle` optionally cleans the prefix, skips unmodified uploads when supported, uploads assets, and deletes local copies (unless `delete` is false).
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "@proj-airi/vite-plugin-warpdrive",
|
||||
"type": "module",
|
||||
"version": "0.10.2",
|
||||
"private": true,
|
||||
"description": "Vite plugin to rewrite and upload heavy build assets to remote object storage",
|
||||
"author": {
|
||||
"name": "Moeru AI Project AIRI Team",
|
||||
"email": "airi@moeru.ai",
|
||||
"url": "https://github.com/moeru-ai"
|
||||
},
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"default": "./dist/index.mjs"
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.mts",
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist",
|
||||
"package.json"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^5.0.0 || ^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"rolldown": "1.0.0-beta.51",
|
||||
"s3mini": "^0.9.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@moeru/std": "catalog:"
|
||||
}
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
import type { OutputAsset } from 'rollup'
|
||||
import type { Plugin, RenderBuiltAssetUrl, ResolvedConfig } from 'vite'
|
||||
|
||||
import type { UploadProvider } from './providers/types'
|
||||
|
||||
import { Buffer } from 'node:buffer'
|
||||
import { rm } from 'node:fs/promises'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { cwd } from 'node:process'
|
||||
|
||||
import { errorCauseFrom, errorMessageFrom, errorNameFrom, errorStackFrom } from '@moeru/std'
|
||||
|
||||
export { createS3Provider } from './providers/s3'
|
||||
export type { S3ProviderOptions } from './providers/s3'
|
||||
export type { UploadProvider } from './providers/types'
|
||||
|
||||
type IncludeMatcher = RegExp | ((filename: string) => boolean)
|
||||
|
||||
export interface WarpDrivePluginOptions {
|
||||
provider: UploadProvider
|
||||
/**
|
||||
* Prefix to prepend before the asset filename when uploading and when rewriting URLs.
|
||||
* e.g. `remote-assets` will produce `remote-assets/assets/duckdb-eh-123.wasm`.
|
||||
*/
|
||||
prefix?: string
|
||||
/**
|
||||
* Restrict which assets are rewritten/uploaded.
|
||||
*/
|
||||
include?: IncludeMatcher[]
|
||||
/**
|
||||
* Optional extra predicate that receives filename + host info to decide inclusion.
|
||||
*/
|
||||
includeBy?: (filename: string, ctx: { hostId?: string, hostType?: string }) => boolean
|
||||
/**
|
||||
* Optional content-type resolver. If omitted, uploads use the provider default.
|
||||
*/
|
||||
contentTypeBy?: (filename: string) => Promise<string | undefined> | string | undefined
|
||||
/**
|
||||
* Emit a manifest with module id + URL for debugging.
|
||||
*/
|
||||
manifest?: boolean
|
||||
/**
|
||||
* Delete the uploaded local asset from disk after upload completes. Enabled by default.
|
||||
*/
|
||||
delete?: boolean
|
||||
/**
|
||||
* Clean the remote prefix before uploading (delete existing objects). Enabled by default.
|
||||
*/
|
||||
clean?: boolean
|
||||
/**
|
||||
* When enabled, skip cleaning and uploading; emit manifest/rewrite URLs only.
|
||||
*/
|
||||
dryRun?: boolean
|
||||
/**
|
||||
* Skip uploading assets that are already present and not modified. Enabled by default when supported.
|
||||
*/
|
||||
skipNotModified?: boolean
|
||||
}
|
||||
|
||||
export function WarpDrivePlugin(options: WarpDrivePluginOptions): Plugin {
|
||||
const include = options.include ?? []
|
||||
const prefix = normalizePrefix(options.prefix ?? 'remote-assets')
|
||||
const pluginName = 'proj-airi-warpdrive'
|
||||
const shouldDeleteLocalAsset = options.delete !== false
|
||||
const shouldCleanRemote = options.clean !== false
|
||||
const shouldSkipNotModified = options.skipNotModified !== false
|
||||
const isDryRun = options.dryRun === true
|
||||
|
||||
const tracked = new Map<string, { key: string, url: string, hostId?: string, hostType?: string }>()
|
||||
const manifest: Array<{
|
||||
fileName: string
|
||||
url: string
|
||||
key: string
|
||||
hostId?: string
|
||||
hostType?: string
|
||||
size: number
|
||||
}> = []
|
||||
|
||||
let resolvedConfig: ResolvedConfig | undefined
|
||||
let cleanedRemote = false
|
||||
const pendingUploads: Array<{
|
||||
fileName: string
|
||||
key: string
|
||||
localPath: string
|
||||
contentType?: string
|
||||
}> = []
|
||||
|
||||
const shouldHandle = (filename: string, ctx: { hostId?: string, hostType?: string }) => {
|
||||
const includeMatch = include.some((matcher) => {
|
||||
if (matcher instanceof RegExp)
|
||||
return matcher.test(filename)
|
||||
|
||||
return matcher(filename)
|
||||
})
|
||||
|
||||
if (!includeMatch)
|
||||
return false
|
||||
if (options.includeBy)
|
||||
return options.includeBy(filename, ctx)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const renderBuiltUrl: RenderBuiltAssetUrl = (filename, ctx) => {
|
||||
if (!shouldHandle(filename, ctx))
|
||||
return
|
||||
if (!options.provider)
|
||||
return
|
||||
|
||||
const key = prefix ? `${prefix}/${filename}` : filename
|
||||
const url = options.provider.getPublicUrl(key)
|
||||
|
||||
tracked.set(filename, {
|
||||
key,
|
||||
url,
|
||||
hostId: ctx.hostId,
|
||||
hostType: ctx.hostType,
|
||||
})
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
return {
|
||||
name: pluginName,
|
||||
apply: 'build',
|
||||
enforce: 'post',
|
||||
config: () => {
|
||||
return {
|
||||
experimental: {
|
||||
renderBuiltUrl,
|
||||
},
|
||||
}
|
||||
},
|
||||
configResolved(config) {
|
||||
resolvedConfig = config
|
||||
},
|
||||
async generateBundle(_, bundle) {
|
||||
if (!resolvedConfig) {
|
||||
console.warn?.(`[${pluginName}] Vite config not resolved, skipping upload step`)
|
||||
return
|
||||
}
|
||||
if (!options.provider) {
|
||||
resolvedConfig.logger.warn(`[${pluginName}] no upload provider configured, skipping upload step`)
|
||||
return
|
||||
}
|
||||
|
||||
const root = resolvedConfig.root || cwd()
|
||||
const outDir = resolve(root, resolvedConfig.build.outDir)
|
||||
|
||||
for (const [fileName, output] of Object.entries(bundle)) {
|
||||
if (output.type !== 'asset')
|
||||
continue
|
||||
|
||||
const trackedMeta = tracked.get(fileName)
|
||||
if (!trackedMeta)
|
||||
continue
|
||||
|
||||
const key = trackedMeta.key
|
||||
const url = trackedMeta.url
|
||||
const localPath = join(outDir, fileName)
|
||||
const size = getAssetSize(output)
|
||||
const contentType = await options.contentTypeBy?.(fileName)
|
||||
|
||||
manifest.push({
|
||||
fileName,
|
||||
url,
|
||||
key,
|
||||
hostId: trackedMeta.hostId,
|
||||
hostType: trackedMeta.hostType,
|
||||
size,
|
||||
})
|
||||
|
||||
pendingUploads.push({ fileName, key, localPath, contentType })
|
||||
resolvedConfig.logger.info(`[${pluginName}] scheduled uploading: ${fileName} -> ${key} (${size} bytes)`)
|
||||
}
|
||||
|
||||
if (options.manifest && manifest.length) {
|
||||
this.emitFile({
|
||||
type: 'asset',
|
||||
fileName: 'remote-assets.manifest.json',
|
||||
source: JSON.stringify({ assets: manifest }, null, 2),
|
||||
})
|
||||
}
|
||||
},
|
||||
async closeBundle() {
|
||||
if (!resolvedConfig) {
|
||||
console.warn?.(`[${pluginName}] Vite config not resolved, skipping upload step`)
|
||||
return
|
||||
}
|
||||
if (!options.provider) {
|
||||
resolvedConfig.logger.warn(`[${pluginName}] no upload provider configured, skipping upload step`)
|
||||
return
|
||||
}
|
||||
if (!pendingUploads.length)
|
||||
return
|
||||
if (isDryRun) {
|
||||
resolvedConfig.logger.info(
|
||||
`[${pluginName}] dry run enabled; skipping clean/upload for ${pendingUploads.length} assets`,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (shouldCleanRemote && !cleanedRemote) {
|
||||
if (!prefix) {
|
||||
resolvedConfig.logger.warn(`[${pluginName}] skipping clean step because no prefix provided`)
|
||||
}
|
||||
else if (typeof options.provider.cleanPrefix === 'function') {
|
||||
resolvedConfig.logger.info(`[${pluginName}] cleaning remote prefix: ${prefix}`)
|
||||
await options.provider.cleanPrefix(prefix)
|
||||
resolvedConfig.logger.info(`[${pluginName}] cleaned remote prefix: ${prefix}`)
|
||||
cleanedRemote = true
|
||||
}
|
||||
else {
|
||||
resolvedConfig.logger.warn(
|
||||
`[${pluginName}] clean is enabled but provider does not support prefix cleaning; skipping`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
resolvedConfig.logger.info(`[${pluginName}] uploading ${pendingUploads.length} assets to remote storage...`)
|
||||
const uploads: Array<Promise<void>> = []
|
||||
|
||||
for (const { fileName, key, localPath, contentType } of pendingUploads) {
|
||||
uploads.push((async () => {
|
||||
if (shouldSkipNotModified && typeof options.provider.shouldSkipUpload === 'function') {
|
||||
try {
|
||||
const skip = await options.provider.shouldSkipUpload(localPath, key)
|
||||
if (skip) {
|
||||
resolvedConfig.logger.info(
|
||||
`[${pluginName}] skipped upload (not modified): ${fileName} -> ${key}`,
|
||||
)
|
||||
if (shouldDeleteLocalAsset) {
|
||||
try {
|
||||
await rm(localPath, { force: true })
|
||||
resolvedConfig.logger.info(`[${pluginName}] deleted local asset: ${fileName}`)
|
||||
}
|
||||
catch (error) {
|
||||
resolvedConfig.logger.warn(`[${pluginName}] failed to delete local asset ${fileName}: ${error}`)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
resolvedConfig.logger.warn(
|
||||
`[${pluginName}] could not determine if upload should be skipped for ${fileName}: ${error}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
try {
|
||||
await options.provider.upload(localPath, key, contentType)
|
||||
}
|
||||
catch (err) {
|
||||
const error = new Error(errorMessageFrom(err))
|
||||
error.name = errorNameFrom(err) || 'UploadError'
|
||||
const stack = errorStackFrom(err)
|
||||
if (stack)
|
||||
error.stack = stack
|
||||
|
||||
error.cause = errorCauseFrom(err)
|
||||
|
||||
resolvedConfig.logger.error(`[${pluginName}] upload failed, file: ${fileName} -> ${key}: ${err}`, { error })
|
||||
throw err
|
||||
}
|
||||
|
||||
if (shouldDeleteLocalAsset) {
|
||||
try {
|
||||
await rm(localPath, { force: true })
|
||||
resolvedConfig.logger.info(`[${pluginName}] deleted local asset: ${fileName}`)
|
||||
}
|
||||
catch (error) {
|
||||
resolvedConfig.logger.warn(`[${pluginName}] failed to delete local asset ${fileName}: ${error}`)
|
||||
}
|
||||
}
|
||||
})())
|
||||
}
|
||||
|
||||
await Promise.all(uploads)
|
||||
resolvedConfig.logger.info(`[${pluginName}] upload complete`)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function normalizePrefix(prefix: string) {
|
||||
return prefix.replace(/^\/*/, '').replace(/\/*$/, '')
|
||||
}
|
||||
|
||||
function getAssetSize(asset: OutputAsset) {
|
||||
if (typeof asset.source === 'string')
|
||||
return Buffer.byteLength(asset.source)
|
||||
|
||||
return asset.source?.byteLength ?? 0
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { join } from 'node:path'
|
||||
import { cwd, env } from 'node:process'
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { createS3Provider } from './s3'
|
||||
|
||||
describe('s3', (test) => {
|
||||
if (!env.S3_ENDPOINT || !env.S3_REGION || !env.S3_ACCESS_KEY_ID || !env.S3_SECRET_ACCESS_KEY) {
|
||||
test.skip('S3_ENDPOINT, S3_REGION, S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY must be set in environment to run this test', () => {})
|
||||
return
|
||||
}
|
||||
|
||||
// eslint-disable-next-line test/prefer-lowercase-title
|
||||
describe('S3Provider', () => {
|
||||
it('should skip upload', async () => {
|
||||
const s3 = createS3Provider({
|
||||
endpoint: env.S3_ENDPOINT!,
|
||||
accessKeyId: env.S3_ACCESS_KEY_ID!,
|
||||
secretAccessKey: env.S3_SECRET_ACCESS_KEY!,
|
||||
region: env.S3_REGION,
|
||||
publicBaseUrl: env.WARP_DRIVE_PUBLIC_BASE ?? env.S3_ENDPOINT,
|
||||
})
|
||||
|
||||
expect(await s3.shouldSkipUpload?.(join(cwd(), 'packages', 'stage-ui', 'src', 'assets', 'live2d', 'models', 'hiyori_free_zh.zip'), '/proj-airi/stage-web/assets/hiyori_free_zh-D9UJNK98.zip')).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,102 +0,0 @@
|
||||
import type { Buffer } from 'node:buffer'
|
||||
|
||||
import type { UploadProvider } from './types'
|
||||
|
||||
import { createHash } from 'node:crypto'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
|
||||
import { S3mini } from 's3mini'
|
||||
|
||||
export interface S3ProviderOptions {
|
||||
endpoint: string
|
||||
accessKeyId: string
|
||||
secretAccessKey: string
|
||||
region?: string
|
||||
requestSizeInBytes?: number
|
||||
requestAbortTimeout?: number
|
||||
/**
|
||||
* Skip uploading when the remote object ETag matches the local content hash (MD5). Enabled by default.
|
||||
*/
|
||||
skipNotModified?: boolean
|
||||
/**
|
||||
* Public base URL used in rewritten assets. Defaults to endpoint.
|
||||
*/
|
||||
publicBaseUrl?: string
|
||||
}
|
||||
|
||||
export function createS3Provider(options: S3ProviderOptions): UploadProvider {
|
||||
const client = new S3mini({
|
||||
accessKeyId: options.accessKeyId,
|
||||
secretAccessKey: options.secretAccessKey,
|
||||
endpoint: options.endpoint,
|
||||
region: options.region ?? 'auto',
|
||||
requestAbortTimeout: options.requestAbortTimeout,
|
||||
requestSizeInBytes: options.requestSizeInBytes,
|
||||
})
|
||||
|
||||
const publicBaseUrl = options.publicBaseUrl ?? options.endpoint
|
||||
const skipNotModified = options.skipNotModified !== false
|
||||
|
||||
return {
|
||||
async upload(localPath: string, key: string, contentType?: string) {
|
||||
const data = await readFile(localPath)
|
||||
await client.putObject(normalizeKey(key), data, contentType ?? 'application/octet-stream')
|
||||
},
|
||||
async cleanPrefix(prefix: string) {
|
||||
const normalizedPrefix = normalizePrefix(prefix)
|
||||
if (!normalizedPrefix)
|
||||
return
|
||||
|
||||
const objects = await client.listObjects('/', `${normalizedPrefix}/`)
|
||||
if (!objects?.length)
|
||||
return
|
||||
|
||||
const keys = objects.map(obj => obj.Key)
|
||||
await client.deleteObjects(keys)
|
||||
},
|
||||
async shouldSkipUpload(localPath: string, key: string) {
|
||||
if (!skipNotModified)
|
||||
return false
|
||||
|
||||
const data = await readFile(localPath)
|
||||
return isMd5HashMatched(client, key, data)
|
||||
},
|
||||
getPublicUrl(key: string) {
|
||||
return joinUrl(publicBaseUrl, key)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async function isMd5HashMatched(client: S3mini, key: string, data: Buffer) {
|
||||
try {
|
||||
const etag = await client.getEtag(normalizeKey(key))
|
||||
if (!etag)
|
||||
return false
|
||||
|
||||
const normalizedEtag = sanitizeEtag(etag)
|
||||
if (!normalizedEtag || normalizedEtag.includes('-'))
|
||||
return false
|
||||
|
||||
const localHash = createHash('md5').update(data).digest('hex')
|
||||
return normalizedEtag.toLowerCase() === localHash.toLowerCase()
|
||||
}
|
||||
catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function normalizePrefix(prefix: string) {
|
||||
return prefix.replace(/^\/*/, '').replace(/\/*$/, '')
|
||||
}
|
||||
|
||||
function normalizeKey(key: string) {
|
||||
return key.replace(/^\/*/, '')
|
||||
}
|
||||
|
||||
function joinUrl(base: string, path: string) {
|
||||
return `${base.replace(/\/+$/, '')}/${path.replace(/^\/+/, '')}`
|
||||
}
|
||||
|
||||
function sanitizeEtag(etag: string) {
|
||||
return etag.replace(/^"+|"+$/g, '')
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
export interface UploadProvider {
|
||||
getPublicUrl: (key: string) => string
|
||||
upload: (localPath: string, key: string, contentType?: string) => Promise<void>
|
||||
/**
|
||||
* Optionally clean a remote prefix before uploading new assets.
|
||||
*/
|
||||
cleanPrefix?: (prefix: string) => Promise<void>
|
||||
/**
|
||||
* Optionally determine if an upload can be skipped (e.g., hash/etag match).
|
||||
*/
|
||||
shouldSkipUpload?: (localPath: string, key: string) => Promise<boolean>
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { defineConfig } from 'tsdown'
|
||||
|
||||
export default defineConfig({
|
||||
entry: [
|
||||
'./src/index.ts',
|
||||
],
|
||||
dts: true,
|
||||
sourcemap: true,
|
||||
})
|
||||
@@ -1,14 +0,0 @@
|
||||
import { join } from 'node:path'
|
||||
import { cwd } from 'node:process'
|
||||
|
||||
import { loadEnv } from 'vite'
|
||||
import { defineConfig } from 'vitest/config'
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
return ({
|
||||
test: {
|
||||
include: ['src/**/*.test.ts'],
|
||||
env: loadEnv(mode, join(cwd(), 'packages', 'vite-plugin-warpdrive'), ''),
|
||||
},
|
||||
})
|
||||
})
|
||||
Generated
+23
-197
@@ -1063,9 +1063,6 @@ importers:
|
||||
'@proj-airi/unplugin-live2d-sdk':
|
||||
specifier: ^0.1.7
|
||||
version: 0.1.7(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)
|
||||
'@proj-airi/vite-plugin-warpdrive':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/vite-plugin-warpdrive
|
||||
'@shikijs/markdown-it':
|
||||
specifier: ^4.0.2
|
||||
version: 4.0.2
|
||||
@@ -1950,9 +1947,6 @@ importers:
|
||||
'@proj-airi/unplugin-live2d-sdk':
|
||||
specifier: ^0.1.7
|
||||
version: 0.1.7(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)
|
||||
'@proj-airi/vite-plugin-warpdrive':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/vite-plugin-warpdrive
|
||||
'@shikijs/markdown-it':
|
||||
specifier: ^4.0.2
|
||||
version: 4.0.2
|
||||
@@ -1998,6 +1992,9 @@ importers:
|
||||
less:
|
||||
specifier: ^4.6.4
|
||||
version: 4.6.4
|
||||
unplugin-basemove:
|
||||
specifier: 0.0.1
|
||||
version: 0.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))
|
||||
unplugin-info:
|
||||
specifier: ^1.3.2
|
||||
version: 1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))
|
||||
@@ -3486,9 +3483,6 @@ importers:
|
||||
'@proj-airi/stream-kit':
|
||||
specifier: workspace:*
|
||||
version: link:../stream-kit
|
||||
'@proj-airi/vite-plugin-warpdrive':
|
||||
specifier: workspace:*
|
||||
version: link:../vite-plugin-warpdrive
|
||||
'@types/audioworklet':
|
||||
specifier: 'catalog:'
|
||||
version: 0.0.97
|
||||
@@ -3531,6 +3525,9 @@ importers:
|
||||
unocss:
|
||||
specifier: ^66.6.8
|
||||
version: 66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))
|
||||
unplugin-basemove:
|
||||
specifier: 0.0.1
|
||||
version: 0.0.1(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))
|
||||
unplugin-info:
|
||||
specifier: 'catalog:'
|
||||
version: 1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))
|
||||
@@ -3876,22 +3873,6 @@ importers:
|
||||
specifier: ^3.2.6
|
||||
version: 3.2.6(typescript@5.9.3)
|
||||
|
||||
packages/vite-plugin-warpdrive:
|
||||
dependencies:
|
||||
rolldown:
|
||||
specifier: 1.0.0-beta.51
|
||||
version: 1.0.0-beta.51(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)
|
||||
s3mini:
|
||||
specifier: ^0.9.4
|
||||
version: 0.9.4
|
||||
vite:
|
||||
specifier: ^5.0.0 || ^6.0.0
|
||||
version: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)
|
||||
devDependencies:
|
||||
'@moeru/std':
|
||||
specifier: 'catalog:'
|
||||
version: 0.1.0-beta.17
|
||||
|
||||
plugins/airi-plugin-bilibili-laplace:
|
||||
dependencies:
|
||||
'@guiiai/logg':
|
||||
@@ -7944,9 +7925,6 @@ packages:
|
||||
'@oxc-project/types@0.126.0':
|
||||
resolution: {integrity: sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==}
|
||||
|
||||
'@oxc-project/types@0.98.0':
|
||||
resolution: {integrity: sha512-Vzmd6FsqVuz5HQVcRC/hrx7Ujo3WEVeQP7C2UNP5uy1hUY4SQvMB+93jxkI1KRHz9a/6cni3glPOtvteN+zpsw==}
|
||||
|
||||
'@oxc-resolver/binding-android-arm-eabi@11.19.1':
|
||||
resolution: {integrity: sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==}
|
||||
cpu: [arm]
|
||||
@@ -8703,12 +8681,6 @@ packages:
|
||||
'@rive-app/canvas-lite@2.37.2':
|
||||
resolution: {integrity: sha512-Pp8R/ZpZliwkPm684HFIKZ4N6UurcfbfFQXV74+HV2bxAutpQYsDCr0sOjEgJC/brG5aeSCVyJY3Iq7nNAkmeQ==}
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-Ctn8FUXKWWQI9pWC61P1yumS9WjQtelNS9riHwV7oCkknPGaAry4o7eFx2KgoLMnI2BgFJYpW7Im8/zX3BuONg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8721,12 +8693,6 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-EL1aRW2Oq15ShUEkBPsDtLMO8GTqfb/ktM/dFaVzXKQiEE96Ss6nexMgfgQrg8dGnNpndFyffVDb5IdSibsu1g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8739,12 +8705,6 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-uGtYKlFen9pMIPvkHPWZVDtmYhMQi5g5Ddsndg1gf3atScKYKYgs5aDP4DhHeTwGXQglhfBG7lEaOIZ4UAIWww==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8757,12 +8717,6 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-JRoVTQtHYbZj1P07JLiuTuXjiBtIa7ag7/qgKA6CIIXnAcdl4LrOf7nfDuHPJcuRKaP5dzecMgY99itvWfmUFQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8775,12 +8729,6 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-BKATVnpPZ0TYBW9XfDwyd4kPGgvf964HiotIwUgpMrFOFYWqpZ+9ONNzMV4UFAYC7Hb5C2qgYQk/qj2OnAd4RQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8793,13 +8741,6 @@ packages:
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-xLd7da5jkfbVsBCm1buIRdWtuXY8+hU3+6ESXY/Tk5X5DPHaifrUblhYDgmA34dQt6WyNC2kfXGgrduPEvDI6Q==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8814,13 +8755,6 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-EQFXTgHxxTzv3t5EmjUP/DfxzFYx9sMndfLsYaAY4DWF6KsK1fXGYsiupif6qPTViPC9eVmRm78q0pZU/kuIPg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8863,13 +8797,6 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-p5P6Xpa68w3yFaAdSzIZJbj+AfuDnMDqNSeglBXM7UlJT14Q4zwK+rV+8Mhp9MiUb4XFISZtbI/seBprhkQbiQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8884,13 +8811,6 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-sNVVyLa8HB8wkFipdfz1s6i0YWinwpbMWk5hO5S+XAYH2UH67YzUT13gs6wZTKg2x/3gtgXzYnHyF5wMIqoDAw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8905,12 +8825,6 @@ packages:
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-e/JMTz9Q8+T3g/deEi8DK44sFWZWGKr9AOCW5e8C8SCVWzAXqYXAG7FXBWBNzWEZK0Rcwo9TQHTQ9Q0gXgdCaA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8923,11 +8837,6 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-We3LWqSu6J9s5Y0MK+N7fUiiu37aBGPG3Pc347EoaROuAwkCS2u9xJ5dpIyLW4B49CIbS3KaPmn4kTgPb3EyPw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -8938,12 +8847,6 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-fj56buHRuMM+r/cb6ZYfNjNvO/0xeFybI6cTkTROJatdP4fvmQ1NS8D/Lm10FCSDEOkqIz8hK3TGpbAThbPHsA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8956,18 +8859,6 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-fkqEqaeEx8AySXiDm54b/RdINb3C0VovzJA3osMhZsbn6FoD73H0AOIiaVAtGr6x63hefruVKTX8irAm4Jkt2w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-CWuLG/HMtrVcjKGa0C4GnuxONrku89g0+CsH8nT0SNhOtREXuzwgjIXNJImpE/A/DMf9JF+1Xkrq/YRr+F/rCg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.15':
|
||||
resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -8980,9 +8871,6 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.51':
|
||||
resolution: {integrity: sha512-51/8cNXMrqWqX3o8DZidhwz1uYq0BhHDDSfVygAND1Skx5s1TDw3APSSxCMcFFedwgqGcx34gRouwY+m404BBQ==}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-rc.13':
|
||||
resolution: {integrity: sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==}
|
||||
|
||||
@@ -16245,11 +16133,6 @@ packages:
|
||||
vue-tsc:
|
||||
optional: true
|
||||
|
||||
rolldown@1.0.0-beta.51:
|
||||
resolution: {integrity: sha512-ZRLgPlS91l4JztLYEZnmMcd3Umcla1hkXJgiEiR4HloRJBBoeaX8qogTu5Jfu36rRMVLndzqYv0h+M5gJAkUfg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
rolldown@1.0.0-rc.15:
|
||||
resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -17328,6 +17211,11 @@ packages:
|
||||
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
unplugin-basemove@0.0.1:
|
||||
resolution: {integrity: sha512-U1XlGlzhmppJwNbCLMHZCr9srhRclpCTa70vcOoe8B9CGcmQ5ykqqsNc4p3twHLifsmorWL0mXgjWd71y89VSA==}
|
||||
peerDependencies:
|
||||
vite: ^5.0.0 || ^6.0.0
|
||||
|
||||
unplugin-combine@2.3.0:
|
||||
resolution: {integrity: sha512-0aZjv0JqOCPY+yujTatSwlCbsK6bMcBUZDlpMHTlc7KDc2gq8XL5cPgEOeS2GZ767BHAonkEqhC+NlOvzzm5FA==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
@@ -22251,8 +22139,6 @@ snapshots:
|
||||
|
||||
'@oxc-project/types@0.126.0': {}
|
||||
|
||||
'@oxc-project/types@0.98.0': {}
|
||||
|
||||
'@oxc-resolver/binding-android-arm-eabi@11.19.1':
|
||||
optional: true
|
||||
|
||||
@@ -22900,63 +22786,42 @@ snapshots:
|
||||
|
||||
'@rive-app/canvas-lite@2.37.2': {}
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
@@ -22975,41 +22840,24 @@ snapshots:
|
||||
'@rolldown/binding-linux-s390x-gnu@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.51(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)':
|
||||
dependencies:
|
||||
'@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)
|
||||
transitivePeerDependencies:
|
||||
- '@emnapi/core'
|
||||
- '@emnapi/runtime'
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-rc.15':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.9.2
|
||||
@@ -23024,29 +22872,18 @@ snapshots:
|
||||
'@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.51':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.16':
|
||||
optional: true
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.51': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-rc.13': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-rc.15': {}
|
||||
@@ -31687,29 +31524,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- oxc-resolver
|
||||
|
||||
rolldown@1.0.0-beta.51(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2):
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.98.0
|
||||
'@rolldown/pluginutils': 1.0.0-beta.51
|
||||
optionalDependencies:
|
||||
'@rolldown/binding-android-arm64': 1.0.0-beta.51
|
||||
'@rolldown/binding-darwin-arm64': 1.0.0-beta.51
|
||||
'@rolldown/binding-darwin-x64': 1.0.0-beta.51
|
||||
'@rolldown/binding-freebsd-x64': 1.0.0-beta.51
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.51
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.51
|
||||
'@rolldown/binding-linux-arm64-musl': 1.0.0-beta.51
|
||||
'@rolldown/binding-linux-x64-gnu': 1.0.0-beta.51
|
||||
'@rolldown/binding-linux-x64-musl': 1.0.0-beta.51
|
||||
'@rolldown/binding-openharmony-arm64': 1.0.0-beta.51
|
||||
'@rolldown/binding-wasm32-wasi': 1.0.0-beta.51(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.51
|
||||
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.51
|
||||
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.51
|
||||
transitivePeerDependencies:
|
||||
- '@emnapi/core'
|
||||
- '@emnapi/runtime'
|
||||
|
||||
rolldown@1.0.0-rc.15:
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.124.0
|
||||
@@ -33041,6 +32855,18 @@ snapshots:
|
||||
|
||||
unpipe@1.0.0: {}
|
||||
|
||||
unplugin-basemove@0.0.1(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)):
|
||||
dependencies:
|
||||
s3mini: 0.9.4
|
||||
unplugin: 3.0.0
|
||||
vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)
|
||||
|
||||
unplugin-basemove@0.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)):
|
||||
dependencies:
|
||||
s3mini: 0.9.4
|
||||
unplugin: 3.0.0
|
||||
vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)
|
||||
|
||||
unplugin-combine@2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@2.80.0)(unplugin@2.3.11)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)):
|
||||
optionalDependencies:
|
||||
esbuild: 0.27.2
|
||||
|
||||
@@ -15,7 +15,6 @@ export default defineConfig({
|
||||
'packages/server-runtime',
|
||||
'packages/server-sdk',
|
||||
'packages/stage-shared',
|
||||
'packages/vite-plugin-warpdrive',
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user