update: state, event, condition, data.event.types

This commit is contained in:
Vick Scarlet
2026-08-16 20:06:16 +08:00
committed by 神戸小鳥
parent e035cdfe90
commit e646492e75
18 changed files with 1216 additions and 793 deletions
+2 -7
View File
@@ -1,5 +1,5 @@
import { expect, test, describe } from 'bun:test'
import { checkCondition } from '.'
import { check } from '.'
// 定义属性 mock 字典的类型契约
interface MockProperties {
@@ -10,12 +10,7 @@ interface MockProperties {
* 属性注入高阶函数:模拟角色属性管理类
*/
function withProp(prop: MockProperties) {
const p = {
get(key: string): any {
return prop[key]
},
}
return (condition: string): boolean => checkCondition(p, condition)
return (condition: string): boolean => check(prop, condition)
}
describe('condition', () => {
+27 -24
View File
@@ -1,17 +1,9 @@
// 条件节点可以是一个纯字符串表达式(如 'AGE>18'),或者是一个无限嵌套自身的数组
export type ConditionNode = string | ConditionTree
export interface ConditionTree extends Array<ConditionNode> {}
// 🌟 核心类型定义 2:定义满足有 .get 提取器属性的游戏对象约束(如玩家属性管理类或原生 Map)
export interface PropertyContainer {
get(key: string): any
}
export type PropertyContainer = Record<string, any>
/**
* 词法解析器:将条件字符串切分为多维嵌套的语法树树(AST)
* @param condition 原始字符串表达式,例如 "AGE > 10 & (SEX = 1 | CHR >= 5)"
*/
function parseCondition(condition: string): ConditionTree {
export function parse(condition: string): ConditionTree {
const conditions: ConditionTree = []
const length = condition.length
const stack: ConditionTree[] = []
@@ -60,16 +52,8 @@ function parseCondition(condition: string): ConditionTree {
return conditions
}
/**
* 外部核心接口:判定某个角色的属性是否完美符合该文本条件限制
* @param property 玩家或局内属性提取器
* @param condition 原始条件表达式
*/
export function checkCondition(
property: PropertyContainer,
condition: string,
): boolean {
const conditions = parseCondition(condition)
export function check(property: PropertyContainer, condition: string): boolean {
const conditions = parse(condition)
return checkParsedConditions(property, conditions)
}
@@ -115,9 +99,6 @@ function checkParsedConditions(
return ret
}
/**
* 原子逻辑判定器:负责处理诸如 '>', '<', '=', '?', '!' 各种操作符的最终生死判定
*/
function checkProp(property: PropertyContainer, condition: string): boolean {
const length = condition.length
let i = condition.search(/[><!?=]/)
@@ -131,7 +112,7 @@ function checkProp(property: PropertyContainer, condition: string): boolean {
const symbol = condition.substring(i, (i += isDoubleSymbol ? 2 : 1))
const d = condition.substring(i, length)
const propData = property.get(prop)
const propData = property[prop]
const conditionData: number | any[] =
d[0] === '[' ? JSON.parse(d) : Number(d)
@@ -145,17 +126,31 @@ function checkProp(property: PropertyContainer, condition: string): boolean {
case '<=':
return propData <= conditionData
case '=':
if (propData instanceof Set) {
return propData.has(conditionData)
}
if (Array.isArray(propData)) {
return propData.includes(conditionData)
}
return propData == conditionData
case '!=':
if (propData instanceof Set) {
return !propData.has(conditionData)
}
if (Array.isArray(propData)) {
return !propData.includes(conditionData)
}
return propData != conditionData
case '?': // 🌟 包含判定符(如 属性值 是否在 [1,2,3] 数组范围内)
if (propData instanceof Set) {
if (Array.isArray(conditionData)) {
for (const c of conditionData) {
if (propData.has(c)) return true
}
}
return false
}
if (Array.isArray(propData)) {
if (Array.isArray(conditionData)) {
for (const p of propData) {
@@ -170,6 +165,14 @@ function checkProp(property: PropertyContainer, condition: string): boolean {
return false
case '!': // 🌟 排除判定符(如 属性值 是否不存在于 [1,2,3] 数组中)
if (propData instanceof Set) {
if (Array.isArray(conditionData)) {
for (const c of conditionData) {
if (propData.has(c)) return false
}
}
return true
}
if (Array.isArray(propData)) {
if (Array.isArray(conditionData)) {
for (const p of propData) {
+4 -2
View File
@@ -7,9 +7,11 @@
"lint": "eslint .",
"test": "bun test"
},
"devDependencies": {
"dependencies": {
"@remake/condition": "workspace:*",
"@remake/data": "workspace:*"
"@remake/data": "workspace:*",
"@remake/vitex": "workspace:*",
"immer": "^11.1.15"
},
"eslintConfig": {
"extends": "../../package.json"
+36
View File
@@ -0,0 +1,36 @@
import { expect, test, describe } from 'bun:test'
import { createState } from './state'
import { trigger } from './event'
describe('Event', () => {
const profile = {
times: 0,
talents: new Set([]),
achievements: new Set([]),
events: new Set([]),
}
const allocation = {
charm: 10,
intelligence: 10,
strength: 0,
money: 0,
}
test('10003 branch 0 玉佩', () => {
const result = trigger(
10003,
createState(allocation, [1001, 1002, 1003]),
profile,
)
expect(result.state.life).toBe(1)
expect(result.state.events).toEqual(new Set([10003, 10004]))
expect(result.events).toEqual([10003, 10004])
})
test('10003 branch 1 死了', () => {
const result = trigger(10003, createState(allocation, []), profile)
expect(result.state.life).toBe(0)
expect(result.state.events).toEqual(new Set([10003, 10000]))
expect(result.events).toEqual([10003, 10000])
})
})
+51
View File
@@ -0,0 +1,51 @@
import type { EventEffect, Event } from '@remake/data/event'
import events from '@remake/data/event'
import type { Properties, Effect } from '@/state'
import type { GameState, ProfileState } from '@/state'
import { stateEffect, createFlatState } from '@/state'
import { check } from '@remake/condition'
export function convertEffect(effect: EventEffect): Effect {
const converted = {} as Effect
const properties = [] as [keyof Properties, number][]
if (effect.CHR) properties.push(['charm', effect.CHR])
if (effect.INT) properties.push(['intelligence', effect.INT])
if (effect.STR) properties.push(['strength', effect.STR])
if (effect.MNY) properties.push(['money', effect.MNY])
if (effect.SPR) properties.push(['spirit', effect.SPR])
if (properties.length > 0)
converted.properties = Object.fromEntries(properties)
if (effect.LIF) converted.life = effect.LIF
return converted
}
export interface TriggerResult {
state: GameState
events: Event['id'][]
}
export function trigger(
eventId: number,
state: GameState,
profile: ProfileState,
): TriggerResult {
const event = events.get(eventId)
if (!event)
throw new Error(`[@remake/core][event] id:${eventId} not found.`)
const effect = event.effect ? convertEffect(event.effect) : {}
effect.events = [eventId]
const newState = stateEffect(state, effect)
const flatState = createFlatState(newState, profile)
if (event.branch) {
for (const branch of event.branch) {
if (check(flatState, branch.condition)) {
const result = trigger(branch.event, newState, profile)
return {
state: result.state,
events: [eventId, ...result.events],
}
}
}
}
return { state: newState, events: [eventId] }
}
+4
View File
@@ -0,0 +1,4 @@
export interface GameEffects {
save: (profile: any) => Promise<boolean>
load: () => Promise<any>
}
-2
View File
@@ -1,2 +0,0 @@
import { age } from '@remake/data/age'
import { checkCondition } from '@remake/condition'
+212
View File
@@ -0,0 +1,212 @@
import { expect, test, describe } from 'bun:test'
import { parse, type ConditionNode } from '@remake/condition'
import achievements from '@remake/data/achievement'
import events from '@remake/data/event'
import talents from '@remake/data/talent'
import { createFlatState } from './state'
const A = ['AGE', 'CHR', 'INT', 'STR', 'MNY', 'SPR', 'LIF', 'TLT', 'EVT', 'TMS']
const B = ['HAGE', 'HCHR', 'HINT', 'HSTR', 'HMNY', 'HSPR']
const C = ['LAGE', 'LCHR', 'LINT', 'LSTR', 'LMNY', 'LSPR']
const D = ['AEVT', 'ATLT', 'SUM']
const FlatProperties = new Set([...A, ...B, ...C, ...D])
/**
* 核心递归辅助函数:从多维语法树节点中提取所有属性名
*/
function extractKeysFromNode(node: ConditionNode, properties: Set<string>) {
if (Array.isArray(node)) {
for (const subNode of node) {
extractKeysFromNode(subNode, properties)
}
} else {
if (node === '&' || node === '|') return
// 匹配操作符(><!?=)前面的属性名部分
const match = node.match(/^([^><!?=]+)/)
if (match && match) {
properties.add(match[1]!.trim())
}
}
}
/**
* 从条件字符串中提取所有使用到的属性键名
*/
function getPropertiesFromCondition(condition: string): Set<string> {
const parsedConditions = parse(condition)
const properties = new Set<string>()
extractKeysFromNode(parsedConditions, properties)
return properties
}
describe('策划配置条件完整覆盖率测试', () => {
test('event [include, exclude, branch]', () => {
const unmappedKeys = new Set<string>()
for (const item of events.values()) {
const conditionsToTrack: { label: string; text: string }[] = []
if (item.include) {
conditionsToTrack.push({ label: 'include', text: item.include })
}
if (item.exclude) {
conditionsToTrack.push({ label: 'exclude', text: item.exclude })
}
if (item.branch && Array.isArray(item.branch)) {
item.branch.forEach((branchObj, index) => {
if (branchObj && branchObj.condition) {
conditionsToTrack.push({
label: `branch[${index}].condition (目标事件ID: ${branchObj.event})`,
text: branchObj.condition,
})
}
})
}
for (const { label, text } of conditionsToTrack) {
const usedProperties = getPropertiesFromCondition(text)
for (const key of usedProperties) {
if (!FlatProperties.has(key)) {
unmappedKeys.add(
`[事件 ID: ${item.id}] 的 "${label}" 字段使用了未定义的键名: "${key}" (完整条件: "${text}")`,
)
}
}
}
}
if (unmappedKeys.size > 0) {
console.error('\n❌ 发现事件配置表存在未定义的 Property 键名:')
unmappedKeys.forEach(msg => console.error(msg))
}
expect(unmappedKeys.size).toBe(0)
})
test('talent [condition]', () => {
const unmappedKeys = new Set<string>()
const allTalentItems = talents.values()
for (const item of allTalentItems) {
const conditionStr = item.condition
if (!conditionStr) continue
const usedProperties = getPropertiesFromCondition(conditionStr)
for (const key of usedProperties) {
if (!FlatProperties.has(key)) {
unmappedKeys.add(
`[天赋 ID: ${item.id}] 使用了未定义的键名: "${key}" (完整条件: "${conditionStr}")`,
)
}
}
}
if (unmappedKeys.size > 0) {
console.error('\n❌ 发现天赋配置表存在未定义的 Property 键名:')
unmappedKeys.forEach(msg => console.error(msg))
}
expect(unmappedKeys.size).toBe(0)
})
test('achievement [condition]', () => {
const unmappedKeys = new Set<string>()
const allAchievementItems = achievements.values()
for (const item of allAchievementItems) {
const conditionStr = item.condition
if (!conditionStr) continue
const usedProperties = getPropertiesFromCondition(conditionStr)
for (const key of usedProperties) {
if (!FlatProperties.has(key)) {
unmappedKeys.add(
`[成就 ID: ${item.id}] 使用了未定义的键名: "${key}" (完整条件: "${conditionStr}")`,
)
}
}
}
if (unmappedKeys.size > 0) {
console.error('\n❌ 发现成就配置表存在未定义的 Property 键名:')
unmappedKeys.forEach(msg => console.error(msg))
}
expect(unmappedKeys.size).toBe(0)
})
})
describe('FlatProperties', () => {
test('check key', () => {
const game = {
lowest: {
age: 1,
charm: 2,
intelligence: 3,
strength: 4,
money: 5,
spirit: 6,
},
properties: {
age: 11,
charm: 12,
intelligence: 13,
strength: 14,
money: 15,
spirit: 16,
},
highest: {
age: 21,
charm: 22,
intelligence: 23,
strength: 24,
money: 25,
spirit: 26,
},
life: 31,
talents: new Set([33]),
events: new Set([34, 35]),
achievements: new Set([36]),
}
const profile = {
times: 41,
external: 42,
talents: new Set([43]),
achievements: new Set([44]),
events: new Set([45, 46]),
}
const flatState = createFlatState(game, profile)
expect(flatState['AGE']).toBe(game.properties.age)
expect(flatState['CHR']).toBe(game.properties.charm)
expect(flatState['INT']).toBe(game.properties.intelligence)
expect(flatState['STR']).toBe(game.properties.strength)
expect(flatState['MNY']).toBe(game.properties.money)
expect(flatState['SPR']).toBe(game.properties.spirit)
expect(flatState['LIF']).toBe(game.life)
expect(flatState['TLT']).toEqual(game.talents)
expect(flatState['EVT']).toEqual(game.events)
expect(flatState['LAGE']).toBe(game.lowest.age)
expect(flatState['HAGE']).toBe(game.highest.age)
expect(flatState['LCHR']).toBe(game.lowest.charm)
expect(flatState['HCHR']).toBe(game.highest.charm)
expect(flatState['LINT']).toBe(game.lowest.intelligence)
expect(flatState['HINT']).toBe(game.highest.intelligence)
expect(flatState['LSTR']).toBe(game.lowest.strength)
expect(flatState['HSTR']).toBe(game.highest.strength)
expect(flatState['LMNY']).toBe(game.lowest.money)
expect(flatState['HMNY']).toBe(game.highest.money)
expect(flatState['LSPR']).toBe(game.lowest.spirit)
expect(flatState['HSPR']).toBe(game.highest.spirit)
expect(flatState['TMS']).toBe(profile.times)
expect(flatState['AEVT']).toEqual(profile.events)
expect(flatState['ATLT']).toEqual(profile.talents)
expect(flatState['AACH']).toEqual(profile.achievements)
expect(flatState['SUM']).toBe(
Math.floor((22 + 23 + 24 + 25 + 26) * 2 + 21 / 2),
)
})
})
+212
View File
@@ -0,0 +1,212 @@
import type { Talent } from '@remake/data/talent'
import type { Event } from '@remake/data/event'
import type { Achievement } from '@remake/data/achievement'
import { produce, enableMapSet } from 'immer'
import { sum } from '@remake/vitex'
enableMapSet()
/** 基础的属性 */
export interface Properties {
age: number
charm: number
intelligence: number
strength: number
money: number
spirit: number
}
export type Allocation = Omit<Properties, 'age' | 'spirit'>
export interface GameState {
properties: Properties // 本局属性
highest: Properties // 本局最高属性
lowest: Properties // 本局最低属性
life: number // 本局生命值
talents: Set<Talent['id']> // 本局拥有的天赋
events: Set<Event['id']> // 本局触发过的事件
achievements: Set<Achievement['id']> // 本局达成的成就
}
/** 持久化存储的数据 */
export interface ProfileState {
times: number // 游戏次数
external?: Talent['id'] // 继承的天赋
talents: Set<Talent['id']> // 拥有过的天赋
events: Set<Event['id']> // 触发过的事件
achievements: Set<Achievement['id']> // 达成的成就
highest?: Properties // 历史最高属性
lowest?: Properties // 历史最低属性
}
export function createState(
allocation: Allocation,
talents?: Iterable<Talent['id']>,
): GameState {
const properties = { ...allocation, age: -1, spirit: 0 }
return {
properties,
highest: { ...properties },
lowest: { ...properties },
life: 1,
talents: new Set(talents),
events: new Set(),
achievements: new Set(),
}
}
export interface FlatState {
AGE: GameState['properties']['age']
CHR: GameState['properties']['charm']
INT: GameState['properties']['intelligence']
STR: GameState['properties']['strength']
MNY: GameState['properties']['money']
SPR: GameState['properties']['spirit']
LIF: GameState['life']
TLT: GameState['talents']
EVT: GameState['events']
LAGE: GameState['lowest']['age']
HAGE: GameState['highest']['age']
LCHR: GameState['lowest']['charm']
HCHR: GameState['highest']['charm']
LINT: GameState['lowest']['intelligence']
HINT: GameState['highest']['intelligence']
LSTR: GameState['lowest']['strength']
HSTR: GameState['highest']['strength']
LMNY: GameState['lowest']['money']
HMNY: GameState['highest']['money']
LSPR: GameState['lowest']['spirit']
HSPR: GameState['highest']['spirit']
TMS: ProfileState['times']
AEVT: ProfileState['events']
ATLT: ProfileState['talents']
AACH: ProfileState['achievements']
SUM: number
}
interface FlatPropertiesTarget {
game: GameState
profile: ProfileState
}
const FlatMappers = {
AGE: (state: FlatPropertiesTarget) => state.game.properties.age,
CHR: (state: FlatPropertiesTarget) => state.game.properties.charm,
INT: (state: FlatPropertiesTarget) => state.game.properties.intelligence,
STR: (state: FlatPropertiesTarget) => state.game.properties.strength,
MNY: (state: FlatPropertiesTarget) => state.game.properties.money,
SPR: (state: FlatPropertiesTarget) => state.game.properties.spirit,
LIF: (state: FlatPropertiesTarget) => state.game.life,
TLT: (state: FlatPropertiesTarget) => state.game.talents,
EVT: (state: FlatPropertiesTarget) => state.game.events,
LAGE: (state: FlatPropertiesTarget) => state.game.lowest.age,
HAGE: (state: FlatPropertiesTarget) => state.game.highest.age,
LCHR: (state: FlatPropertiesTarget) => state.game.lowest.charm,
HCHR: (state: FlatPropertiesTarget) => state.game.highest.charm,
LINT: (state: FlatPropertiesTarget) => state.game.lowest.intelligence,
HINT: (state: FlatPropertiesTarget) => state.game.highest.intelligence,
LSTR: (state: FlatPropertiesTarget) => state.game.lowest.strength,
HSTR: (state: FlatPropertiesTarget) => state.game.highest.strength,
LMNY: (state: FlatPropertiesTarget) => state.game.lowest.money,
HMNY: (state: FlatPropertiesTarget) => state.game.highest.money,
LSPR: (state: FlatPropertiesTarget) => state.game.lowest.spirit,
HSPR: (state: FlatPropertiesTarget) => state.game.highest.spirit,
TMS: (state: FlatPropertiesTarget) => state.profile.times,
AEVT: (state: FlatPropertiesTarget) => state.profile.events,
ATLT: (state: FlatPropertiesTarget) => state.profile.talents,
AACH: (state: FlatPropertiesTarget) => state.profile.achievements,
SUM: (state: FlatPropertiesTarget) => {
const { age, ...others } = state.game.highest
const s = sum(Object.values(others))
return Math.floor(s * 2 + age / 2)
},
}
const flatPropertiesHandle = {
get(target: FlatPropertiesTarget, prop: string) {
if (prop in FlatMappers) {
return FlatMappers[prop as keyof typeof FlatMappers](target)
}
},
set() {
return true
},
}
export function createFlatState(game: GameState, profile: ProfileState) {
return new Proxy(
{ game, profile },
flatPropertiesHandle,
) as unknown as FlatState
}
export interface Effect {
properties?: Partial<Properties>
life?: number
talents?: Iterable<Talent['id']>
events?: Iterable<Event['id']>
achievements?: Iterable<Achievement['id']>
}
export function stateEffect(state: GameState, effect: Effect) {
return produce(state, draft => {
for (const key in effect.properties) {
const prop = key as keyof Properties
const value = effect.properties[prop]!
draft.properties[prop] += value
draft.highest[prop] = Math.max(
draft.highest[prop],
draft.properties[prop],
)
draft.lowest[prop] = Math.min(
draft.lowest[prop],
draft.properties[prop],
)
}
if (effect.life) draft.life += effect.life
if (effect.talents)
draft.talents = new Set([...draft.talents, ...effect.talents])
if (effect.events)
draft.events = new Set([...draft.events, ...effect.events])
if (effect.achievements)
draft.achievements = new Set([
...draft.achievements,
...effect.achievements,
])
})
}
function highestProperties(a: Properties, b?: Properties): Properties {
if (!b) return { ...a }
const result = {} as Properties
for (const key of Object.keys(a) as (keyof Properties)[]) {
result[key] = Math.max(a[key], b[key])
}
return result
}
function lowestProperties(a: Properties, b?: Properties): Properties {
if (!b) return { ...a }
const result = {} as Properties
for (const key of Object.keys(a) as (keyof Properties)[]) {
result[key] = Math.min(a[key], b[key])
}
return result
}
export function nextProfile(
profile: ProfileState,
state: GameState,
external?: Talent['id'],
) {
return {
times: profile.times + 1,
talents: profile.talents.union(state.talents),
events: profile.events.union(state.events),
achievements: profile.achievements.union(state.achievements),
highest: highestProperties(state.highest, profile.highest),
lowest: lowestProperties(state.lowest, profile.lowest),
external: external ?? profile.external,
}
}
+21
View File
@@ -0,0 +1,21 @@
import type { TalentEffect } from '@remake/data/talent'
import talents from '@remake/data/talent'
import type { Properties } from './state'
import { pick } from '@remake/vitex'
const TalentEffectPropertiesKeyMapper = {
MNY: () => 'money',
STR: () => 'strength',
INT: () => 'intelligence',
CHR: () => 'charm',
SPR: () => 'spirit',
RND: () => pick(['money', 'strength', 'intelligence', 'charm', 'spirit'])!,
} as Record<keyof TalentEffect, () => keyof Properties>
export const count = talents.size
export function get(talent: number) {
return talents.get(talent)
}
export function random(talent: number) {}
+1 -1
View File
@@ -5,7 +5,7 @@
"main": "src/index.ts",
"author": "Vick Scarlet <vick@syaro.io>",
"scripts": {
"build": "bunx --bun v-transform@3.0.0 transform -t ts -w src -d dist \"**/[!~$]*.xlsx\" ",
"build": "bunx --bun v-transform@3.0.1 transform -t ts -w src -d dist \"**/[!~$]*.xlsx\" ",
"lint": "eslint .",
"test": "bun test"
},
+20 -1
View File
@@ -19,6 +19,14 @@ export type EventEffect = {
readonly AGE?: number
}
/** 分支路线 */
export type EventBranch = {
/** 分支条件 */
condition: string
/** 分支事件ID */
event: number
}
/** 事件 */
export type Event = {
/** ID */
@@ -38,7 +46,7 @@ export type Event = {
/** 有某事件时一定随机不到 */
readonly exclude?: string
/** 分支路线 */
readonly branch?: string[]
readonly branch?: EventBranch[]
}
// @vt-types-end
@@ -55,4 +63,15 @@ export const transformers = {
}
return val
},
branch: (val?: any[]) => {
if (!val) return
for (const key in val) {
const [condition, eventId] = val[key]!.split(':')
const event = Number(eventId)
if (isNaN(event))
throw new Error(`Invalid event ID in branch: ${eventId}`)
val[key] = { condition, event }
}
return val
},
}
+24
View File
@@ -0,0 +1,24 @@
export type RNG = (max?: number, min?: number) => number
export function random(max: number, min: number = 0, rng?: RNG): number {
if (rng) return rng(max, min)
return Math.floor(Math.random() * (max - min + 1)) + min
}
export function pick<T>(items: T[], rng?: RNG) {
if (items.length === 0) return null
return items[random(items.length - 1, 0, rng)]
}
export type WeightItem<T> = [T, number]
export function pickWeight<T>(items: WeightItem<T>[], rng?: RNG) {
if (items.length === 0) return null
const totalWeight = items.reduce((sum, [, weight]) => sum + weight, 0)
let mark = random(totalWeight - 1, 0, rng)
for (const [item, weight] of items) {
if (mark < weight) return item
mark -= weight
}
return null
}
export function sum(arr: number[]) {
return arr.reduce((sum, v) => sum + v, 0)
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "@remake/vitex",
"type": "module",
"version": "3.0.0",
"main": "./index.ts",
"author": "Vick Scarlet <vick@syaro.io>",
"scripts": {
"lint": "eslint .",
"test": "bun test"
},
"eslintConfig": {
"extends": "../../package.json"
}
}
+29
View File
@@ -0,0 +1,29 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"types": ["bun"],
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": true,
"noUnusedParameters": true,
"noPropertyAccessFromIndexSignature": false,
"noImplicitAny": true
},
"include": ["**/*"]
}
+74 -580
View File
@@ -47,30 +47,40 @@ importers:
devDependencies:
'@preact/preset-vite':
specifier: ^2.10.2
version: 2.10.6(@babel/core@7.29.7)(preact@10.29.7)(rollup@4.62.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0))
version: 2.10.6(@babel/core@7.29.7)(preact@10.29.7)(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0))
eslint-config-preact:
specifier: ^2.0.0
version: 2.0.0(eslint@10.8.0(jiti@2.7.0))
vite:
specifier: ^8.1.3
version: 8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)
version: 8.1.5(@types/node@26.1.2)(jiti@2.7.0)
vitest:
specifier: ^4.1.10
version: 4.1.10(@types/node@26.1.2)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0))
version: 4.1.10(@types/node@26.1.2)(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0))
packages/condition: {}
packages/core:
devDependencies:
dependencies:
'@remake/condition':
specifier: workspace:*
version: link:../condition
'@remake/data':
specifier: workspace:*
version: link:../data
'@remake/vitex':
specifier: workspace:*
version: link:../vitex
immer:
specifier: ^11.1.15
version: 11.1.15
packages/data: {}
packages/vitex: {}
thirdparty/bili-toy: {}
packages:
'@babel/code-frame@7.29.7':
@@ -187,162 +197,6 @@ packages:
'@emnapi/wasi-threads@1.2.2':
resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==}
'@esbuild/aix-ppc64@0.28.1':
resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.28.1':
resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.28.1':
resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.28.1':
resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.28.1':
resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.28.1':
resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.28.1':
resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.28.1':
resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.28.1':
resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.28.1':
resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.28.1':
resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.28.1':
resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.28.1':
resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.28.1':
resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.28.1':
resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.28.1':
resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.28.1':
resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.28.1':
resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.28.1':
resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.28.1':
resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.28.1':
resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/openharmony-arm64@0.28.1':
resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/sunos-x64@0.28.1':
resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.28.1':
resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.28.1':
resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.28.1':
resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@eslint-community/eslint-utils@4.10.1':
resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -419,11 +273,12 @@ packages:
'@mdn/browser-compat-data@6.1.5':
resolution: {integrity: sha512-PzdZZzRhcXvKB0begee28n5lvwAcinGKYuLZOVxHAZm+n7y01ddEGfdS1ZXRuVcV+ndG6mSEAE8vgudom5UjYg==}
'@napi-rs/wasm-runtime@1.1.6':
resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==}
'@napi-rs/wasm-runtime@1.2.0':
resolution: {integrity: sha512-kDoONqMa+VnZ4vvvu/ZUurpJ4gkZU57e7g69qpNgWhYcZFPUHZM2CEMKm+cG6ufDVALbjMvfmMjFVqaK7uEMnA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0}
peerDependencies:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
'@emnapi/core': ^2.0.0-alpha.3
'@emnapi/runtime': ^2.0.0-alpha.3
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
@@ -565,144 +420,6 @@ packages:
rollup:
optional: true
'@rollup/rollup-android-arm-eabi@4.62.3':
resolution: {integrity: sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.62.3':
resolution: {integrity: sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.62.3':
resolution: {integrity: sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.62.3':
resolution: {integrity: sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-freebsd-arm64@4.62.3':
resolution: {integrity: sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==}
cpu: [arm64]
os: [freebsd]
'@rollup/rollup-freebsd-x64@4.62.3':
resolution: {integrity: sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==}
cpu: [x64]
os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.62.3':
resolution: {integrity: sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.62.3':
resolution: {integrity: sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.62.3':
resolution: {integrity: sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.62.3':
resolution: {integrity: sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.62.3':
resolution: {integrity: sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.62.3':
resolution: {integrity: sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==}
cpu: [loong64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-ppc64-gnu@4.62.3':
resolution: {integrity: sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.62.3':
resolution: {integrity: sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==}
cpu: [ppc64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.62.3':
resolution: {integrity: sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.62.3':
resolution: {integrity: sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.62.3':
resolution: {integrity: sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.62.3':
resolution: {integrity: sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.62.3':
resolution: {integrity: sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-openbsd-x64@4.62.3':
resolution: {integrity: sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==}
cpu: [x64]
os: [openbsd]
'@rollup/rollup-openharmony-arm64@4.62.3':
resolution: {integrity: sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==}
cpu: [arm64]
os: [openharmony]
'@rollup/rollup-win32-arm64-msvc@4.62.3':
resolution: {integrity: sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==}
cpu: [arm64]
os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.62.3':
resolution: {integrity: sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-gnu@4.62.3':
resolution: {integrity: sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==}
cpu: [x64]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.62.3':
resolution: {integrity: sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==}
cpu: [x64]
os: [win32]
'@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
@@ -947,8 +664,8 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
acorn@8.17.0:
resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==}
acorn@8.18.0:
resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==}
engines: {node: '>=0.4.0'}
hasBin: true
@@ -1010,8 +727,8 @@ packages:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22}
baseline-browser-mapping@2.11.4:
resolution: {integrity: sha512-s4+sLr9mZ/CyqeRritFeYV/Zx73OAtmaHn6kkBS1XRoJn1hrg3xIDUcpicAEX68tkcIN0iBCgti31C8zxtkhsQ==}
baseline-browser-mapping@2.11.6:
resolution: {integrity: sha512-69D/imtToCsIcAl8WBS2YaRwA4jO/j0HhU+hELqMEu9f54MoUtI6+XH5mrKU8rEFNEk/Ui1I2MK4/JkWacclGw==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -1126,8 +843,8 @@ packages:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
electron-to-chromium@1.5.396:
resolution: {integrity: sha512-yHiw2Y3C3H9U6TMbOfoWK/BPreiOPXRfTWPBwQBoZG6/8TB6eOPnsy5oaRYuatR7Fw2SJ4kKforgufeo7fq0EQ==}
electron-to-chromium@1.5.398:
resolution: {integrity: sha512-AsvhAxopJGh6museTDMIjn6JpDYOfgu4RLlygomt87MUwBUqTfd/1EiPtx10/LZE8xpTvkP2E9Gafq7lkLtodQ==}
entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
@@ -1172,11 +889,6 @@ packages:
resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==}
engines: {node: '>= 0.4'}
esbuild@0.28.1:
resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
engines: {node: '>=18'}
hasBin: true
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
@@ -1399,6 +1111,9 @@ packages:
resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==}
engines: {node: '>= 4'}
immer@11.1.15:
resolution: {integrity: sha512-VrNANlmnWQnh5COXIIOQXM9oOJw7naGKlBT74ZOOR6lpVXc3gFEu9FJLDFcpCJ2j+NWr8TIwtWD//T6ZX6TKiQ==}
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
@@ -1652,8 +1367,8 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
minimatch@10.2.5:
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
minimatch@10.2.6:
resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==}
engines: {node: 18 || 20 || >=22}
minimatch@3.1.5:
@@ -1761,8 +1476,8 @@ packages:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'}
postcss@8.5.23:
resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==}
postcss@8.5.24:
resolution: {integrity: sha512-8RyVklq0owXUTa4xlpzu4l9AaVKIdQvAcOHZWaMh98HgySsUtxRVf/chRe3dsSLqb6i40BzGRzEUddRaI+9TSw==}
engines: {node: ^10 || ^12 || >=14}
preact@10.29.7:
@@ -1805,11 +1520,6 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
rollup@4.62.3:
resolution: {integrity: sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
safe-array-concat@1.1.4:
resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==}
engines: {node: '>=0.4'}
@@ -1929,8 +1639,8 @@ packages:
resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
engines: {node: '>=12.0.0'}
tinyrainbow@3.1.0:
resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
tinyrainbow@3.1.1:
resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==}
engines: {node: '>=14.0.0'}
ts-api-utils@2.5.0:
@@ -2277,84 +1987,6 @@ snapshots:
tslib: 2.8.1
optional: true
'@esbuild/aix-ppc64@0.28.1':
optional: true
'@esbuild/android-arm64@0.28.1':
optional: true
'@esbuild/android-arm@0.28.1':
optional: true
'@esbuild/android-x64@0.28.1':
optional: true
'@esbuild/darwin-arm64@0.28.1':
optional: true
'@esbuild/darwin-x64@0.28.1':
optional: true
'@esbuild/freebsd-arm64@0.28.1':
optional: true
'@esbuild/freebsd-x64@0.28.1':
optional: true
'@esbuild/linux-arm64@0.28.1':
optional: true
'@esbuild/linux-arm@0.28.1':
optional: true
'@esbuild/linux-ia32@0.28.1':
optional: true
'@esbuild/linux-loong64@0.28.1':
optional: true
'@esbuild/linux-mips64el@0.28.1':
optional: true
'@esbuild/linux-ppc64@0.28.1':
optional: true
'@esbuild/linux-riscv64@0.28.1':
optional: true
'@esbuild/linux-s390x@0.28.1':
optional: true
'@esbuild/linux-x64@0.28.1':
optional: true
'@esbuild/netbsd-arm64@0.28.1':
optional: true
'@esbuild/netbsd-x64@0.28.1':
optional: true
'@esbuild/openbsd-arm64@0.28.1':
optional: true
'@esbuild/openbsd-x64@0.28.1':
optional: true
'@esbuild/openharmony-arm64@0.28.1':
optional: true
'@esbuild/sunos-x64@0.28.1':
optional: true
'@esbuild/win32-arm64@0.28.1':
optional: true
'@esbuild/win32-ia32@0.28.1':
optional: true
'@esbuild/win32-x64@0.28.1':
optional: true
'@eslint-community/eslint-utils@4.10.1(eslint@10.8.0(jiti@2.7.0))':
dependencies:
eslint: 10.8.0(jiti@2.7.0)
@@ -2366,7 +1998,7 @@ snapshots:
dependencies:
'@eslint/object-schema': 3.0.5
debug: 4.4.3
minimatch: 10.2.5
minimatch: 10.2.6
transitivePeerDependencies:
- supports-color
@@ -2426,7 +2058,7 @@ snapshots:
'@mdn/browser-compat-data@6.1.5': {}
'@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)':
'@napi-rs/wasm-runtime@1.2.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)':
dependencies:
'@emnapi/core': 1.11.1
'@emnapi/runtime': 1.11.1
@@ -2439,19 +2071,19 @@ snapshots:
'@oxc-project/types@0.139.0': {}
'@preact/preset-vite@2.10.6(@babel/core@7.29.7)(preact@10.29.7)(rollup@4.62.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0))':
'@preact/preset-vite@2.10.6(@babel/core@7.29.7)(preact@10.29.7)(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0))':
dependencies:
'@babel/core': 7.29.7
'@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7)
'@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7)
'@prefresh/vite': 2.4.12(preact@10.29.7)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0))
'@rollup/pluginutils': 5.4.0(rollup@4.62.3)
'@prefresh/vite': 2.4.12(preact@10.29.7)(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0))
'@rollup/pluginutils': 5.4.0
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.7)
debug: 4.4.3
magic-string: 0.30.21
picocolors: 1.1.1
vite: 8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)
vite-prerender-plugin: 0.5.13(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0))
vite: 8.1.5(@types/node@26.1.2)(jiti@2.7.0)
vite-prerender-plugin: 0.5.13(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0))
zimmerframe: 1.1.4
transitivePeerDependencies:
- preact
@@ -2466,7 +2098,7 @@ snapshots:
'@prefresh/utils@1.2.1': {}
'@prefresh/vite@2.4.12(preact@10.29.7)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0))':
'@prefresh/vite@2.4.12(preact@10.29.7)(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0))':
dependencies:
'@babel/core': 7.29.7
'@prefresh/babel-plugin': 0.5.3
@@ -2474,7 +2106,7 @@ snapshots:
'@prefresh/utils': 1.2.1
'@rollup/pluginutils': 4.2.1
preact: 10.29.7
vite: 8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)
vite: 8.1.5(@types/node@26.1.2)(jiti@2.7.0)
transitivePeerDependencies:
- supports-color
@@ -2518,7 +2150,7 @@ snapshots:
dependencies:
'@emnapi/core': 1.11.1
'@emnapi/runtime': 1.11.1
'@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)
'@napi-rs/wasm-runtime': 1.2.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)
optional: true
'@rolldown/binding-win32-arm64-msvc@1.1.5':
@@ -2534,88 +2166,11 @@ snapshots:
estree-walker: 2.0.2
picomatch: 2.3.2
'@rollup/pluginutils@5.4.0(rollup@4.62.3)':
'@rollup/pluginutils@5.4.0':
dependencies:
'@types/estree': 1.0.9
estree-walker: 2.0.2
picomatch: 4.0.5
optionalDependencies:
rollup: 4.62.3
'@rollup/rollup-android-arm-eabi@4.62.3':
optional: true
'@rollup/rollup-android-arm64@4.62.3':
optional: true
'@rollup/rollup-darwin-arm64@4.62.3':
optional: true
'@rollup/rollup-darwin-x64@4.62.3':
optional: true
'@rollup/rollup-freebsd-arm64@4.62.3':
optional: true
'@rollup/rollup-freebsd-x64@4.62.3':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.62.3':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.62.3':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.62.3':
optional: true
'@rollup/rollup-linux-arm64-musl@4.62.3':
optional: true
'@rollup/rollup-linux-loong64-gnu@4.62.3':
optional: true
'@rollup/rollup-linux-loong64-musl@4.62.3':
optional: true
'@rollup/rollup-linux-ppc64-gnu@4.62.3':
optional: true
'@rollup/rollup-linux-ppc64-musl@4.62.3':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.62.3':
optional: true
'@rollup/rollup-linux-riscv64-musl@4.62.3':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.62.3':
optional: true
'@rollup/rollup-linux-x64-gnu@4.62.3':
optional: true
'@rollup/rollup-linux-x64-musl@4.62.3':
optional: true
'@rollup/rollup-openbsd-x64@4.62.3':
optional: true
'@rollup/rollup-openharmony-arm64@4.62.3':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.62.3':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.62.3':
optional: true
'@rollup/rollup-win32-x64-gnu@4.62.3':
optional: true
'@rollup/rollup-win32-x64-msvc@4.62.3':
optional: true
'@standard-schema/spec@1.1.0': {}
@@ -2712,7 +2267,7 @@ snapshots:
'@typescript-eslint/types': 8.65.0
'@typescript-eslint/visitor-keys': 8.65.0
debug: 4.4.3
minimatch: 10.2.5
minimatch: 10.2.6
semver: 7.8.5
tinyglobby: 0.2.17
ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2)
@@ -2807,19 +2362,19 @@ snapshots:
'@vitest/spy': 4.1.10
'@vitest/utils': 4.1.10
chai: 6.2.2
tinyrainbow: 3.1.0
tinyrainbow: 3.1.1
'@vitest/mocker@4.1.10(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0))':
'@vitest/mocker@4.1.10(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0))':
dependencies:
'@vitest/spy': 4.1.10
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)
vite: 8.1.5(@types/node@26.1.2)(jiti@2.7.0)
'@vitest/pretty-format@4.1.10':
dependencies:
tinyrainbow: 3.1.0
tinyrainbow: 3.1.1
'@vitest/runner@4.1.10':
dependencies:
@@ -2839,13 +2394,13 @@ snapshots:
dependencies:
'@vitest/pretty-format': 4.1.10
convert-source-map: 2.0.0
tinyrainbow: 3.1.0
tinyrainbow: 3.1.1
acorn-jsx@5.3.2(acorn@8.17.0):
acorn-jsx@5.3.2(acorn@8.18.0):
dependencies:
acorn: 8.17.0
acorn: 8.18.0
acorn@8.17.0: {}
acorn@8.18.0: {}
ajv@6.15.0:
dependencies:
@@ -2931,7 +2486,7 @@ snapshots:
balanced-match@4.0.4: {}
baseline-browser-mapping@2.11.4: {}
baseline-browser-mapping@2.11.6: {}
boolbase@1.0.0: {}
@@ -2946,9 +2501,9 @@ snapshots:
browserslist@4.28.7:
dependencies:
baseline-browser-mapping: 2.11.4
baseline-browser-mapping: 2.11.6
caniuse-lite: 1.0.30001806
electron-to-chromium: 1.5.396
electron-to-chromium: 1.5.398
node-releases: 2.0.51
update-browserslist-db: 1.2.3(browserslist@4.28.7)
@@ -3063,7 +2618,7 @@ snapshots:
es-errors: 1.3.0
gopd: 1.2.0
electron-to-chromium@1.5.396: {}
electron-to-chromium@1.5.398: {}
entities@4.5.0: {}
@@ -3180,36 +2735,6 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
esbuild@0.28.1:
optionalDependencies:
'@esbuild/aix-ppc64': 0.28.1
'@esbuild/android-arm': 0.28.1
'@esbuild/android-arm64': 0.28.1
'@esbuild/android-x64': 0.28.1
'@esbuild/darwin-arm64': 0.28.1
'@esbuild/darwin-x64': 0.28.1
'@esbuild/freebsd-arm64': 0.28.1
'@esbuild/freebsd-x64': 0.28.1
'@esbuild/linux-arm': 0.28.1
'@esbuild/linux-arm64': 0.28.1
'@esbuild/linux-ia32': 0.28.1
'@esbuild/linux-loong64': 0.28.1
'@esbuild/linux-mips64el': 0.28.1
'@esbuild/linux-ppc64': 0.28.1
'@esbuild/linux-riscv64': 0.28.1
'@esbuild/linux-s390x': 0.28.1
'@esbuild/linux-x64': 0.28.1
'@esbuild/netbsd-arm64': 0.28.1
'@esbuild/netbsd-x64': 0.28.1
'@esbuild/openbsd-arm64': 0.28.1
'@esbuild/openbsd-x64': 0.28.1
'@esbuild/openharmony-arm64': 0.28.1
'@esbuild/sunos-x64': 0.28.1
'@esbuild/win32-arm64': 0.28.1
'@esbuild/win32-ia32': 0.28.1
'@esbuild/win32-x64': 0.28.1
optional: true
escalade@3.2.0: {}
escape-string-regexp@4.0.0: {}
@@ -3313,7 +2838,7 @@ snapshots:
imurmurhash: 0.1.4
is-glob: 4.0.3
json-stable-stringify-without-jsonify: 1.0.1
minimatch: 10.2.5
minimatch: 10.2.6
natural-compare: 1.4.0
optionator: 0.9.4
optionalDependencies:
@@ -3323,8 +2848,8 @@ snapshots:
espree@11.2.0:
dependencies:
acorn: 8.17.0
acorn-jsx: 5.3.2(acorn@8.17.0)
acorn: 8.18.0
acorn-jsx: 5.3.2(acorn@8.18.0)
eslint-visitor-keys: 5.0.1
esquery@1.7.0:
@@ -3467,6 +2992,8 @@ snapshots:
ignore@7.0.6: {}
immer@11.1.15: {}
imurmurhash@0.1.4: {}
internal-slot@1.1.0:
@@ -3699,7 +3226,7 @@ snapshots:
math-intrinsics@1.1.0: {}
minimatch@10.2.5:
minimatch@10.2.6:
dependencies:
brace-expansion: 5.0.8
@@ -3809,7 +3336,7 @@ snapshots:
possible-typed-array-names@1.1.0: {}
postcss@8.5.23:
postcss@8.5.24:
dependencies:
nanoid: 3.3.16
picocolors: 1.1.1
@@ -3879,38 +3406,6 @@ snapshots:
'@rolldown/binding-win32-arm64-msvc': 1.1.5
'@rolldown/binding-win32-x64-msvc': 1.1.5
rollup@4.62.3:
dependencies:
'@types/estree': 1.0.9
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.62.3
'@rollup/rollup-android-arm64': 4.62.3
'@rollup/rollup-darwin-arm64': 4.62.3
'@rollup/rollup-darwin-x64': 4.62.3
'@rollup/rollup-freebsd-arm64': 4.62.3
'@rollup/rollup-freebsd-x64': 4.62.3
'@rollup/rollup-linux-arm-gnueabihf': 4.62.3
'@rollup/rollup-linux-arm-musleabihf': 4.62.3
'@rollup/rollup-linux-arm64-gnu': 4.62.3
'@rollup/rollup-linux-arm64-musl': 4.62.3
'@rollup/rollup-linux-loong64-gnu': 4.62.3
'@rollup/rollup-linux-loong64-musl': 4.62.3
'@rollup/rollup-linux-ppc64-gnu': 4.62.3
'@rollup/rollup-linux-ppc64-musl': 4.62.3
'@rollup/rollup-linux-riscv64-gnu': 4.62.3
'@rollup/rollup-linux-riscv64-musl': 4.62.3
'@rollup/rollup-linux-s390x-gnu': 4.62.3
'@rollup/rollup-linux-x64-gnu': 4.62.3
'@rollup/rollup-linux-x64-musl': 4.62.3
'@rollup/rollup-openbsd-x64': 4.62.3
'@rollup/rollup-openharmony-arm64': 4.62.3
'@rollup/rollup-win32-arm64-msvc': 4.62.3
'@rollup/rollup-win32-ia32-msvc': 4.62.3
'@rollup/rollup-win32-x64-gnu': 4.62.3
'@rollup/rollup-win32-x64-msvc': 4.62.3
fsevents: 2.3.3
optional: true
safe-array-concat@1.1.4:
dependencies:
call-bind: 1.0.9
@@ -4067,7 +3562,7 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.5)
picomatch: 4.0.5
tinyrainbow@3.1.0: {}
tinyrainbow@3.1.1: {}
ts-api-utils@2.5.0(@typescript/typescript6@6.0.2):
dependencies:
@@ -4157,7 +3652,7 @@ snapshots:
dependencies:
punycode: 2.3.1
vite-prerender-plugin@0.5.13(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)):
vite-prerender-plugin@0.5.13(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0)):
dependencies:
kolorist: 1.8.0
magic-string: 0.30.21
@@ -4165,25 +3660,24 @@ snapshots:
simple-code-frame: 1.3.0
source-map: 0.7.6
stack-trace: 1.0.0
vite: 8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)
vite: 8.1.5(@types/node@26.1.2)(jiti@2.7.0)
vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0):
vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0):
dependencies:
lightningcss: 1.33.0
picomatch: 4.0.5
postcss: 8.5.23
postcss: 8.5.24
rolldown: 1.1.5
tinyglobby: 0.2.17
optionalDependencies:
'@types/node': 26.1.2
esbuild: 0.28.1
fsevents: 2.3.3
jiti: 2.7.0
vitest@4.1.10(@types/node@26.1.2)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)):
vitest@4.1.10(@types/node@26.1.2)(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0)):
dependencies:
'@vitest/expect': 4.1.10
'@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0))
'@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@26.1.2)(jiti@2.7.0))
'@vitest/pretty-format': 4.1.10
'@vitest/runner': 4.1.10
'@vitest/snapshot': 4.1.10
@@ -4199,8 +3693,8 @@ snapshots:
tinybench: 2.9.0
tinyexec: 1.2.4
tinyglobby: 0.2.17
tinyrainbow: 3.1.0
vite: 8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)
tinyrainbow: 3.1.1
vite: 8.1.5(@types/node@26.1.2)(jiti@2.7.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 26.1.2
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "@remake/condition",
"name": "@remake/thirdparty-bili-toy",
"type": "module",
"version": "3.0.0",
"main": "./index.ts",
+484 -175
View File
@@ -1,194 +1,503 @@
declare namespace toy {
/**
* Toy JS SDK 类型声明(面向创作者)
*
* 用法:把本文件放进你的 Toy 项目(如 `types/toy.d.ts`),TypeScript 会自动加载,
* 无需 import 即可获得 `window.toy` 的类型检查与补全。
*
* 前置:页面 `<head>` 中引入
* <script src="//s1.hdslb.com/bfs/seed/toy/app/sdk/toy-sdk.js"></script>
* 加载后 SDK 把实例挂到全局 `window.toy`,所有方法返回 Promise。
*
* 通用约定:
* - 所有方法抛出的 Errormessage 统一带 `[ToySDK]` 前缀。
* - 数据类能力(用户 / 作者 / 视频互动)不抛错时通过 `status` 字段表达结果,
* 需要先判断 `status === 'ok'` 再读 `data` / `items`。
* - 云存储与排行榜失败时 Promise reject,需要 try/catch。
*/
declare namespace ToySDK {
// ---------------------------------------------------------------------------
// 页面跳转
// ---------------------------------------------------------------------------
/** 站内跳转的目标页面类型。 */
type NavigateType = 'video' | 'space' | 'search' | 'opus' | 'tribee' | 'toy'
interface NavigateReq {
/** 目标页面类型。 */
type: NavigateType
/**
* B站 Toy 平台开放能力名称联合类型
* 资源标识,随 `type` 变化:
* - video: BV 号,如 `BV1Hh411S7Ys`
* - space: 用户 mid
* - search: 搜索关键词(SDK 内部会做 URL 编码)
* - opus: 图文 / 动态 id
* - tribee: 小站 id
* - toy: toy id
*/
type Ability =
| 'navigate'
| 'saveImageToAlbum'
| 'closeBrowser'
| 'getUserProfile'
| 'reportAction'
| 'getCloudStorage'
| 'setCloudStorage'
| 'removeCloudStorage'
| 'getAuthorProfile'
| 'getAuthorVideos'
| 'getAuthorRelation'
| 'getVideoUserActions'
| 'submitScore'
| 'getRankList'
| 'getMyRank'
id: string
/** 额外查询参数,拼接到目标 URL 上透传给目标页面。 */
extra?: Record<string, string>
}
// ---------------------------------------------------------------------------
// 保存图片
// ---------------------------------------------------------------------------
/** `url` 与 `base64Data` 二选一,两者都不传则由客户端返回错误。 */
interface SaveImageReq {
/** 网络图片地址。 */
url?: string
/** base64 图片数据。 */
base64Data?: string
/** 申请相册权限时展示给用户的提示文案。 */
hintMsg?: string
}
interface SaveImageResp {
/** 保存后的本地文件路径,由客户端返回。 */
localPath: string
}
interface ReportActionReq {
/** UP 主自定义的动作标识。 */
userEventId: string
}
// ---------------------------------------------------------------------------
// 用户信息
// ---------------------------------------------------------------------------
interface UserProfileResp {
/** 头像地址,SDK 已统一归一化为 https 与 p0 CDN 域名。 */
avatar: string
/** 昵称。 */
nickname: string
}
// ---------------------------------------------------------------------------
// 数据类能力的状态枚举
// ---------------------------------------------------------------------------
/**
* 数据类能力的整体状态。
* - `ok`: 成功
* - `partial`: 批量请求部分成功,逐项状态见各 item 的 `status`
* - `unauthorized`: 未登录
* - `denied`: 用户拒绝了数据使用确认
* - `unsupported`: 当前环境不支持(如外部手机浏览器,SDK 会引导打开 B站 App)
* - `toy_context_unavailable`: 拿不到当前 toy 上下文
* - `author_mismatch`: 请求的资源不属于当前 Toy 作者
* - `video_not_found`: 视频不存在
* - `video_invisible`: 视频对当前用户不可见
* - `unavailable`: 依赖服务不可用
* - `invalid_argument`: 参数非法
*/
type ToyDataStatus =
| 'ok'
| 'partial'
| 'unauthorized'
| 'denied'
| 'unsupported'
| 'toy_context_unavailable'
| 'author_mismatch'
| 'video_not_found'
| 'video_invisible'
| 'unavailable'
| 'invalid_argument'
/** 批量结果中单项的状态:与 `ToyDataStatus` 相同,但不会是 `partial`。 */
type ToyItemStatus = Exclude<ToyDataStatus, 'partial'>
// ---------------------------------------------------------------------------
// 作者资料
// ---------------------------------------------------------------------------
/** 作者认证信息。`role` / `type` 为后端数字枚举,SDK 未定义其取值含义。 */
interface AuthorCertification {
role: number
title: string
description: string
type: number
}
/** 充电聚合信息。 */
interface ChargingSummary {
/** 充电人数。 */
count: number
display?: {
show: boolean
text?: string
}
}
/** 粉丝勋章配置。 */
interface FanMedalConfig {
/** 勋章名称。 */
name: string
/** 是否已开启粉丝勋章。 */
enabled: boolean
/** 各等级的亲密度区间;最高等级无上限时 `maxIntimacy` 缺省。 */
levels: Array<{
level: number
minIntimacy: number
maxIntimacy?: number
}>
}
interface AuthorProfile {
nickname: string
avatar: string
/** 个性签名。 */
sign: string
/** 未认证时缺省。 */
certification?: AuthorCertification
/** 关注数。 */
following: number
/** 粉丝数。 */
follower: number
/** 稿件数。 */
archiveCount: number
/** 未开通充电时缺省。 */
charging?: ChargingSummary
/** 未配置粉丝勋章时缺省。 */
fanMedal?: FanMedalConfig
/** 生日,时间戳;未公开时缺省。 */
birthday?: number
}
interface AuthorProfileResp {
status: ToyDataStatus
/** `status` 非 `ok` 时缺省。 */
data?: AuthorProfile
}
// ---------------------------------------------------------------------------
// 作者视频
// ---------------------------------------------------------------------------
/** 视频引用:每项只能传 `aid` 或 `bvid` 之一,同时传或都不传会本地抛错。 */
type AuthorVideoRef =
| { aid: number; bvid?: never }
| { bvid: string; aid?: never }
interface AuthorVideosReq {
/** 150 项;SDK 会按 aid/bvid 去重并保留首次出现顺序。 */
videos: AuthorVideoRef[]
}
interface AuthorVideo {
aid: number
bvid: string
title: string
/** 封面地址,SDK 已归一化 CDN 域名。 */
cover: string
description: string
/** 发布时间,时间戳。 */
publishTime: number
/** 总时长,单位由后端定义。 */
duration: number
/** 分区名称。 */
partition?: string
/** 分 P 列表。 */
pages: Array<{
page: number
title: string
duration: number
}>
/** 稿件统计数据。 */
stat: {
view: number
like: number
coin: number
favorite: number
share: number
comment: number
danmaku: number
}
/** 付费相关标记。 */
pay: {
/** 是否充电专属。 */
chargingPay: boolean
/** 是否付费稿件。 */
paid: boolean
}
/** 所属合集 id;不属于任何合集时缺省。 */
seasonId?: number
/** 排行信息;无排行数据时缺省。 */
rank?: {
now: number
highest: number
}
}
interface AuthorVideoItem {
/** 回显本次请求传入的引用,用于与请求项对应。 */
ref: AuthorVideoRef
status: ToyItemStatus
/** `status` 非 `ok` 时缺省(如非当前作者、视频不可见)。 */
data?: AuthorVideo
}
interface AuthorVideosResp {
/** 整体状态;部分项失败时为 `partial`。 */
status: ToyDataStatus
items: AuthorVideoItem[]
}
// ---------------------------------------------------------------------------
// 作者互动关系
// ---------------------------------------------------------------------------
interface AuthorRelation {
/** 当前访问用户是否已关注该作者。 */
isFollowing: boolean
/** 当前访问用户是否就是该 Toy 作者本人。 */
isAuthor: boolean
/** 是否为老粉。 */
isOldFan: boolean
/** 是否持有该作者的粉丝勋章。 */
hasFanMedal: boolean
/** 勋章名称;无勋章时缺省。 */
fanMedalName?: string
/** 勋章等级;无勋章时缺省。 */
fanMedalLevel?: number
/** 勋章是否处于点亮状态;无勋章时缺省。 */
isFanMedalActive?: boolean
/** 当前是否正在对该作者进行包月充电。 */
isCharging: boolean
/** 关注时间,时间戳;未关注时缺省。 */
followTime?: number
}
interface AuthorRelationResp {
status: ToyDataStatus
/** `status` 非 `ok` 时缺省。 */
data?: AuthorRelation
}
// ---------------------------------------------------------------------------
// 视频互动数据
// ---------------------------------------------------------------------------
interface VideoUserActionsReq {
/** 150 个正整数 aid;SDK 会去重并保留首次出现顺序。 */
aids: number[]
}
interface VideoUserActionItem {
aid: number
status: ToyItemStatus
/** 是否已点赞;`status` 非 `ok` 时缺省。 */
liked?: boolean
/** 已投币数;`status` 非 `ok` 时缺省。 */
coinCount?: number
/** 是否已收藏;`status` 非 `ok` 时缺省。 */
favorited?: boolean
}
interface VideoUserActionsResp {
/** 整体状态;部分项失败时为 `partial`。 */
status: ToyDataStatus
items: VideoUserActionItem[]
}
// ---------------------------------------------------------------------------
// 排行榜
// ---------------------------------------------------------------------------
/** 榜单周期:总榜(永久)/ 月 / 周 / 日。 */
type RankPeriod = 'all' | 'month' | 'week' | 'day'
interface SubmitScoreReq {
/** 榜位,固定 1 / 2 / 3(含义由 toy 自定义),不传默认 1;非法值本地抛错。 */
board?: number
/**
* 本次成绩的绝对分数,不是增量。整数,取值范围 -16777216 ~ 16777215
* 允许 0 与负数;超出范围本地抛错。服务端只保留该榜位的历史最高分。
*/
score: number
}
interface SubmitScoreResp {
/** 我的总榜(all)历史最高分,已合并本次提交。 */
score: number
}
interface RankListReq {
/** 榜位,固定 1 / 2 / 3,不传默认 1。 */
board?: number
/** 周期,不传按总榜 `all`。 */
period?: RankPeriod
/** 返回名次数量;不传或超上限按后端默认(≤100)。 */
limit?: number
}
/** 榜单单行:名次 + 历史最高分 + 展示用昵称/头像,不含 uid。 */
interface RankItem {
rank: number
score: number
nickname: string
/** 头像地址,SDK 已归一化 CDN 域名。 */
avatar: string
}
interface MyRankReq {
/** 榜位,固定 1 / 2 / 3,不传默认 1。 */
board?: number
/** 周期,不传按总榜 `all`。 */
period?: RankPeriod
}
interface MyRankResp {
/** 是否已上榜。分数允许 0 / 负,判断是否上榜必须用本字段,不能用 `score`。 */
ranked: boolean
/** 我的名次,从 1 起,唯一不并列(同分先达成者靠前);未上榜为 0。 */
rank: number
/** 我的历史最高分;未上榜为 0。 */
score: number
}
// ---------------------------------------------------------------------------
// 媒体能力
// ---------------------------------------------------------------------------
interface MediaRelayOptions {
/** 摄像头朝向,不传默认使用前置摄像头。 */
facingMode?: 'user' | 'environment'
}
// ---------------------------------------------------------------------------
// window.toy 的公开 API 面
// ---------------------------------------------------------------------------
interface Toy {
/**
* 判断当前环境是否支持指定能力。传能力名(如 `'saveImageToAlbum'`)即可,
* 带不带 `toy.` 前缀都能匹配。
*
* 端外 Web 不支持 `saveImageToAlbum` / `closeBrowser`,其余能力两端一致。
*/
isSupport(ability: string): Promise<boolean>
/**
* 判断当前 B站 App 宿主环境是否支持指定开放能力
* 跳转到指定页面。
*
* 必须在用户手势事件(如 click)中调用:SDK 会检查 `navigator.userActivation`
* 无有效用户激活时抛错。端内走 JSB 原生跳转,端外用 `window.open` 新开标签页。
*/
function isSupport(ability: Ability): Promise<boolean>
/** 跨页面/App组件跳转配置参数 */
type NavigateRequest = {
/** 目标页面类型:video(视频), space(空间), search(搜索), opus(图文动态), tribee(社区), toy(其它小游戏) */
type: 'video' | 'space' | 'search' | 'opus' | 'tribee' | 'toy'
/** 目标资源唯一标识 ID,如视频 BV 号、用户 mid、动态 id、游戏 id */
id: string
/** 额外附加参数,会作为 Query 或者是透传参数传递给目标承载页面 */
extra?: Record<string, string>
}
/**
* 跳转到指定 B站 App 原生或 H5 页面(注意:必须由用户手势或点击事件同步触发)
*/
function navigate(req: NavigateRequest): Promise<void>
/** 保存图片到相册的参数约束 */
type SaveImageToAlbumRequest = (
| {
/** 网络图片的绝对 URL 地址 */
url: string
base64?: never
}
| {
/** 带有 Data URI 前缀或纯 base64 的图片字符数据,体积最大硬限制 2M */
base64: string
url?: never
}
) & {
/** 客户端唤起操作系统申请相册写入权限时的引导提示文案 */
hintMsg?: string
}
/**
* 保存图片到系统相册(此 API 仅在 B站 App 宿主环境内环境生效)
*/
function saveImageToAlbum(
req: SaveImageToAlbumRequest,
): Promise<{ localPath: string }>
navigate(req: NavigateReq): Promise<void>
/**
* 关闭当前的 H5/小游戏浏览器容器,返回到上一级 App 原生界面
* 保存图片到系统相册。**仅 B站 App 内可用**,Web 端调用直接抛错。
*
* Web 端请改用标准浏览器下载能力(`<a download>` 或 canvas blob URL,需用户点击触发)。
*/
function closeBrowser(): Promise<void>
saveImageToAlbum(req: SaveImageReq): Promise<SaveImageResp>
/** 用户基本个人资料返回结果 */
type UserProfile = {
/** 用户 mid */
mid: string
/** 昵称 */
nickname: string
/** 头像绝对 URL 地址 */
avatar: string
/** 性别: 0-保密, 1-男, 2-女 */
gender: 0 | 1 | 2
}
/**
* 唤起 B站 原生授权弹窗,获取当前登录用户的公开个人资料
*/
function getUserProfile(): Promise<UserProfile>
/** 行为汇报参数配置 */
type ReportActionRequest = {
/** 行为埋点事件名/动作名 */
action: string
/** 汇报携带的属性字典 */
label?: Record<string, string | number>
}
/**
* 向 B站 开放平台数仓上报当前玩家的游戏行为埋点数据
*/
function reportAction(req: ReportActionRequest): Promise<void>
/** 获取云存储数据(托管数据)*/
function getCloudStorage<K extends string[]>(
keys?: [...K],
): Promise<{ [P in K[number]]?: string }>
/** 设置/写入云存储数据 */
function setCloudStorage(items: Record<string, string>): Promise<void>
/** 移除指定的云存储键值对 */
function removeCloudStorage(req: string[]): Promise<void>
/** UP主/作者档案资料 */
type AuthorProfile = {
mid: string
name: string
face: string
fans: number
}
/** 获取关联当前活动/游戏的UP主详细档案 */
function getAuthorProfile(): Promise<AuthorProfile>
/** 视频资产简单模型 */
type VideoItem = {
bvid: string
title: string
pic: string
play: number
}
/** 获取当前活动/游戏的关联视频列表 */
function getAuthorVideos(req: {
page: number
pageSize: number
}): Promise<{ list: VideoItem[]; total: number }>
/** 玩家与该关联UP主的关系状态 */
type AuthorRelation = {
/** 是否已关注该UP主 */
isFollowing: boolean
/** 是否是该UP主的特粉/大航海成员 */
isVipRelation: boolean
}
/** 获取当前登录玩家与目标UP主之间的社交关注链状态 */
function getAuthorRelation(): Promise<AuthorRelation>
/** 用户针对某条视频的互动行为状态 */
type VideoUserActions = {
like: boolean // 是否点赞
coin: boolean // 是否投币
fav: boolean // 是否收藏
share: boolean // 是否分享
}
/** 获取用户针对指定关联视频的点赞、投币、收藏、分享(三连)等原生行为状态 */
function getVideoUserActions(req: {
bvid: string
}): Promise<VideoUserActions>
/** 排行榜单项得分模型 */
type RankItem = {
rank: number
mid: string
nickname: string
avatar: string
score: number
}
/** 提交积分排行榜得分参数 */
type SubmitScoreRequest = {
/** 榜单唯一标识 ID */
leaderboardId: string
/** 当前局内取得的纯数字分数 */
score: number
/** 额外附加的自定义上下文字符串(如关卡详情等) */
extra?: string
}
/**
* 提交当前玩家的得分到 B站 开放平台官方托管的活动排行榜
*/
function submitScore(
req: SubmitScoreRequest,
): Promise<{ isNewRecord: boolean }>
/** 关闭当前 WebView 容器。**仅 B站 App 内可用**,Web 端调用直接抛错。 */
closeBrowser(): Promise<void>
/**
* 获取指定官方托管排行榜的分数列表
* 获取当前登录用户的头像与昵称。
*
* 首次调用需由用户手势触发,并由平台展示固定的用户数据确认弹窗(Toy 不能自定义弹窗内容);
* 用户拒绝、未登录或在外部手机浏览器中调用时 Promise reject(外部浏览器会先引导打开 B站 App)。
*/
function getRankList(req: {
leaderboardId: string
page: number
pageSize: number
}): Promise<{ list: RankItem[]; total: number }>
getUserProfile(): Promise<UserProfileResp>
/** 上报 UP 主自定义的用户动作。 */
reportAction(req: ReportActionReq): Promise<void>
/**
* 获取当前登录玩家自己在指定排行榜中的实时名次、分数等信息
* 获取当前 Toy 作者的公开资料、账号统计、稿件数、充电聚合与粉丝勋章配置。
* 不能指定作者,固定取当前 Toy 的作者。
*/
function getMyRank(req: { leaderboardId: string }): Promise<RankItem>
getAuthorProfile(): Promise<AuthorProfileResp>
/**
* 批量获取当前 Toy 作者的视频公开信息。
* 非当前作者或对当前用户不可见的视频,对应 item 只返回 `status`,不含 `data`。
*/
getAuthorVideos(req: AuthorVideosReq): Promise<AuthorVideosResp>
/**
* 获取当前访问用户与当前 Toy 作者的关注、老粉、粉丝勋章状态,
* 以及当前是否正在对该作者进行包月充电。
*
* 只校验登录态,不触发用户数据确认弹窗。外部手机浏览器返回 `status: 'unsupported'`
* 并引导打开 B站 App。
*/
getAuthorRelation(): Promise<AuthorRelationResp>
/**
* 获取当前访问用户对当前作者视频的点赞、投币、收藏状态。
*
* 只校验登录态,不触发用户数据确认弹窗。外部手机浏览器返回
* `status: 'unsupported'` 且 `items` 为空数组。
*/
getVideoUserActions(req: VideoUserActionsReq): Promise<VideoUserActionsResp>
/**
* 读取云存储。不传或传空数组读取当前用户在该 Toy 下的全部数据;
* 未命中的 key 不出现在结果中。
*
* 需用户已登录,按「登录用户 + Toy」双维度隔离,不触发用户数据确认。
* key 不满足 `[a-zA-Z0-9_-]{1,128}` 时本地抛错。
*/
getCloudStorage(keys?: string[]): Promise<Record<string, string>>
/**
* 批量写入云存储(upsert),同 key 覆盖旧值。
*
* `items` 必须是普通对象(传数组 / 字符串 / null 会本地抛错)。
* key 只能含字母、数字、下划线、短横线且 ≤128 字节;value 为字符串,
* 字节上限由服务端校验(存对象请自行 `JSON.stringify`)。
* 单个 Toy 的 key 数量上限由服务端拦截。
*/
setCloudStorage(items: Record<string, string>): Promise<void>
/** 批量删除云存储中指定的 key。key 格式非法时本地抛错。 */
removeCloudStorage(keys: string[]): Promise<void>
/**
* 上报分数到排行榜。需用户已登录,首次提交前由平台完成用户数据确认。
* 按「toy + 榜位 + 周期」隔离,同榜位只保留历史最高分,本次更低不覆盖。
*/
submitScore(req: SubmitScoreReq): Promise<SubmitScoreResp>
/**
* 读取榜单,游客可读。返回前 `limit` 名,固定从高到低;
* 同分时先达成者靠前,名次唯一、不并列。
*/
getRankList(req?: RankListReq): Promise<RankItem[]>
/** 查询我在指定榜单的排名。需用户已登录;是否上榜必须用 `ranked` 判断。 */
getMyRank(req?: MyRankReq): Promise<MyRankResp>
/**
* 申请摄像头业务授权和系统权限,并返回中继的媒体流。
* 必须在用户手势事件中调用。
*/
requestCamera(options?: MediaRelayOptions): Promise<MediaStream>
/**
* 申请麦克风业务授权和系统权限,并返回中继的媒体流。
* 不接受参数,且必须在用户手势事件中调用。
*/
requestMicrophone(): Promise<MediaStream>
/** 停止媒体中继并释放摄像头或麦克风设备。 */
stopMedia(stream: MediaStream): Promise<void>
}
}
// 全局声明。本文件是 ambient 声明文件(没有顶层 import / export),
// 放进项目后 TypeScript 自动加载,`window.toy` 与 `ToySDK.*` 均可直接使用。
interface Window {
/** 哔哩哔哩 Toy 开放平台(H5游戏容器/小程序)专属官方高级运行时 JavaScript-SDK 挂载点 */
readonly toy: typeof toy
/** Toy JS SDK 实例,由 toy-sdk.js 加载后挂载到全局。 */
toy: ToySDK.Toy
}
/** Toy JS SDK 实例(等价于 `window.toy`)。 */
declare const toy: ToySDK.Toy