* feat(plugin-md-power): add `::: encrypt` container * chore: tweak * chore: tweak * chore: tweak
This commit is contained in:
parent
78a2859398
commit
b1f996cb0e
@ -57,6 +57,7 @@ export const theme: Theme = plumeTheme({
|
||||
codeSandbox: true,
|
||||
jsfiddle: true,
|
||||
demo: true,
|
||||
encrypt: true,
|
||||
npmTo: ['pnpm', 'yarn', 'npm'],
|
||||
repl: {
|
||||
go: true,
|
||||
|
||||
@ -7,19 +7,18 @@ permalink: /en/guide/features/encryption/
|
||||
|
||||
## Encryption
|
||||
|
||||
This theme supports multiple flexible encryption methods, including **full-site encryption** and **partial encryption**.
|
||||
In this topic, various flexible encryption methods such as **full-site encryption** and **partial encryption** are supported.
|
||||
|
||||
::: warning Note
|
||||
Due to the inherent limitations of `vuepress` as a static site generator,
|
||||
the **encryption** only makes content *appear* invisible and excludes the content from being pre-rendered
|
||||
into `html` during compilation. However, the content can still be accessed from the site's source files.
|
||||
|
||||
Therefore, the **encryption** feature should not be considered **secure and reliable**.
|
||||
Due to the limitations of `vuepress` as a static site, **encryption** only makes the content *appear* invisible.
|
||||
During compilation, the content is not pre-rendered into the `html`,
|
||||
but it can still be retrieved from the site's source files.
|
||||
Therefore, the **encryption** feature should not be considered as completely secure or reliable.
|
||||
|
||||
Avoid using the **encryption feature** for content that requires **strict confidentiality**.
|
||||
:::
|
||||
|
||||
**Unlocked articles are only visible within the current session.**
|
||||
**Unlocked articles are only visible during the current session.**
|
||||
|
||||
## Enabling Encryption
|
||||
|
||||
@ -40,8 +39,8 @@ export default defineUserConfig({
|
||||
|
||||
## Full-Site Encryption
|
||||
|
||||
In some cases, you may need to encrypt the entire site. Configure full-site encryption using the `encrypt.
|
||||
global` option, then set one or more passwords using the `encrypt.admin` option.
|
||||
In some cases, you may need to encrypt the entire site.
|
||||
You can configure full-site encryption using the `encrypt.global` option and set one or more passwords with `encrypt.admin`.
|
||||
|
||||
```ts title=".vuepress/config.ts"
|
||||
export default defineUserConfig({
|
||||
@ -56,22 +55,23 @@ export default defineUserConfig({
|
||||
|
||||
## Partial Encryption
|
||||
|
||||
In most cases, you may only need to encrypt specific articles, directories, etc. Configure partial encryption using the `encrypt.rules` option.
|
||||
In most cases, you may only need to encrypt a specific article, directory, etc.
|
||||
You can configure partial encryption using the `encrypt.rules` option.
|
||||
|
||||
```ts title=".vuepress/config.ts"
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
encrypt: {
|
||||
rules: {
|
||||
// Can be relative path to md file - encrypts this file
|
||||
// Can be the relative path of an MD file to encrypt that file
|
||||
'前端/基础.md': '123456',
|
||||
// Can be directory path - encrypts all articles under this directory
|
||||
// Can be a directory path to encrypt all articles under that directory
|
||||
'/notes/vuepress-theme-plume/': '123456',
|
||||
// Can be request path - encrypts all articles under this access path
|
||||
// Can be a request path to encrypt all articles under that path
|
||||
'/vuepress-theme-plume/': '123456',
|
||||
// Can be specific page request path - encrypts this page
|
||||
// Can be a specific page's request path to encrypt that page
|
||||
'/article/f8dnci3/': '123456',
|
||||
// If starting with `^`, pages matching this regex will also be encrypted
|
||||
// If prefixed with `^`, pages matching the regex will also be encrypted
|
||||
'^/(a|b)/': '123456',
|
||||
}
|
||||
}
|
||||
@ -79,19 +79,20 @@ export default defineUserConfig({
|
||||
})
|
||||
```
|
||||
|
||||
The **keys** in `encrypt.rules` serve as matching rules, and the **values** serve as passwords for those rules. You can set one or multiple passwords.
|
||||
The **key** in `encrypt.rules` serves as the matching rule,
|
||||
and the **value** is the corresponding password (or multiple passwords) for that rule.
|
||||
|
||||
:::tip Notes
|
||||
|
||||
- Passwords must be plain strings.
|
||||
- If an entire directory is encrypted, unlocking applies to the entire directory, not individual articles within it.
|
||||
- If encrypting an entire directory, unlocking applies to the entire directory, not individual articles within it.
|
||||
- `encrypt.admin` can also be used to unlock **partially encrypted** pages.
|
||||
- After unlocking with `encrypt.admin`, the user is considered an administrator and other locked pages are unlocked by default.
|
||||
- After unlocking with `encrypt.admin`, the user is considered an admin, and all other locked pages are unlocked by default.
|
||||
:::
|
||||
|
||||
### Frontmatter
|
||||
|
||||
Use the `password` field in Markdown file `Frontmatter` to set article passwords.
|
||||
In the `Frontmatter` of a Markdown file, you can set the article's password using the `password` field.
|
||||
|
||||
```md
|
||||
---
|
||||
@ -100,7 +101,7 @@ password: 123456
|
||||
---
|
||||
```
|
||||
|
||||
You can also add the `passwordHint` option to set password hint information.
|
||||
You can also add the `passwordHint` option to provide a password hint.
|
||||
|
||||
```md
|
||||
---
|
||||
@ -114,9 +115,9 @@ passwordHint: The password is 123456
|
||||
|
||||
Click to visit [Encrypted Article, Password: 123456](/article/enx7c9s/)
|
||||
|
||||
## Related Configuration
|
||||
## Related Configurations
|
||||
|
||||
The following configurations support use in [multilingual configuration](../../config/locales.md).
|
||||
The following configurations can be used in [multilingual settings](../../config/locales.md).
|
||||
|
||||
### encryptGlobalText
|
||||
|
||||
@ -124,7 +125,7 @@ The following configurations support use in [multilingual configuration](../../c
|
||||
- **Default**: `'Only password can access this site'`
|
||||
- **Description**:
|
||||
|
||||
Prompt message for full-site encryption. Supports HTML. Useful if you want to provide contact information for visitors to obtain passwords.
|
||||
The prompt message for full-site encryption. Supports HTML. Useful if you want to provide contact information for visitors to obtain the password.
|
||||
|
||||
### encryptPageText
|
||||
|
||||
@ -132,19 +133,19 @@ The following configurations support use in [multilingual configuration](../../c
|
||||
- **Default**: `'Only password can access this page'`
|
||||
- **Description**:
|
||||
|
||||
Prompt message for partial encryption. Supports HTML. Useful if you want to provide contact information for visitors to obtain passwords.
|
||||
The prompt message for partial encryption. Supports HTML. Useful if you want to provide contact information for visitors to obtain the password.
|
||||
|
||||
### encryptButtonText
|
||||
|
||||
- **Type**: `string`
|
||||
- **Default**: `'Confirm'`
|
||||
- **Description**: Text for the confirmation button
|
||||
- **Description**: The text for the confirmation button.
|
||||
|
||||
### encryptPlaceholder
|
||||
|
||||
- **Type**: `string`
|
||||
- **Default**: `'Enter password'`
|
||||
- **Description**: Placeholder text for the password input field
|
||||
- **Description**: The placeholder text for the password input field.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
@ -111,3 +111,54 @@ This component relies entirely on the `@vuepress/plugin-llms` plugin and can onl
|
||||
|
||||
Therefore, the functionality provided by this component **is only available in the built production package**.
|
||||
:::
|
||||
|
||||
## Markup Extensions
|
||||
|
||||
### `<llm-only>`
|
||||
|
||||
You can add content in a file that is visible to LLMs but not to humans, which helps set special instructions,
|
||||
such as "Refer to basic-queries for demos," "Do not execute...", "Always use... in cases of...", etc.
|
||||
|
||||
To do this, wrap the content with the `<llm-only>` tag.
|
||||
|
||||
```md
|
||||
<llm-only>
|
||||
|
||||
## Section for LLMs
|
||||
|
||||
This content appears only in the generated LLM file and will not include the `<llm-only>` tag itself.
|
||||
|
||||
</llm-only>
|
||||
```
|
||||
|
||||
You can also use the `<llm-only>` tag inline, but note that only one `<llm-only>` tag can be included per line;
|
||||
otherwise, it will cause a parsing error.
|
||||
|
||||
```md
|
||||
Check the plugin API guide for documentation on creating plugins.
|
||||
|
||||
<llm-only>For LLMs only</llm-only>
|
||||
```
|
||||
|
||||
### `<llm-exclude>`
|
||||
|
||||
You can add content in a file that is visible to humans but not to LLMs, which is the opposite of `<llm-only>`:
|
||||
|
||||
```md
|
||||
<llm-exclude>
|
||||
|
||||
## Section for humans
|
||||
|
||||
This content will not appear in the files generated for LLMs.
|
||||
|
||||
</llm-exclude>
|
||||
```
|
||||
|
||||
You can also use the `<llm-exclude>` tag inline, but note that only one `<llm-only>` tag can be included per line;
|
||||
otherwise, it will cause a parsing error.
|
||||
|
||||
```md
|
||||
Check the plugin API guide for documentation on creating plugins.
|
||||
|
||||
<llm-exclude>For humans only</llm-exclude>
|
||||
```
|
||||
|
||||
@ -7,7 +7,7 @@ permalink: /guide/features/encryption/
|
||||
|
||||
## 加密
|
||||
|
||||
在本主题中,支持 **全站加密** 和 **部分加密** 等多种灵活的加密方式。
|
||||
在本主题中,支持 **全站加密** 、 **部分页面加密** 和 **部分内容加密** 等多种灵活的加密方式。
|
||||
|
||||
::: warning 提示
|
||||
由于 `vuepress` 是静态站点,其自身限制的原因,**加密** 仅仅只是 看起来 看不到内容,
|
||||
@ -53,7 +53,7 @@ export default defineUserConfig({
|
||||
})
|
||||
```
|
||||
|
||||
## 部分加密
|
||||
## 部分页面加密
|
||||
|
||||
大多数情况下,你可能只需需要 加密 某一篇文章、某一个目录 等。
|
||||
因此,你可以通过 `encrypt.rules` 选项配置部分加密。
|
||||
@ -110,10 +110,112 @@ passwordHint: 密码是 123456
|
||||
---
|
||||
```
|
||||
|
||||
## 示例
|
||||
### 示例
|
||||
|
||||
点击访问 [加密文章,密码:123456](/article/enx7c9s/)
|
||||
|
||||
## 部分内容加密
|
||||
|
||||
### 配置
|
||||
|
||||
部分内容加密通过 `::: encrypt` 容器实现,需要配置 `markdown.encrypt` 选项:
|
||||
|
||||
```ts title=".vuepress/config.ts"
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
markdown: {
|
||||
encrypt: true, // [!code ++]
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
还可以给 `::: encrypt` 容器设置统一的默认密码:
|
||||
|
||||
```ts title=".vuepress/config.ts"
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
markdown: {
|
||||
encrypt: {
|
||||
password: 123456, // [!code ++]
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
||||
使用 `::: encrypt` 容器,将需要加密的内容包裹起来。
|
||||
可以在容器中添加 `password` / `pwd` 属性,设置该容器的密码。
|
||||
如果没有设置密码,将使用默认密码。
|
||||
|
||||
还可以在容器上添加 `hint` 属性,设置密码提示信息。
|
||||
|
||||
```md /password="123456"/
|
||||
::: encrypt password="123456" hint="密码是连续的 6 位数"
|
||||
这是加密的内容
|
||||
:::
|
||||
```
|
||||
|
||||
::: info 密码仅有一个生效,不支持同时设置多个密码。
|
||||
:::
|
||||
|
||||
### 示例
|
||||
|
||||
**输入:**
|
||||
|
||||
```md
|
||||
::: encrypt password="123456"
|
||||
这是加密的内容
|
||||
:::
|
||||
```
|
||||
|
||||
**输出:**
|
||||
|
||||
::: encrypt password="123456"
|
||||
这是加密的内容
|
||||
:::
|
||||
|
||||
**输入:**
|
||||
|
||||
```md
|
||||
::: encrypt password="654321" hint="密码是连续的 6 位数"
|
||||
这是加密的内容2
|
||||
:::
|
||||
```
|
||||
|
||||
**输出:**
|
||||
|
||||
::: encrypt password="654321" hint="密码是连续的 6 位数"
|
||||
这是加密的内容2
|
||||
:::
|
||||
|
||||
::: warning 使用限制
|
||||
**对于被加密的内容,可以使用:**
|
||||
|
||||
- 所有标准的 markdown 语法
|
||||
- 主题提供的 大多数扩展语法,但不包括:
|
||||
- `@[demo]()` 从目录中引入的代码示例
|
||||
- `@[code]()` 从目录中引入的代码片段
|
||||
- `@[code-tree]()` 从目录中引入的代码树
|
||||
- 主题提供的 全局 vue 组件
|
||||
- 用户自定义的 全局 vue 组件
|
||||
- 被加密的内容,不能包含可执行的脚本,如有特殊交互,请通过组件实现。
|
||||
|
||||
**网络环境要求:**
|
||||
部分内容加密采用 [Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) 实现,
|
||||
因此,在 **非 HTTPS 环境** 下,将无法正常工作。
|
||||
:::
|
||||
|
||||
::: details 如果你是技术开发者,你可能需要知道的内容
|
||||
|
||||
原始 markdown 内容首先进过 markdown 渲染为 HTML 内容后,再进行加密;传输到客户端,再进行解密渲染。
|
||||
解密后的内容会被包装为一个动态的 vue 组件,html 作为 template 传给该动态组件,因此,涉及到运行时编译 template
|
||||
的内容。这导致了如果启用部分内容加密功能,那么就需要将 vue 切换到 `esm-bundler` 版本,以支持运行时编译,
|
||||
这会比默认的 `runtime-only` 版本性能差一些,体积也会增加。
|
||||
:::
|
||||
|
||||
## 相关配置
|
||||
|
||||
以下配置支持在 [多语言配置](../../config/locales.md) 中使用。
|
||||
|
||||
@ -103,3 +103,52 @@ export default defineClientConfig({
|
||||
|
||||
因此,此组件提供的功能 **仅在构建后的生产包中才可用** 。
|
||||
:::
|
||||
|
||||
## 扩展标记 (Markup)
|
||||
|
||||
### `<llm-only>`
|
||||
|
||||
你可以在文件中添加对 LLM 可见但对人类不可见的内容,这有助于设置特殊指令,
|
||||
例如 “参考 basic-queries 获取演示”、“切勿执行……”、“在……情况下始终使用……”等。
|
||||
|
||||
为此,需要使用 `<llm-only>` 标签来包裹内容。
|
||||
|
||||
```md
|
||||
<llm-only>
|
||||
|
||||
## Section for LLMs
|
||||
|
||||
此内容仅出现在生成的LLM文件中,不会包含 `<llm-only>` 标签本身。
|
||||
|
||||
</llm-only>
|
||||
```
|
||||
|
||||
也可以在单行中使用 `<llm-only>` 标签,但请注意单行时仅能包含一个 `<llm-only>` 标签,否则会导致解析错误。
|
||||
|
||||
```md
|
||||
查看插件API指南,了解创建插件的相关文档。
|
||||
|
||||
<llm-only>仅限 LLM 阅读</llm-only>
|
||||
```
|
||||
|
||||
### `<llm-exclude>`
|
||||
|
||||
你可以在文件中添加对人类可见但对LLM不可见的内容,这与 `<llm-only>` 的作用相反:
|
||||
|
||||
```md
|
||||
<llm-exclude>
|
||||
|
||||
## Section for humans
|
||||
|
||||
此内容将不会出现在为 LLMs 生成的文件中
|
||||
|
||||
</llm-exclude>
|
||||
```
|
||||
|
||||
也可以在单行中使用 `<llm-exclude>` 标签,但请注意单行时仅能包含一个 `<llm-only>` 标签,否则会导致解析错误。
|
||||
|
||||
```md
|
||||
查看插件API指南,了解创建插件的相关文档。
|
||||
|
||||
<llm-exclude>仅限人类阅读</llm-exclude>
|
||||
```
|
||||
|
||||
@ -0,0 +1,248 @@
|
||||
<script setup lang="ts">
|
||||
import snippets from '@internal/encrypt-snippets'
|
||||
import { decodeData } from '@vuepress/helper/client'
|
||||
import { useIntersectionObserver } from '@vueuse/core'
|
||||
import { computed, defineComponent, h, ref, useTemplateRef } from 'vue'
|
||||
import { ClientOnly, onContentUpdated } from 'vuepress/client'
|
||||
import { useDecrypt } from '../composables/decrypt.js'
|
||||
import { ENCRYPT_LOCALES } from '../options.js'
|
||||
|
||||
const { data, hint, pathLocale } = defineProps<{
|
||||
data: string
|
||||
pathLocale: string
|
||||
hint?: string
|
||||
}>()
|
||||
|
||||
const config = computed<{
|
||||
hash: string
|
||||
salt: number[]
|
||||
iv: number[]
|
||||
}>(() => JSON.parse(decodeData(data)))
|
||||
|
||||
const locale = computed(() => ENCRYPT_LOCALES[pathLocale] || {})
|
||||
|
||||
const { decrypt } = useDecrypt(config)
|
||||
|
||||
const el = useTemplateRef<HTMLDivElement>('el')
|
||||
const password = ref('')
|
||||
const content = ref('')
|
||||
const errorCode = ref<0 | 1 | 2>(0) // 0: no error, 1: wrong password 2: no content
|
||||
const loading = ref(false)
|
||||
|
||||
// web encrypt should always use https
|
||||
const isHttps = computed(() => {
|
||||
if (__VUEPRESS_SSR__)
|
||||
return false
|
||||
|
||||
if (__VUEPRESS_DEV__)
|
||||
return true
|
||||
|
||||
return window.location.protocol === 'https:'
|
||||
})
|
||||
|
||||
let rawContent = ''
|
||||
async function load(): Promise<[null, string] | [2, null]> {
|
||||
if (rawContent)
|
||||
return [null, rawContent]
|
||||
const loader = snippets[config.value.hash]
|
||||
if (loader) {
|
||||
try {
|
||||
return [null, rawContent = (await loader()).default]
|
||||
}
|
||||
catch {
|
||||
return [2, null]
|
||||
}
|
||||
}
|
||||
return [2, null]
|
||||
}
|
||||
|
||||
async function onDecrypt() {
|
||||
if (!password.value || loading.value)
|
||||
return
|
||||
|
||||
loading.value = true
|
||||
errorCode.value = 0
|
||||
const [code, rawContent] = await load()
|
||||
if (typeof code === 'number') {
|
||||
errorCode.value = code
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
content.value = (await decrypt(password.value, rawContent))!
|
||||
}
|
||||
catch {
|
||||
errorCode.value = 1
|
||||
}
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
useIntersectionObserver(el, ([entry]) => {
|
||||
if (entry?.isIntersecting)
|
||||
load()
|
||||
})
|
||||
|
||||
onContentUpdated((reason) => {
|
||||
if (reason === 'updated') {
|
||||
rawContent = ''
|
||||
content.value = ''
|
||||
errorCode.value = 0
|
||||
}
|
||||
})
|
||||
|
||||
const DecryptedContent = defineComponent({
|
||||
name: 'DecryptedContent',
|
||||
props: { content: String },
|
||||
render() {
|
||||
const template = `<div>${this.content}</div>`
|
||||
return h({ template })
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<div v-if="!content" ref="el" class="vp-encrypt-snippet">
|
||||
<div class="snippet-hint">
|
||||
<span class="vpi-lock" />
|
||||
<span>{{ hint || locale.hint || 'The content is encrypted, please unlock to view.' }}</span>
|
||||
</div>
|
||||
<div v-if="!isHttps" class="snippet-warning">
|
||||
<strong>{{ locale.warningTitle || '🚨 Security Warning:' }}</strong>
|
||||
{{ locale.warningText || 'Your connection is not encrypted with HTTPS, posing a risk of content leakage and preventing access to encrypted content.' }}
|
||||
</div>
|
||||
<div v-else class="snippet-form" :class="{ error: errorCode === 1 }">
|
||||
<label for="password">
|
||||
<input
|
||||
v-model="password" name="password" type="password"
|
||||
:placeholder="locale.placeholder || 'Enter password'"
|
||||
@keydown.enter="onDecrypt"
|
||||
@input="errorCode = 0"
|
||||
>
|
||||
</label>
|
||||
<button type="button" :disabled="!password" @click="onDecrypt">
|
||||
<span :class="loading ? 'vpi-loading' : 'vpi-unlock'" />
|
||||
</button>
|
||||
<p v-if="errorCode === 1" class="snippet-error">
|
||||
{{ locale.incPwd || 'Incorrect password' }}
|
||||
</p>
|
||||
<p v-if="errorCode === 2" class="snippet-error">
|
||||
{{ locale.noContent || 'Unlocked, but content failed to load, please try again later.' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<DecryptedContent v-else :content="content" class="decrypted-content" />
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.vp-encrypt-snippet {
|
||||
padding: 16px 20px;
|
||||
background-color: var(--vp-c-important-soft);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-hint {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--vp-c-important-1);
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-warning {
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-2);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 320px;
|
||||
height: 36px;
|
||||
padding-right: 4px;
|
||||
padding-left: 12px;
|
||||
margin: 12px auto 8px;
|
||||
background: var(--vp-c-bg);
|
||||
border: solid 1px var(--vp-c-important-2);
|
||||
border-radius: 18px;
|
||||
transition: border-color var(--vp-t-color);
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form.error {
|
||||
border-color: var(--vp-c-caution-1);
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form label {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form input {
|
||||
width: 100%;
|
||||
color: var(--vp-c-important-1);
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-important-1);
|
||||
cursor: pointer;
|
||||
border: solid 2px var(--vp-c-important-1);
|
||||
border-radius: 50%;
|
||||
transition: var(--vp-t-color);
|
||||
transition-property: color, border-color;
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form button[disabled] {
|
||||
color: var(--vp-c-text-3);
|
||||
border-color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form button:not([disabled]):hover {
|
||||
color: var(--vp-c-important-3);
|
||||
border-color: var(--vp-c-important-3);
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form button .vpi-loading {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.vp-encrypt-snippet .snippet-form .snippet-error {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding-left: 12px;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-caution-1);
|
||||
}
|
||||
|
||||
.decrypted-content {
|
||||
background-color: transparent;
|
||||
animation: fade-scale 800ms ease-in 8 alternate;
|
||||
}
|
||||
|
||||
@keyframes fade-scale {
|
||||
0% {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-color: var(--vp-c-green-soft);
|
||||
}
|
||||
}
|
||||
|
||||
.vpi-unlock {
|
||||
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26' viewBox='0 0 26 26'%3E%3Cpath fill='%23000' d='M7 0C4.79 0 2.878.917 1.687 2.406C.498 3.896 0 5.826 0 7.906V11h3V7.906c0-1.58.389-2.82 1.031-3.625C4.674 3.477 5.541 3 7 3c1.463 0 2.328.45 2.969 1.25c.64.8 1.031 2.06 1.031 3.656V9h3V7.906c0-2.092-.527-4.044-1.719-5.531C11.09.888 9.206 0 7 0m2 10c-1.656 0-3 1.344-3 3v10c0 1.656 1.344 3 3 3h14c1.656 0 3-1.344 3-3V13c0-1.656-1.344-3-3-3zm7 5a2 2 0 0 1 2 2c0 .738-.404 1.372-1 1.719V21c0 .551-.449 1-1 1s-1-.449-1-1v-2.281c-.596-.347-1-.98-1-1.719a2 2 0 0 1 2-2'/%3E%3C/svg%3E");
|
||||
}
|
||||
</style>
|
||||
62
plugins/plugin-md-power/src/client/composables/decrypt.ts
Normal file
62
plugins/plugin-md-power/src/client/composables/decrypt.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import type { ComputedRef } from 'vue'
|
||||
|
||||
export function useDecrypt(
|
||||
config: ComputedRef<{ salt: number[], iv: number[] }>,
|
||||
) {
|
||||
const toUnit8Array = (raw: number[]) => Uint8Array.from(raw)
|
||||
|
||||
return {
|
||||
decrypt: async (password: string, text: string) => {
|
||||
if (!password)
|
||||
return
|
||||
|
||||
const keyMaterial = await getKeyMaterial(password)
|
||||
const key = await getCryptoDeriveKey(keyMaterial, toUnit8Array(config.value.salt))
|
||||
|
||||
const ciphertextData = Uint8Array.from(text, c => c.charCodeAt(0))
|
||||
|
||||
const decrypted = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: 'AES-CBC',
|
||||
iv: toUnit8Array(config.value.iv),
|
||||
},
|
||||
key,
|
||||
ciphertextData,
|
||||
)
|
||||
|
||||
return new TextDecoder().decode(decrypted)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function getKeyMaterial(password: string) {
|
||||
const enc = new TextEncoder()
|
||||
return window.crypto.subtle.importKey(
|
||||
'raw',
|
||||
enc.encode(password),
|
||||
'PBKDF2',
|
||||
false,
|
||||
['deriveBits', 'deriveKey'],
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* crypto
|
||||
*/
|
||||
function getCryptoDeriveKey(keyMaterial: CryptoKey, salt: BufferSource) {
|
||||
return window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'PBKDF2',
|
||||
salt,
|
||||
iterations: 100000,
|
||||
hash: 'SHA-256',
|
||||
},
|
||||
keyMaterial,
|
||||
{
|
||||
name: 'AES-CBC',
|
||||
length: 256,
|
||||
},
|
||||
true,
|
||||
['encrypt', 'decrypt'],
|
||||
)
|
||||
}
|
||||
@ -1,5 +1,13 @@
|
||||
import type { LocaleConfig } from 'vuepress'
|
||||
import type { EncryptSnippetLocale } from '../shared/encrypt.js'
|
||||
import type { MarkdownPowerPluginOptions } from '../shared/index.js'
|
||||
|
||||
declare const __MD_POWER_INJECT_OPTIONS__: MarkdownPowerPluginOptions
|
||||
declare const __MD_POWER_DASHJS_INSTALLED__: boolean
|
||||
declare const __MD_POWER_HLSJS_INSTALLED__: boolean
|
||||
declare const __MD_POWER_MPEGTSJS_INSTALLED__: boolean
|
||||
declare const __MD_POWER_ENCRYPT_LOCALES__: LocaleConfig<EncryptSnippetLocale>
|
||||
|
||||
export const pluginOptions: MarkdownPowerPluginOptions = __MD_POWER_INJECT_OPTIONS__
|
||||
|
||||
export const installed: {
|
||||
@ -33,3 +41,5 @@ export const INJECT_TIMELINE_KEY: symbol = Symbol(
|
||||
export const INJECT_COLLAPSE_KEY: symbol = Symbol(
|
||||
__VUEPRESS_DEV__ ? 'collapse' : '',
|
||||
)
|
||||
|
||||
export const ENCRYPT_LOCALES = __MD_POWER_ENCRYPT_LOCALES__
|
||||
|
||||
13
plugins/plugin-md-power/src/client/shim.d.ts
vendored
13
plugins/plugin-md-power/src/client/shim.d.ts
vendored
@ -1,5 +1,3 @@
|
||||
import type { ReplEditorData } from '../shared/repl.js'
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { ComponentOptions } from 'vue'
|
||||
|
||||
@ -8,16 +6,13 @@ declare module '*.vue' {
|
||||
}
|
||||
|
||||
declare module '@internal/md-power/replEditorData' {
|
||||
import type { ReplEditorData } from '../shared/repl.js'
|
||||
|
||||
const res: ReplEditorData
|
||||
export default res
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
const __MD_POWER_INJECT_OPTIONS__: MarkdownPowerPluginOptions
|
||||
const __MD_POWER_DASHJS_INSTALLED__: boolean
|
||||
const __MD_POWER_HLSJS_INSTALLED__: boolean
|
||||
const __MD_POWER_MPEGTSJS_INSTALLED__: boolean
|
||||
|
||||
declare module '@internal/encrypt-snippets' {
|
||||
const res: Record<string, () => Promise<{ default: string }>>
|
||||
export default res
|
||||
}
|
||||
|
||||
80
plugins/plugin-md-power/src/node/container/encrypt.ts
Normal file
80
plugins/plugin-md-power/src/node/container/encrypt.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import type { App } from 'vuepress/core'
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import type { EncryptSnippetOptions } from '../../shared/encrypt'
|
||||
import { getRandomValues } from 'node:crypto'
|
||||
import { debounce } from '@pengzhanbo/utils'
|
||||
import { encodeData, ensureLeadingSlash } from '@vuepress/helper'
|
||||
import { colors, fs, hash } from 'vuepress/utils'
|
||||
import { cleanMarkdownEnv } from '../utils/cleanMarkdownEnv'
|
||||
import { encryptContent } from '../utils/encryptContent'
|
||||
import { logger } from '../utils/logger'
|
||||
import { createContainerSyntaxPlugin } from './createContainer'
|
||||
|
||||
interface EncryptOptions {
|
||||
password: string
|
||||
salt: Uint8Array
|
||||
iv: Uint8Array
|
||||
}
|
||||
|
||||
export function encryptPlugin(app: App, md: Markdown, options: EncryptSnippetOptions): void {
|
||||
const encrypted: Set<string> = new Set()
|
||||
const entryFile = 'internal/encrypt-snippets/index.js'
|
||||
|
||||
const writeTemp = async (
|
||||
hash: string,
|
||||
content: string,
|
||||
options: EncryptOptions,
|
||||
) => {
|
||||
const encrypted = await encryptContent(content, options)
|
||||
await app.writeTemp(`internal/encrypt-snippets/${hash}.js`, `export default ${JSON.stringify(encrypted)}`)
|
||||
}
|
||||
|
||||
const writeEntry = debounce(150, async () => {
|
||||
let content = `export default {\n`
|
||||
for (const hash of encrypted) {
|
||||
content += ` '${hash}': () => import('./${hash}.js' /* webpackChunkName: "snippet-${hash}" */),\n`
|
||||
}
|
||||
content += '\n}\n'
|
||||
app.writeTemp(entryFile, content)
|
||||
})
|
||||
|
||||
if (!fs.existsSync(app.dir.temp(entryFile))) {
|
||||
// 初始化
|
||||
app.writeTemp(entryFile, 'export default {}\n')
|
||||
}
|
||||
|
||||
const localKeys = Object.keys(app.options.locales || {}).filter(key => key !== '/')
|
||||
const getLocale = (relativePath: string) => {
|
||||
const relative = ensureLeadingSlash(relativePath)
|
||||
return localKeys.find(key => relative.startsWith(key)) || '/'
|
||||
}
|
||||
|
||||
createContainerSyntaxPlugin(md, 'encrypt', (tokens, index, _, env) => {
|
||||
const { meta, content } = tokens[index]
|
||||
const { password, pwd, hint } = meta as { password?: string, pwd?: string, hint?: string }
|
||||
const rendered = md.render(content, cleanMarkdownEnv(env))
|
||||
const _pwd = password || pwd || options.password
|
||||
|
||||
if (!_pwd) {
|
||||
logger.warn(`${colors.cyan('[encrypt snippet]')} ${colors.green('::: encrypt')} container missing password. ${colors.gray(`(${env.filePathRelative})`)}`)
|
||||
return rendered
|
||||
}
|
||||
|
||||
const contentHash = hash(content)
|
||||
encrypted.add(contentHash)
|
||||
|
||||
const salt = getRandomValues(new Uint8Array(16))
|
||||
const iv = getRandomValues(new Uint8Array(16))
|
||||
|
||||
writeEntry()
|
||||
writeTemp(contentHash, rendered, { salt, iv, password: String(_pwd) })
|
||||
|
||||
const data = encodeData(JSON.stringify({
|
||||
hash: contentHash,
|
||||
salt: Array.from(salt),
|
||||
iv: Array.from(iv),
|
||||
}))
|
||||
|
||||
return `<VPEncryptSnippet data="${data}" hint="${hint || ''}" path-locale="${getLocale(env.filePathRelative)}" />`
|
||||
})
|
||||
}
|
||||
@ -9,6 +9,7 @@ import { codeTabs } from './codeTabs.js'
|
||||
import { codeTreePlugin } from './codeTree.js'
|
||||
import { collapsePlugin } from './collapse.js'
|
||||
import { demoWrapperPlugin } from './demoWrapper.js'
|
||||
import { encryptPlugin } from './encrypt.js'
|
||||
import { fieldPlugin } from './field.js'
|
||||
import { fileTreePlugin } from './fileTree.js'
|
||||
import { langReplPlugin } from './langRepl.js'
|
||||
@ -39,6 +40,11 @@ export async function containerPlugin(
|
||||
// ::: card / card-grid
|
||||
cardPlugin(md)
|
||||
|
||||
if (options.encrypt) {
|
||||
// ::: encrypt password="xxx"
|
||||
encryptPlugin(app, md, typeof options.encrypt === 'boolean' ? {} : options.encrypt)
|
||||
}
|
||||
|
||||
if (options.npmTo) {
|
||||
// ::: npm-to
|
||||
npmToPlugins(md, typeof options.npmTo === 'boolean' ? {} : options.npmTo)
|
||||
|
||||
12
plugins/plugin-md-power/src/node/locales/de.ts
Normal file
12
plugins/plugin-md-power/src/node/locales/de.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
|
||||
export const deLocale: MDPowerLocaleData = {
|
||||
encrypt: {
|
||||
hint: 'Der Inhalt ist verschlüsselt, bitte entsperren Sie ihn, um ihn anzuzeigen.',
|
||||
placeholder: 'Passwort eingeben',
|
||||
incPwd: 'Falsches Passwort',
|
||||
noContent: 'Entsperrt, aber der Inhalt konnte nicht geladen werden. Bitte versuchen Sie es später erneut.',
|
||||
warningTitle: '🚨 Sicherheitswarnung:',
|
||||
warningText: 'Ihre Verbindung ist nicht mit HTTPS verschlüsselt, was ein Risiko für Inhaltslecks darstellt und den Zugriff auf verschlüsselte Inhalte verhindert.',
|
||||
},
|
||||
}
|
||||
12
plugins/plugin-md-power/src/node/locales/en.ts
Normal file
12
plugins/plugin-md-power/src/node/locales/en.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
|
||||
export const enLocale: MDPowerLocaleData = {
|
||||
encrypt: {
|
||||
hint: 'The content is encrypted, please unlock to view.',
|
||||
placeholder: 'Enter password',
|
||||
incPwd: 'Incorrect password',
|
||||
noContent: 'Unlocked, but content failed to load, please try again later.',
|
||||
warningTitle: '🚨 Security Warning:',
|
||||
warningText: 'Your connection is not encrypted with HTTPS, posing a risk of content leakage and preventing access to encrypted content.',
|
||||
},
|
||||
}
|
||||
12
plugins/plugin-md-power/src/node/locales/fr.ts
Normal file
12
plugins/plugin-md-power/src/node/locales/fr.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
|
||||
export const frLocale: MDPowerLocaleData = {
|
||||
encrypt: {
|
||||
hint: 'Le contenu est chiffré, veuillez déverrouiller pour afficher.',
|
||||
placeholder: 'Entrez le mot de passe',
|
||||
incPwd: 'Mot de passe incorrect',
|
||||
noContent: 'Déverrouillé, mais le contenu n\'a pas pu être chargé, veuillez réessayer plus tard.',
|
||||
warningTitle: '🚨 Avertissement de sécurité :',
|
||||
warningText: 'Votre connexion n\'est pas chiffrée avec HTTPS, ce qui présente un risque de fuite de contenu et empêche l\'accès au contenu chiffré.',
|
||||
},
|
||||
}
|
||||
21
plugins/plugin-md-power/src/node/locales/index.ts
Normal file
21
plugins/plugin-md-power/src/node/locales/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import type { DefaultLocaleInfo } from '@vuepress/helper'
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
import { deLocale } from './de'
|
||||
import { enLocale } from './en'
|
||||
import { frLocale } from './fr'
|
||||
import { jaLocale } from './ja'
|
||||
import { koLocale } from './ko'
|
||||
import { ruLocale } from './ru'
|
||||
import { zhLocale } from './zh'
|
||||
import { zhTWLocale } from './zh-tw'
|
||||
|
||||
export const LOCALE_OPTIONS: DefaultLocaleInfo<MDPowerLocaleData> = [
|
||||
[['en', 'en-US'], enLocale],
|
||||
[['zh', 'zh-CN', 'zh-Hans', 'zh-Hant'], zhLocale],
|
||||
[['zh-TW'], zhTWLocale],
|
||||
[['de', 'de-DE'], deLocale],
|
||||
[['fr', 'fr-FR'], frLocale],
|
||||
[['ru', 'ru-RU'], ruLocale],
|
||||
[['ja', 'ja-JP'], jaLocale],
|
||||
[['ko', 'ko-KR'], koLocale],
|
||||
]
|
||||
12
plugins/plugin-md-power/src/node/locales/ja.ts
Normal file
12
plugins/plugin-md-power/src/node/locales/ja.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
|
||||
export const jaLocale: MDPowerLocaleData = {
|
||||
encrypt: {
|
||||
hint: 'コンテンツは暗号化されています。閲覧するにはロックを解除してください。',
|
||||
placeholder: 'パスワードを入力',
|
||||
incPwd: 'パスワードが間違っています',
|
||||
noContent: 'ロックは解除されましたが、コンテンツの読み込みに失敗しました。後ほど再度お試しください。',
|
||||
warningTitle: '🚨 セキュリティ警告:',
|
||||
warningText: '接続がHTTPSで暗号化されていないため、コンテンツの漏洩リスクがあり、暗号化されたコンテンツへのアクセスができません。',
|
||||
},
|
||||
}
|
||||
12
plugins/plugin-md-power/src/node/locales/ko.ts
Normal file
12
plugins/plugin-md-power/src/node/locales/ko.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
|
||||
export const koLocale: MDPowerLocaleData = {
|
||||
encrypt: {
|
||||
hint: '내용이 암호화되어 있습니다. 잠금 해제 후 확인하세요.',
|
||||
placeholder: '비밀번호 입력',
|
||||
incPwd: '잘못된 비밀번호',
|
||||
noContent: '잠금이 해제되었지만 내용을 불러오지 못했습니다. 나중에 다시 시도해 주세요.',
|
||||
warningTitle: '🚨 보안 경고:',
|
||||
warningText: '연결이 HTTPS로 암호화되지 않아 내용 유출 위험이 있으며, 암호화된 콘텐츠에 접근할 수 없습니다.',
|
||||
},
|
||||
}
|
||||
12
plugins/plugin-md-power/src/node/locales/ru.ts
Normal file
12
plugins/plugin-md-power/src/node/locales/ru.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
|
||||
export const ruLocale: MDPowerLocaleData = {
|
||||
encrypt: {
|
||||
hint: 'Контент зашифрован, разблокируйте для просмотра.',
|
||||
placeholder: 'Введите пароль',
|
||||
incPwd: 'Неверный пароль',
|
||||
noContent: 'Разблокировано, но не удалось загрузить содержимое. Повторите попытку позже.',
|
||||
warningTitle: '🚨 Предупреждение безопасности:',
|
||||
warningText: 'Ваше соединение не защищено HTTPS, что создает риск утечки данных и блокирует доступ к зашифрованному контенту.',
|
||||
},
|
||||
}
|
||||
12
plugins/plugin-md-power/src/node/locales/zh-tw.ts
Normal file
12
plugins/plugin-md-power/src/node/locales/zh-tw.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
|
||||
export const zhTWLocale: MDPowerLocaleData = {
|
||||
encrypt: {
|
||||
hint: '內容已加密,請解鎖後查看。',
|
||||
placeholder: '輸入密碼',
|
||||
incPwd: '密碼錯誤',
|
||||
noContent: '已解鎖,但內容載入失敗,請稍後再試。',
|
||||
warningTitle: '🚨 安全警告:',
|
||||
warningText: '您的連線未使用 HTTPS 加密,可能導致內容洩露風險,無法存取加密內容。',
|
||||
},
|
||||
}
|
||||
12
plugins/plugin-md-power/src/node/locales/zh.ts
Normal file
12
plugins/plugin-md-power/src/node/locales/zh.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { MDPowerLocaleData } from '../../shared/locale'
|
||||
|
||||
export const zhLocale: MDPowerLocaleData = {
|
||||
encrypt: {
|
||||
hint: '内容已加密,请解锁后查看。',
|
||||
placeholder: '输入密码',
|
||||
incPwd: '密码错误',
|
||||
noContent: '已解锁,但内容加载失败,请稍后再试。',
|
||||
warningTitle: '🚨 安全警告:',
|
||||
warningText: '您的连接未使用HTTPS加密,存在内容泄露风险,无法访问加密内容。',
|
||||
},
|
||||
}
|
||||
@ -22,7 +22,14 @@ export function markdownPowerPlugin(
|
||||
|
||||
clientConfigFile: app => prepareConfigFile(app, options),
|
||||
|
||||
define: provideData(options),
|
||||
define: app => provideData(app, options),
|
||||
|
||||
alias: (_, isServer) => {
|
||||
if (!isServer) {
|
||||
return { ...options.encrypt ? { '/^vue$/': 'vue/dist/vue.esm-bundler.js' } : undefined }
|
||||
}
|
||||
return {}
|
||||
},
|
||||
|
||||
extendsBundlerOptions(bundlerOptions, app) {
|
||||
if (options.repl) {
|
||||
|
||||
@ -21,6 +21,11 @@ export async function prepareConfigFile(app: App, options: MarkdownPowerPluginOp
|
||||
imports.add(`import CodeTabs from '${CLIENT_FOLDER}components/CodeTabs.vue'`)
|
||||
enhances.add(`app.component('CodeTabs', CodeTabs)`)
|
||||
|
||||
if (options.encrypt) {
|
||||
imports.add(`import VPEncryptSnippet from '${CLIENT_FOLDER}components/VPEncryptSnippet.vue'`)
|
||||
enhances.add(`app.component('VPEncryptSnippet', VPEncryptSnippet)`)
|
||||
}
|
||||
|
||||
if (options.pdf) {
|
||||
imports.add(`import PDFViewer from '${CLIENT_FOLDER}components/PDFViewer.vue'`)
|
||||
enhances.add(`app.component('PDFViewer', PDFViewer)`)
|
||||
|
||||
@ -1,19 +1,44 @@
|
||||
import type { App, LocaleConfig } from 'vuepress'
|
||||
import type { MarkdownPowerPluginOptions } from '../shared/index.js'
|
||||
import type { MDPowerLocaleData } from '../shared/locale.js'
|
||||
import { getFullLocaleConfig } from '@vuepress/helper'
|
||||
import { isPackageExists } from 'local-pkg'
|
||||
import { LOCALE_OPTIONS } from './locales/index.js'
|
||||
|
||||
export function provideData(options: MarkdownPowerPluginOptions): Record<string, unknown> {
|
||||
const mardownOptions = {
|
||||
export function provideData(app: App, options: MarkdownPowerPluginOptions): Record<string, unknown> {
|
||||
const markdownOptions = {
|
||||
plot: options.plot,
|
||||
pdf: options.pdf,
|
||||
}
|
||||
|
||||
const locales = getFullLocaleConfig({
|
||||
app,
|
||||
name: 'vuepress-plugin-md-power',
|
||||
default: LOCALE_OPTIONS,
|
||||
config: options.locales,
|
||||
})
|
||||
const icon = options.icon ?? { provider: 'iconify' }
|
||||
|
||||
return {
|
||||
__MD_POWER_INJECT_OPTIONS__: mardownOptions,
|
||||
__MD_POWER_INJECT_OPTIONS__: markdownOptions,
|
||||
__MD_POWER_DASHJS_INSTALLED__: isPackageExists('dashjs'),
|
||||
__MD_POWER_HLSJS_INSTALLED__: isPackageExists('hls.js'),
|
||||
__MD_POWER_MPEGTSJS_INSTALLED__: isPackageExists('mpegts.js'),
|
||||
__MD_POWER_ICON_PROVIDER__: icon.provider || 'iconify',
|
||||
__MD_POWER_ICON_PREFIX__: icon.prefix || '',
|
||||
__MD_POWER_ENCRYPT_LOCALES__: options.encrypt ? findLocales(locales, 'encrypt') : {},
|
||||
}
|
||||
}
|
||||
|
||||
function findLocales<
|
||||
T extends MDPowerLocaleData,
|
||||
K extends keyof T,
|
||||
>(locales: LocaleConfig<T>, key: K): Record<string, T[K]> {
|
||||
const res: Record<string, T[K]> = {}
|
||||
|
||||
for (const [locale, value] of Object.entries(locales)) {
|
||||
res[locale] = value[key] ?? {} as T[K]
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
60
plugins/plugin-md-power/src/node/utils/encryptContent.ts
Normal file
60
plugins/plugin-md-power/src/node/utils/encryptContent.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { webcrypto } from 'node:crypto'
|
||||
|
||||
/**
|
||||
* @see https://developer.mozilla.org/zh-CN/docs/Web/API/SubtleCrypto/deriveKey#pbkdf2_2
|
||||
* @param password
|
||||
*/
|
||||
function getKeyMaterial(password: string) {
|
||||
const enc = new TextEncoder()
|
||||
return webcrypto.subtle.importKey(
|
||||
'raw',
|
||||
enc.encode(password),
|
||||
'PBKDF2',
|
||||
false,
|
||||
['deriveBits', 'deriveKey'],
|
||||
)
|
||||
}
|
||||
|
||||
function getCryptoDeriveKey(keyMaterial: CryptoKey | webcrypto.CryptoKey, salt: Uint8Array) {
|
||||
return webcrypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'PBKDF2',
|
||||
salt: salt as unknown as ArrayBuffer,
|
||||
iterations: 100000,
|
||||
hash: 'SHA-256',
|
||||
},
|
||||
keyMaterial,
|
||||
{
|
||||
name: 'AES-CBC',
|
||||
length: 256,
|
||||
},
|
||||
true,
|
||||
['encrypt', 'decrypt'],
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/mdn/dom-examples/blob/main/web-crypto/encrypt-decrypt/aes-cbc.js
|
||||
* @param content
|
||||
*/
|
||||
export async function encryptContent(content: string, options: {
|
||||
password: string
|
||||
iv: Uint8Array
|
||||
salt: Uint8Array
|
||||
}) {
|
||||
const { password, iv, salt } = options
|
||||
const keyMaterial = await getKeyMaterial(password)
|
||||
const key = await getCryptoDeriveKey(keyMaterial, salt)
|
||||
|
||||
const enc = new TextEncoder()
|
||||
const cipherTextData = await webcrypto.subtle.encrypt(
|
||||
{
|
||||
name: 'AES-CBC',
|
||||
iv: iv as unknown as ArrayBuffer,
|
||||
},
|
||||
key,
|
||||
enc.encode(content),
|
||||
)
|
||||
|
||||
return String.fromCharCode(...new Uint8Array(cipherTextData))
|
||||
}
|
||||
36
plugins/plugin-md-power/src/shared/encrypt.ts
Normal file
36
plugins/plugin-md-power/src/shared/encrypt.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import type { LocaleData } from 'vuepress'
|
||||
|
||||
export interface EncryptSnippetLocale extends LocaleData {
|
||||
/**
|
||||
* @default 'The content is encrypted, please unlock to view.''
|
||||
*/
|
||||
hint?: string
|
||||
/**
|
||||
* @default 'Enter password'
|
||||
*/
|
||||
placeholder?: string
|
||||
/**
|
||||
* @default 'Incorrect password'
|
||||
*/
|
||||
incPwd?: string
|
||||
/**
|
||||
* @default 'Unlocked, but content failed to load, please try again later.'
|
||||
*/
|
||||
noContent?: string
|
||||
|
||||
/**
|
||||
* @default '🚨 Security Warning:'
|
||||
*/
|
||||
warningTitle?: string
|
||||
/**
|
||||
* @default 'Your connection is not encrypted with HTTPS, posing a risk of content leakage and preventing access to encrypted content.'
|
||||
*/
|
||||
warningText?: string
|
||||
}
|
||||
|
||||
export interface EncryptSnippetOptions {
|
||||
/**
|
||||
* default password
|
||||
*/
|
||||
password?: string
|
||||
}
|
||||
6
plugins/plugin-md-power/src/shared/locale.ts
Normal file
6
plugins/plugin-md-power/src/shared/locale.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import type { LocaleData } from 'vuepress'
|
||||
import type { EncryptSnippetLocale } from './encrypt'
|
||||
|
||||
export interface MDPowerLocaleData extends LocaleData {
|
||||
encrypt?: EncryptSnippetLocale
|
||||
}
|
||||
@ -1,9 +1,12 @@
|
||||
import type { LocaleConfig } from 'vuepress'
|
||||
import type { CanIUseOptions } from './caniuse.js'
|
||||
import type { CodeTabsOptions } from './codeTabs.js'
|
||||
import type { CodeTreeOptions } from './codeTree.js'
|
||||
import type { EncryptSnippetOptions } from './encrypt.js'
|
||||
import type { MarkdownEnvPreset } from './env.js'
|
||||
import type { FileTreeOptions } from './fileTree.js'
|
||||
import type { IconOptions } from './icon.js'
|
||||
import type { MDPowerLocaleData } from './locale.js'
|
||||
import type { MarkOptions } from './mark.js'
|
||||
import type { NpmToOptions } from './npmTo.js'
|
||||
import type { PDFOptions } from './pdf.js'
|
||||
@ -55,6 +58,13 @@ export interface MarkdownPowerPluginOptions {
|
||||
* @default 'eager'
|
||||
*/
|
||||
mark?: MarkOptions
|
||||
|
||||
/**
|
||||
* 是否启用 内容片段加密容器
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
encrypt?: boolean | EncryptSnippetOptions
|
||||
/**
|
||||
* 配置代码块分组
|
||||
*/
|
||||
@ -310,4 +320,6 @@ export interface MarkdownPowerPluginOptions {
|
||||
* @default false
|
||||
*/
|
||||
imageSize?: boolean | 'local' | 'all'
|
||||
|
||||
locales?: LocaleConfig<MDPowerLocaleData>
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import { argv } from '../../scripts/tsdown-args.mjs'
|
||||
/** @import {Options} from 'tsdown' */
|
||||
|
||||
const config = [
|
||||
{ dir: 'composables', files: ['codeRepl.ts', 'pdf.ts', 'rustRepl.ts', 'size.ts', 'audio.ts', 'demo.ts', 'mark.ts'] },
|
||||
{ dir: 'composables', files: ['codeRepl.ts', 'pdf.ts', 'rustRepl.ts', 'size.ts', 'audio.ts', 'demo.ts', 'mark.ts', 'decrypt.ts'] },
|
||||
{ dir: 'utils', files: ['http.ts', 'link.ts', 'sleep.ts'] },
|
||||
{ dir: '', files: ['index.ts', 'options.ts'] },
|
||||
]
|
||||
|
||||
359
pnpm-lock.yaml
generated
359
pnpm-lock.yaml
generated
@ -213,11 +213,11 @@ catalogs:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
'@vueuse/core':
|
||||
specifier: ^14.1.0
|
||||
version: 14.1.0
|
||||
specifier: ^14.2.0
|
||||
version: 14.2.1
|
||||
'@vueuse/integrations':
|
||||
specifier: ^14.1.0
|
||||
version: 14.1.0
|
||||
specifier: ^14.2.0
|
||||
version: 14.2.1
|
||||
cac:
|
||||
specifier: ^6.7.14
|
||||
version: 6.7.14
|
||||
@ -400,7 +400,7 @@ overrides:
|
||||
chokidar: 5.0.0
|
||||
esbuild: ^0.27.2
|
||||
sass-embedded: ^1.97.2
|
||||
vite: ^8.0.0-beta.8
|
||||
vite: ^8.0.0-beta.10
|
||||
vue-router: ^4.6.4
|
||||
|
||||
patchedDependencies:
|
||||
@ -688,7 +688,7 @@ importers:
|
||||
version: 2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
'@vueuse/core':
|
||||
specifier: catalog:prod
|
||||
version: 14.1.0(vue@3.5.27(typescript@5.9.3))
|
||||
version: 14.2.1(vue@3.5.27(typescript@5.9.3))
|
||||
chokidar:
|
||||
specifier: 5.0.0
|
||||
version: 5.0.0
|
||||
@ -773,10 +773,10 @@ importers:
|
||||
version: 2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
'@vueuse/core':
|
||||
specifier: catalog:prod
|
||||
version: 14.1.0(vue@3.5.27(typescript@5.9.3))
|
||||
version: 14.2.1(vue@3.5.27(typescript@5.9.3))
|
||||
'@vueuse/integrations':
|
||||
specifier: catalog:prod
|
||||
version: 14.1.0(axios@1.13.2)(change-case@5.4.4)(focus-trap@7.8.0)(qrcode@1.5.4)(vue@3.5.27(typescript@5.9.3))
|
||||
version: 14.2.1(axios@1.13.2)(change-case@5.4.4)(focus-trap@7.8.0)(qrcode@1.5.4)(vue@3.5.27(typescript@5.9.3))
|
||||
chokidar:
|
||||
specifier: 5.0.0
|
||||
version: 5.0.0
|
||||
@ -872,7 +872,7 @@ importers:
|
||||
version: 2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
'@vuepress/plugin-shiki':
|
||||
specifier: catalog:vuepress
|
||||
version: 2.0.0-rc.122(@vuepress/shiki-twoslash@2.0.0-rc.122(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))))(@vueuse/core@14.1.0(vue@3.5.27(typescript@5.9.3)))(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
version: 2.0.0-rc.122(@vuepress/shiki-twoslash@2.0.0-rc.122(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))))(@vueuse/core@14.2.1(vue@3.5.27(typescript@5.9.3)))(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
'@vuepress/plugin-sitemap':
|
||||
specifier: catalog:vuepress
|
||||
version: 2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
@ -884,7 +884,7 @@ importers:
|
||||
version: 2.0.0-rc.122(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
'@vueuse/core':
|
||||
specifier: catalog:prod
|
||||
version: 14.1.0(vue@3.5.27(typescript@5.9.3))
|
||||
version: 14.2.1(vue@3.5.27(typescript@5.9.3))
|
||||
chokidar:
|
||||
specifier: 5.0.0
|
||||
version: 5.0.0
|
||||
@ -1956,8 +1956,8 @@ packages:
|
||||
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
'@oxc-project/runtime@0.108.0':
|
||||
resolution: {integrity: sha512-J1cESY4anMO4i9KtCPmCfQAzAR00Uw4SWsDPFP10CIwDMugkh34UrTKByuYKuPaHy0XAk8LlJiZJq2OLMfbuIQ==}
|
||||
'@oxc-project/runtime@0.113.0':
|
||||
resolution: {integrity: sha512-apRWH/gXeAsl/sQiblIZnLu7f8P/C9S2fJIicuHV9KOK9J7Hv1JPyTwB8WAcOrDBfjs+cbzjMOGe9UR2ue4ZQg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
|
||||
'@oxc-project/types@0.107.0':
|
||||
@ -1966,6 +1966,9 @@ packages:
|
||||
'@oxc-project/types@0.108.0':
|
||||
resolution: {integrity: sha512-7lf13b2IA/kZO6xgnIZA88sq3vwrxWk+2vxf6cc+omwYCRTiA5e63Beqf3fz/v8jEviChWWmFYBwzfSeyrsj7Q==}
|
||||
|
||||
'@oxc-project/types@0.113.0':
|
||||
resolution: {integrity: sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==}
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.1':
|
||||
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@ -2170,6 +2173,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-hqGXRc162qCCIOAcHN2Cw4eXiVTwYsMFLOhAy1IG2CxY+dwc/l4Ga+dLPkLor3Ikqy5WDn+7kxHbbh6EmshEpQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2182,6 +2191,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-ezvvGuhteE15JmMhJW0wS7BaXmhwLy1YHeEwievYaPC1PgGD86wgBKfOpHr9tSKllAXbCe0BeeMvasscWLhKdA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2194,6 +2209,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-4fhKVJiEYVd5n6no/mrL3LZ9kByfCGwmONOrdtvx8DJGDQhehH/q3RfhG3V/4jGKhpXgbDjpIjkkFdybCTcgew==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2206,6 +2227,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-T3Y52sW6JAhvIqArBw+wtjNU1Ieaz4g0NBxyjSJoW971nZJBZygNlSYx78G4cwkCmo1dYTciTPDOnQygLV23pA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2218,6 +2245,12 @@ packages:
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-NIW40jQDSQap2KDdmm9z3B/4OzWJ6trf8dwx3FD74kcQb3v34ThsBFTtzE5KjDuxnxgUlV+DkAu+XgSMKrgufw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2232,6 +2265,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-CCKEk+H+8c0WGe/8n1E20n85Tq4Pv+HNAbjP1KfUXW+01aCWSMjU56ChNrM2tvHnXicfm7QRNoZyfY8cWh7jLQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2246,6 +2286,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-VlfwJ/HCskPmQi8R0JuAFndySKVFX7yPhE658o27cjSDWWbXVtGkSbwaxstii7Q+3Rz87ZXN+HLnb1kd4R9Img==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2260,6 +2307,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-kuO92hTRyGy0Ts3Nsqll0rfO8eFsEJe9dGQGktkQnZ2hrJrDVN0y419dMgKy/gB2S2o7F2dpWhpfQOBehZPwVA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2274,6 +2328,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-PXAebvNL4sYfCqi8LdY4qyFRacrRoiPZLo3NoUmiTxm7MPtYYR8CNtBGNokqDmMuZIQIecRaD/jbmFAIDz7DxQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2286,6 +2347,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-yJoklQg7XIZq8nAg0bbkEXcDK6sfpjxQGxpg2Nd6ERNtvg+eOaEBRgPww0BVTrYFQzje1pB5qPwC2VnJHT3koQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@ -2296,6 +2363,11 @@ packages:
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-ljZ4+McmCbIuZwEBaoGtiG8Rq2nJjaXEnLEIx+usWetXn1ECjXY0LAhkELxOV6ytv4ensEmoJJ8nXg47hRMjlw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2308,6 +2380,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.59':
|
||||
resolution: {integrity: sha512-bMY4tTIwbdZljW+xe/ln1hvs0SRitahQSXfWtvgAtIzgSX9Ar7KqJzU7lRm33YTRFIHLULRi53yNjw9nJGd6uQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2320,6 +2398,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.29':
|
||||
resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==}
|
||||
|
||||
@ -2329,6 +2413,9 @@ packages:
|
||||
'@rolldown/pluginutils@1.0.0-beta.60':
|
||||
resolution: {integrity: sha512-Jz4aqXRPVtqkH1E3jRDzLO5cgN5JwW+WG0wXGE4NiJd25nougv/AHzxmKCzmVQUYnxLmTM0M4wrZp+LlC2FKLg==}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-rc.4':
|
||||
resolution: {integrity: sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==}
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.52.4':
|
||||
resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==}
|
||||
cpu: [arm]
|
||||
@ -2929,7 +3016,7 @@ packages:
|
||||
resolution: {integrity: sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
peerDependencies:
|
||||
vite: ^8.0.0-beta.8
|
||||
vite: ^8.0.0-beta.10
|
||||
vue: ^3.2.25
|
||||
|
||||
'@vitest/coverage-v8@4.0.17':
|
||||
@ -2961,7 +3048,7 @@ packages:
|
||||
resolution: {integrity: sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==}
|
||||
peerDependencies:
|
||||
msw: ^2.4.9
|
||||
vite: ^8.0.0-beta.8
|
||||
vite: ^8.0.0-beta.10
|
||||
peerDependenciesMeta:
|
||||
msw:
|
||||
optional: true
|
||||
@ -3219,24 +3306,19 @@ packages:
|
||||
'@vuepress/utils@2.0.0-rc.26':
|
||||
resolution: {integrity: sha512-RWzZrGQ0WLSWdELuxg7c6q1D9I22T5PfK/qNFkOsv9eD3gpUsU4jq4zAoumS8o+NRIWHovCJ9WnAhHD0Ns5zAw==}
|
||||
|
||||
'@vueuse/core@14.1.0':
|
||||
resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
'@vueuse/core@14.2.1':
|
||||
resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
'@vueuse/integrations@14.1.0':
|
||||
resolution: {integrity: sha512-eNQPdisnO9SvdydTIXnTE7c29yOsJBD/xkwEyQLdhDC/LKbqrFpXHb3uS//7NcIrQO3fWVuvMGp8dbK6mNEMCA==}
|
||||
'@vueuse/integrations@14.2.1':
|
||||
resolution: {integrity: sha512-2LIUpBi/67PoXJGqSDQUF0pgQWpNHh7beiA+KG2AbybcNm+pTGWT6oPGlBgUoDWmYwfeQqM/uzOHqcILpKL7nA==}
|
||||
peerDependencies:
|
||||
async-validator: ^4
|
||||
axios: ^1
|
||||
change-case: ^5
|
||||
drauu: ^0.4
|
||||
focus-trap: ^7
|
||||
focus-trap: ^7 || ^8
|
||||
fuse.js: ^7
|
||||
idb-keyval: ^6
|
||||
jwt-decode: ^4
|
||||
@ -3271,17 +3353,9 @@ packages:
|
||||
universal-cookie:
|
||||
optional: true
|
||||
|
||||
'@vueuse/metadata@14.1.0':
|
||||
resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==}
|
||||
|
||||
'@vueuse/metadata@14.2.1':
|
||||
resolution: {integrity: sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==}
|
||||
|
||||
'@vueuse/shared@14.1.0':
|
||||
resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
'@vueuse/shared@14.2.1':
|
||||
resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==}
|
||||
peerDependencies:
|
||||
@ -5570,78 +5644,78 @@ packages:
|
||||
lie@3.1.1:
|
||||
resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==}
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
|
||||
lightningcss-android-arm64@1.31.1:
|
||||
resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
lightningcss-darwin-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
|
||||
lightningcss-darwin-arm64@1.31.1:
|
||||
resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-darwin-x64@1.30.2:
|
||||
resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
|
||||
lightningcss-darwin-x64@1.31.1:
|
||||
resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-freebsd-x64@1.30.2:
|
||||
resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
|
||||
lightningcss-freebsd-x64@1.31.1:
|
||||
resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.30.2:
|
||||
resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
|
||||
lightningcss-linux-arm-gnueabihf@1.31.1:
|
||||
resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
|
||||
lightningcss-linux-arm64-gnu@1.31.1:
|
||||
resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
|
||||
lightningcss-linux-arm64-musl@1.31.1:
|
||||
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
|
||||
lightningcss-linux-x64-gnu@1.31.1:
|
||||
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
|
||||
lightningcss-linux-x64-musl@1.31.1:
|
||||
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
|
||||
lightningcss-win32-arm64-msvc@1.31.1:
|
||||
resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss-win32-x64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
|
||||
lightningcss-win32-x64-msvc@1.31.1:
|
||||
resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss@1.30.2:
|
||||
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
|
||||
lightningcss@1.31.1:
|
||||
resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
lilconfig@3.1.3:
|
||||
@ -6729,6 +6803,11 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
rolldown@1.0.0-rc.4:
|
||||
resolution: {integrity: sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
rollup@4.52.4:
|
||||
resolution: {integrity: sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
@ -7594,12 +7673,13 @@ packages:
|
||||
vfile@6.0.3:
|
||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
||||
|
||||
vite@8.0.0-beta.8:
|
||||
resolution: {integrity: sha512-PetN5BNs5dj6NSu1pDrbr0AtbH9KjPhQ/dLePvhLYsYgnZdj6+ihGjtA4DYcR9bASOzOmxN1NqEJEJ4JBUIvpA==}
|
||||
vite@8.0.0-beta.14:
|
||||
resolution: {integrity: sha512-oLW66oi8tZcoxu6+1HFXb+5hLHco3OnEVu2Awmj5NqEo7vxaqybjBM0BXHcq+jAFhzkMGXJl8xcO5qDBczgKLg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': ^20.19.0 || >=22.12.0
|
||||
'@vitejs/devtools': ^0.0.0-alpha.31
|
||||
esbuild: ^0.27.2
|
||||
jiti: '>=1.21.0'
|
||||
less: ^4.0.0
|
||||
@ -7613,6 +7693,8 @@ packages:
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
'@vitejs/devtools':
|
||||
optional: true
|
||||
esbuild:
|
||||
optional: true
|
||||
jiti:
|
||||
@ -8897,12 +8979,14 @@ snapshots:
|
||||
'@opentelemetry/api@1.9.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-project/runtime@0.108.0': {}
|
||||
'@oxc-project/runtime@0.113.0': {}
|
||||
|
||||
'@oxc-project/types@0.107.0': {}
|
||||
|
||||
'@oxc-project/types@0.108.0': {}
|
||||
|
||||
'@oxc-project/types@0.113.0': {}
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.1':
|
||||
optional: true
|
||||
|
||||
@ -9076,60 +9160,90 @@ snapshots:
|
||||
'@rolldown/binding-android-arm64@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-beta.59':
|
||||
dependencies:
|
||||
'@napi-rs/wasm-runtime': 1.1.1
|
||||
@ -9140,24 +9254,37 @@ snapshots:
|
||||
'@napi-rs/wasm-runtime': 1.1.1
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-wasm32-wasi@1.0.0-rc.4':
|
||||
dependencies:
|
||||
'@napi-rs/wasm-runtime': 1.1.1
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.59':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.60':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.4':
|
||||
optional: true
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.29': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.59': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.60': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-rc.4': {}
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.52.4':
|
||||
optional: true
|
||||
|
||||
@ -9774,10 +9901,10 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
|
||||
'@vitejs/plugin-vue@6.0.1(vite@8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))':
|
||||
'@vitejs/plugin-vue@6.0.1(vite@8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.0-beta.29
|
||||
vite: 8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2)
|
||||
vite: 8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2)
|
||||
vue: 3.5.27(typescript@5.9.3)
|
||||
|
||||
'@vitest/coverage-v8@4.0.17(vitest@4.0.17(@opentelemetry/api@1.9.0)(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))':
|
||||
@ -9814,13 +9941,13 @@ snapshots:
|
||||
chai: 6.2.1
|
||||
tinyrainbow: 3.0.3
|
||||
|
||||
'@vitest/mocker@4.0.17(vite@8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))':
|
||||
'@vitest/mocker@4.0.17(vite@8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.0.17
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2)
|
||||
vite: 8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2)
|
||||
|
||||
'@vitest/pretty-format@4.0.17':
|
||||
dependencies:
|
||||
@ -9940,7 +10067,7 @@ snapshots:
|
||||
|
||||
'@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2)':
|
||||
dependencies:
|
||||
'@vitejs/plugin-vue': 6.0.1(vite@8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))
|
||||
'@vitejs/plugin-vue': 6.0.1(vite@8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))
|
||||
'@vuepress/bundlerutils': 2.0.0-rc.26(typescript@5.9.3)
|
||||
'@vuepress/client': 2.0.0-rc.26(typescript@5.9.3)
|
||||
'@vuepress/core': 2.0.0-rc.26(typescript@5.9.3)
|
||||
@ -9951,11 +10078,12 @@ snapshots:
|
||||
postcss: 8.5.6
|
||||
postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(yaml@2.8.2)
|
||||
rollup: 4.52.4
|
||||
vite: 8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2)
|
||||
vite: 8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2)
|
||||
vue: 3.5.27(typescript@5.9.3)
|
||||
vue-router: 4.6.4(vue@3.5.27(typescript@5.9.3))
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- '@vitejs/devtools'
|
||||
- esbuild
|
||||
- jiti
|
||||
- less
|
||||
@ -10027,12 +10155,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
'@vuepress/highlighter-helper@2.0.0-rc.122(@vuepress/helper@2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))))(@vueuse/core@14.1.0(vue@3.5.27(typescript@5.9.3)))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))':
|
||||
'@vuepress/highlighter-helper@2.0.0-rc.122(@vuepress/helper@2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))))(@vueuse/core@14.2.1(vue@3.5.27(typescript@5.9.3)))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))':
|
||||
dependencies:
|
||||
'@vuepress/helper': 2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
vuepress: 2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))
|
||||
optionalDependencies:
|
||||
'@vueuse/core': 14.1.0(vue@3.5.27(typescript@5.9.3))
|
||||
'@vueuse/core': 14.2.1(vue@3.5.27(typescript@5.9.3))
|
||||
|
||||
'@vuepress/markdown@2.0.0-rc.26':
|
||||
dependencies:
|
||||
@ -10243,11 +10371,11 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
'@vuepress/plugin-shiki@2.0.0-rc.122(@vuepress/shiki-twoslash@2.0.0-rc.122(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))))(@vueuse/core@14.1.0(vue@3.5.27(typescript@5.9.3)))(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))':
|
||||
'@vuepress/plugin-shiki@2.0.0-rc.122(@vuepress/shiki-twoslash@2.0.0-rc.122(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))))(@vueuse/core@14.2.1(vue@3.5.27(typescript@5.9.3)))(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))':
|
||||
dependencies:
|
||||
'@shikijs/transformers': 3.22.0
|
||||
'@vuepress/helper': 2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
'@vuepress/highlighter-helper': 2.0.0-rc.122(@vuepress/helper@2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))))(@vueuse/core@14.1.0(vue@3.5.27(typescript@5.9.3)))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
'@vuepress/highlighter-helper': 2.0.0-rc.122(@vuepress/helper@2.0.0-rc.122(typescript@5.9.3)(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))))(@vueuse/core@14.2.1(vue@3.5.27(typescript@5.9.3)))(vuepress@2.0.0-rc.26(@vuepress/bundler-vite@2.0.0-rc.26(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(typescript@5.9.3)(yaml@2.8.2))(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))
|
||||
nanoid: 5.1.6
|
||||
shiki: 3.22.0
|
||||
synckit: 0.11.12
|
||||
@ -10315,13 +10443,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vueuse/core@14.1.0(vue@3.5.27(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.21
|
||||
'@vueuse/metadata': 14.1.0
|
||||
'@vueuse/shared': 14.1.0(vue@3.5.27(typescript@5.9.3))
|
||||
vue: 3.5.27(typescript@5.9.3)
|
||||
|
||||
'@vueuse/core@14.2.1(vue@3.5.27(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.21
|
||||
@ -10329,10 +10450,10 @@ snapshots:
|
||||
'@vueuse/shared': 14.2.1(vue@3.5.27(typescript@5.9.3))
|
||||
vue: 3.5.27(typescript@5.9.3)
|
||||
|
||||
'@vueuse/integrations@14.1.0(axios@1.13.2)(change-case@5.4.4)(focus-trap@7.8.0)(qrcode@1.5.4)(vue@3.5.27(typescript@5.9.3))':
|
||||
'@vueuse/integrations@14.2.1(axios@1.13.2)(change-case@5.4.4)(focus-trap@7.8.0)(qrcode@1.5.4)(vue@3.5.27(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@vueuse/core': 14.1.0(vue@3.5.27(typescript@5.9.3))
|
||||
'@vueuse/shared': 14.1.0(vue@3.5.27(typescript@5.9.3))
|
||||
'@vueuse/core': 14.2.1(vue@3.5.27(typescript@5.9.3))
|
||||
'@vueuse/shared': 14.2.1(vue@3.5.27(typescript@5.9.3))
|
||||
vue: 3.5.27(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
axios: 1.13.2
|
||||
@ -10340,14 +10461,8 @@ snapshots:
|
||||
focus-trap: 7.8.0
|
||||
qrcode: 1.5.4
|
||||
|
||||
'@vueuse/metadata@14.1.0': {}
|
||||
|
||||
'@vueuse/metadata@14.2.1': {}
|
||||
|
||||
'@vueuse/shared@14.1.0(vue@3.5.27(typescript@5.9.3))':
|
||||
dependencies:
|
||||
vue: 3.5.27(typescript@5.9.3)
|
||||
|
||||
'@vueuse/shared@14.2.1(vue@3.5.27(typescript@5.9.3))':
|
||||
dependencies:
|
||||
vue: 3.5.27(typescript@5.9.3)
|
||||
@ -12931,54 +13046,54 @@ snapshots:
|
||||
dependencies:
|
||||
immediate: 3.0.6
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
lightningcss-android-arm64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-arm64@1.30.2:
|
||||
lightningcss-darwin-arm64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-x64@1.30.2:
|
||||
lightningcss-darwin-x64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-freebsd-x64@1.30.2:
|
||||
lightningcss-freebsd-x64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.30.2:
|
||||
lightningcss-linux-arm-gnueabihf@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.30.2:
|
||||
lightningcss-linux-arm64-gnu@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
lightningcss-linux-arm64-musl@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
lightningcss-linux-x64-gnu@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
lightningcss-linux-x64-musl@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
lightningcss-win32-arm64-msvc@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-x64-msvc@1.30.2:
|
||||
lightningcss-win32-x64-msvc@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss@1.30.2:
|
||||
lightningcss@1.31.1:
|
||||
dependencies:
|
||||
detect-libc: 2.1.2
|
||||
optionalDependencies:
|
||||
lightningcss-android-arm64: 1.30.2
|
||||
lightningcss-darwin-arm64: 1.30.2
|
||||
lightningcss-darwin-x64: 1.30.2
|
||||
lightningcss-freebsd-x64: 1.30.2
|
||||
lightningcss-linux-arm-gnueabihf: 1.30.2
|
||||
lightningcss-linux-arm64-gnu: 1.30.2
|
||||
lightningcss-linux-arm64-musl: 1.30.2
|
||||
lightningcss-linux-x64-gnu: 1.30.2
|
||||
lightningcss-linux-x64-musl: 1.30.2
|
||||
lightningcss-win32-arm64-msvc: 1.30.2
|
||||
lightningcss-win32-x64-msvc: 1.30.2
|
||||
lightningcss-android-arm64: 1.31.1
|
||||
lightningcss-darwin-arm64: 1.31.1
|
||||
lightningcss-darwin-x64: 1.31.1
|
||||
lightningcss-freebsd-x64: 1.31.1
|
||||
lightningcss-linux-arm-gnueabihf: 1.31.1
|
||||
lightningcss-linux-arm64-gnu: 1.31.1
|
||||
lightningcss-linux-arm64-musl: 1.31.1
|
||||
lightningcss-linux-x64-gnu: 1.31.1
|
||||
lightningcss-linux-x64-musl: 1.31.1
|
||||
lightningcss-win32-arm64-msvc: 1.31.1
|
||||
lightningcss-win32-x64-msvc: 1.31.1
|
||||
|
||||
lilconfig@3.1.3: {}
|
||||
|
||||
@ -14310,6 +14425,25 @@ snapshots:
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.60
|
||||
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.60
|
||||
|
||||
rolldown@1.0.0-rc.4:
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.113.0
|
||||
'@rolldown/pluginutils': 1.0.0-rc.4
|
||||
optionalDependencies:
|
||||
'@rolldown/binding-android-arm64': 1.0.0-rc.4
|
||||
'@rolldown/binding-darwin-arm64': 1.0.0-rc.4
|
||||
'@rolldown/binding-darwin-x64': 1.0.0-rc.4
|
||||
'@rolldown/binding-freebsd-x64': 1.0.0-rc.4
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.4
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.4
|
||||
'@rolldown/binding-linux-arm64-musl': 1.0.0-rc.4
|
||||
'@rolldown/binding-linux-x64-gnu': 1.0.0-rc.4
|
||||
'@rolldown/binding-linux-x64-musl': 1.0.0-rc.4
|
||||
'@rolldown/binding-openharmony-arm64': 1.0.0-rc.4
|
||||
'@rolldown/binding-wasm32-wasi': 1.0.0-rc.4
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.4
|
||||
'@rolldown/binding-win32-x64-msvc': 1.0.0-rc.4
|
||||
|
||||
rollup@4.52.4:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
@ -15248,14 +15382,14 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
vite@8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2):
|
||||
vite@8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2):
|
||||
dependencies:
|
||||
'@oxc-project/runtime': 0.108.0
|
||||
'@oxc-project/runtime': 0.113.0
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
lightningcss: 1.30.2
|
||||
lightningcss: 1.31.1
|
||||
picomatch: 4.0.3
|
||||
postcss: 8.5.6
|
||||
rolldown: 1.0.0-beta.60
|
||||
rolldown: 1.0.0-rc.4
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 25.0.9
|
||||
@ -15271,7 +15405,7 @@ snapshots:
|
||||
vitest@4.0.17(@opentelemetry/api@1.9.0)(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.0.17
|
||||
'@vitest/mocker': 4.0.17(vite@8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))
|
||||
'@vitest/mocker': 4.0.17(vite@8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2))
|
||||
'@vitest/pretty-format': 4.0.17
|
||||
'@vitest/runner': 4.0.17
|
||||
'@vitest/snapshot': 4.0.17
|
||||
@ -15288,12 +15422,13 @@ snapshots:
|
||||
tinyexec: 1.0.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 3.0.3
|
||||
vite: 8.0.0-beta.8(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2)
|
||||
vite: 8.0.0-beta.14(@types/node@25.0.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(sass-embedded@1.97.2)(sass@1.97.2)(stylus@0.64.0)(yaml@2.8.2)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@types/node': 25.0.9
|
||||
transitivePeerDependencies:
|
||||
- '@vitejs/devtools'
|
||||
- esbuild
|
||||
- jiti
|
||||
- less
|
||||
|
||||
@ -61,7 +61,7 @@ catalogs:
|
||||
tsconfig-vuepress: ^7.0.0
|
||||
tsdown: ^0.19.0
|
||||
typescript: ^5.9.3
|
||||
vite: ^8.0.0-beta.8
|
||||
vite: ^8.0.0-beta.10
|
||||
vitest: ^4.0.17
|
||||
vue-router: ^4.6.4
|
||||
wait-on: ^9.0.3
|
||||
@ -97,8 +97,8 @@ catalogs:
|
||||
'@mdit/plugin-tab': ^0.23.0
|
||||
'@mdit/plugin-tasklist': ^0.22.2
|
||||
'@pengzhanbo/utils': ^3.1.0
|
||||
'@vueuse/core': ^14.1.0
|
||||
'@vueuse/integrations': ^14.1.0
|
||||
'@vueuse/core': ^14.2.0
|
||||
'@vueuse/integrations': ^14.2.0
|
||||
cac: ^6.7.14
|
||||
chart.js: ^4.5.1
|
||||
chokidar: 5.0.0
|
||||
|
||||
@ -61,6 +61,7 @@ let defaultTheme: string | undefined
|
||||
watch(() => props.forceDark, () => {
|
||||
if (!inBrowser || __VUEPRESS_SSR__)
|
||||
return
|
||||
|
||||
if (props.forceDark) {
|
||||
defaultTheme ??= document.documentElement.dataset.theme
|
||||
document.documentElement.dataset.theme = 'dark'
|
||||
@ -69,7 +70,7 @@ watch(() => props.forceDark, () => {
|
||||
noTransition()
|
||||
}
|
||||
document.documentElement.classList.add(`effect-${effect.value}`)
|
||||
}, { immediate: true })
|
||||
}, { immediate: true, flush: 'post' })
|
||||
|
||||
onMounted(() => {
|
||||
if (props.forceDark) {
|
||||
@ -273,7 +274,9 @@ html.no-transition *::after {
|
||||
animation-iteration-count: 1 !important;
|
||||
}
|
||||
|
||||
html[class*="effect-"].force-dark .vp-navbar-appearance {
|
||||
html[class*="effect-"].force-dark .vp-navbar-appearance,
|
||||
html[class*="effect-"].force-dark .vp-navbar-extra .group.appearance,
|
||||
html[class*="effect-"].force-dark .vp-nav-screen .vp-nav-screen-appearance {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ const hasExtraContent = computed(
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="theme.appearance && theme.appearance !== 'force-dark'" class="group">
|
||||
<div v-if="theme.appearance && theme.appearance !== 'force-dark'" class="group appearance">
|
||||
<div class="item appearance">
|
||||
<p class="label">
|
||||
{{ theme.appearanceText || 'Appearance' }}
|
||||
@ -61,7 +61,7 @@ const hasExtraContent = computed(
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="social" class="group">
|
||||
<div v-if="social" class="group social">
|
||||
<div class="item social-links">
|
||||
<VPSocialLinks class="social-links-list" :links="social" />
|
||||
</div>
|
||||
|
||||
@ -4,11 +4,10 @@ import { decodeData } from '@vuepress/helper/client'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export type EncryptConfig = readonly [
|
||||
boolean, // global
|
||||
string, // separator
|
||||
string, // admin
|
||||
string[], // keys
|
||||
Record<string, string>, // rules
|
||||
keys: string, // keys
|
||||
rules: string, // rules
|
||||
global: number, // global
|
||||
admin: string, // admin
|
||||
]
|
||||
|
||||
export interface EncryptDataRule {
|
||||
@ -19,7 +18,6 @@ export interface EncryptDataRule {
|
||||
|
||||
export interface EncryptData {
|
||||
global: boolean
|
||||
separator: string
|
||||
admins: string[]
|
||||
matches: string[]
|
||||
ruleList: EncryptDataRule[]
|
||||
@ -34,22 +32,27 @@ export function useEncryptData(): EncryptRef {
|
||||
}
|
||||
|
||||
function resolveEncryptData(
|
||||
[global, separator, admin, matches, rules]: EncryptConfig,
|
||||
[rawKeys, rawRules, global, admin]: EncryptConfig,
|
||||
): EncryptData {
|
||||
const keys = matches.map(match => decodeData(match))
|
||||
const keys = unwrapData<string[]>(rawKeys).map(key => decodeData(key))
|
||||
const rules = unwrapData<Record<string, string>>(rawRules)
|
||||
const separator = ':'
|
||||
return {
|
||||
global,
|
||||
separator,
|
||||
global: !!global,
|
||||
matches: keys,
|
||||
admins: admin.split(separator),
|
||||
ruleList: Object.keys(rules).map(key => ({
|
||||
key,
|
||||
match: keys[key] as string,
|
||||
match: keys[key],
|
||||
rules: rules[key].split(separator),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
function unwrapData<T>(raw: string): T {
|
||||
return JSON.parse(decodeData(raw)) as T
|
||||
}
|
||||
|
||||
if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) {
|
||||
__VUE_HMR_RUNTIME__.updateEncrypt = (data: EncryptConfig) => {
|
||||
encrypt.value = resolveEncryptData(data)
|
||||
|
||||
@ -30,7 +30,8 @@ const storage = useSessionStorage('2a0a3d6afb2fdf1f', () => {
|
||||
})
|
||||
|
||||
const compareCache = new Map<string, boolean>()
|
||||
async function compareDecrypt(content: string, hash: string, separator = ':'): Promise<boolean> {
|
||||
const separator = ':'
|
||||
async function compareDecrypt(content: string, hash: string): Promise<boolean> {
|
||||
const key = [content, hash].join(separator)
|
||||
if (compareCache.has(key))
|
||||
return compareCache.get(key)!
|
||||
@ -164,7 +165,7 @@ export function useEncryptCompare(): {
|
||||
return false
|
||||
|
||||
for (const admin of encrypt.value.admins) {
|
||||
if (await compareDecrypt(password, admin, encrypt.value.separator)) {
|
||||
if (await compareDecrypt(password, admin)) {
|
||||
storage.value.g = await md5(admin)
|
||||
return true
|
||||
}
|
||||
@ -185,7 +186,7 @@ export function useEncryptCompare(): {
|
||||
for (const { match, key, rules } of hashList.value) {
|
||||
if (toMatch(match, pagePath, filePathRelative)) {
|
||||
for (const rule of rules) {
|
||||
if (await compareDecrypt(password, rule, encrypt.value.separator)) {
|
||||
if (await compareDecrypt(password, rule)) {
|
||||
decrypted = true
|
||||
storage.value.p[key] = await md5(rule)
|
||||
break
|
||||
|
||||
9
theme/src/client/shim.d.ts
vendored
9
theme/src/client/shim.d.ts
vendored
@ -61,11 +61,10 @@ declare module '@internal/sidebar' {
|
||||
declare module '@internal/encrypt' {
|
||||
|
||||
const encrypt: readonly [
|
||||
boolean, // global
|
||||
string, // separator
|
||||
string, // admin
|
||||
string[], // keys
|
||||
Record<string, string>, // rules
|
||||
keys: string,
|
||||
rules: string,
|
||||
global: number,
|
||||
admin: string,
|
||||
]
|
||||
|
||||
export {
|
||||
|
||||
@ -66,6 +66,8 @@ export const MARKDOWN_POWER_FIELDS: (keyof MarkdownPowerPluginOptions)[] = [
|
||||
'chat',
|
||||
'youtube',
|
||||
'qrcode',
|
||||
'encrypt',
|
||||
'locales',
|
||||
]
|
||||
|
||||
export const MARKDOWN_SUPPORT_FIELDS: (keyof MarkdownOptions)[] = [
|
||||
|
||||
@ -15,7 +15,6 @@ import { zhTwLocale, zhTwPresetLocale } from './zh-tw.js'
|
||||
import { zhLocale, zhPresetLocale } from './zh.js'
|
||||
|
||||
export const LOCALE_OPTIONS: DefaultLocaleInfo<ThemeLocaleText> = [
|
||||
[['ko', 'ko-KR'], koLocale],
|
||||
[['en', 'en-US'], enLocale],
|
||||
[['zh', 'zh-CN', 'zh-Hans', 'zh-Hant'], zhLocale],
|
||||
[['zh-TW'], zhTwLocale],
|
||||
@ -23,10 +22,10 @@ export const LOCALE_OPTIONS: DefaultLocaleInfo<ThemeLocaleText> = [
|
||||
[['fr', 'fr-FR'], frLocale],
|
||||
[['ru', 'ru-RU'], ruLocale],
|
||||
[['ja', 'ja-JP'], jaLocale],
|
||||
[['ko', 'ko-KR'], koLocale],
|
||||
]
|
||||
|
||||
export const PRESET_LOCALES: DefaultLocaleInfo<PresetLocale> = [
|
||||
[['ko', 'ko-KR'], koPresetLocale],
|
||||
[['en', 'en-US'], enPresetLocale],
|
||||
[['zh', 'zh-CN', 'zh-Hans', 'zh-Hant'], zhPresetLocale],
|
||||
[['zh-TW'], zhTwPresetLocale],
|
||||
@ -34,4 +33,5 @@ export const PRESET_LOCALES: DefaultLocaleInfo<PresetLocale> = [
|
||||
[['fr', 'fr-FR'], frPresetLocale],
|
||||
[['ru', 'ru-RU'], ruPresetLocale],
|
||||
[['ja', 'ja-JP'], jaPresetLocale],
|
||||
[['ko', 'ko-KR'], koPresetLocale],
|
||||
]
|
||||
|
||||
@ -5,13 +5,17 @@ import { generateTOCLink as rawGenerateTOCLink, llmsPlugin as rawLlmsPlugin } fr
|
||||
import { ensureEndingSlash, ensureLeadingSlash, isPlainObject } from 'vuepress/shared'
|
||||
import { getThemeConfig } from '../loadConfig/index.js'
|
||||
import { isEncryptPage } from '../prepare/prepareEncrypt.js'
|
||||
import { withBase } from '../utils/index.js'
|
||||
import { hash, withBase } from '../utils/index.js'
|
||||
|
||||
const CODE_BLOCK_RE = /(?:^|\n)(?<marker>\s*`{3,})([\s\w])[\s\S]*?\n\k<marker>(?:\n|$)/g
|
||||
const ENCRYPT_CONTAINER_RE = /(?:^|\n)(?<marker>\s*:{3,})\s*encrypt\b[\s\S]*?\n\k<marker>(?:\n|$)/g
|
||||
const RESTORE_RE = /<!-- llms-code-block:(\w+) -->/g
|
||||
|
||||
export function llmsPlugin(app: App, userOptions: true | LlmsPluginOptions): PluginConfig {
|
||||
if (!app.env.isBuild)
|
||||
return []
|
||||
|
||||
const { llmsTxtTemplateGetter, ...userLLMsTxt } = isPlainObject(userOptions) ? userOptions : {}
|
||||
const { llmsTxtTemplateGetter, transformMarkdown, ...userLLMsTxt } = isPlainObject(userOptions) ? userOptions : {}
|
||||
|
||||
function tocGetter(llmPages: LLMPage[], llmState: LLMState): string {
|
||||
const options = getThemeConfig()
|
||||
@ -126,6 +130,21 @@ export function llmsPlugin(app: App, userOptions: true | LlmsPluginOptions): Plu
|
||||
},
|
||||
locale: '/',
|
||||
...userLLMsTxt,
|
||||
transformMarkdown(markdown, page) {
|
||||
// { hash: content }
|
||||
let rematches: Record<string, string> = {}
|
||||
markdown = markdown.replaceAll(CODE_BLOCK_RE, (content) => {
|
||||
const contentHash = hash(content)
|
||||
rematches[contentHash] = content
|
||||
return `<!-- llms-code-block:${contentHash} -->`
|
||||
})
|
||||
markdown = markdown.replaceAll(ENCRYPT_CONTAINER_RE, '')
|
||||
markdown = markdown.replaceAll(RESTORE_RE, (_, hash) => {
|
||||
return rematches[hash] || ''
|
||||
})
|
||||
rematches = {}
|
||||
return transformMarkdown?.(markdown, page) ?? markdown
|
||||
},
|
||||
llmsTxtTemplateGetter: {
|
||||
toc: tocGetter,
|
||||
...llmsTxtTemplateGetter,
|
||||
|
||||
@ -9,11 +9,10 @@ import { getThemeConfig } from '../loadConfig/index.js'
|
||||
import { createFsCache, genEncrypt, hash, perf, resolveContent, writeTemp } from '../utils/index.js'
|
||||
|
||||
export type EncryptConfig = readonly [
|
||||
boolean, // global
|
||||
string, // separator
|
||||
string, // admin
|
||||
string[], // keys
|
||||
Record<string, string>, // rules
|
||||
keys: string, // keys
|
||||
rules: string, // rules
|
||||
global: number, // global
|
||||
admin: string, // admin
|
||||
]
|
||||
|
||||
const isStringLike = (value: unknown): boolean => isString(value) || isNumber(value)
|
||||
@ -73,7 +72,12 @@ async function resolveEncrypt(encrypt?: EncryptOptions): Promise<EncryptConfig>
|
||||
}
|
||||
}
|
||||
|
||||
return [encrypt?.global ?? false, separator, admin, keys, rules]
|
||||
return [
|
||||
encodeData(JSON.stringify(keys)), // keys
|
||||
encodeData(JSON.stringify(rules)), // rules
|
||||
encrypt?.global ? 1 : 0, // global
|
||||
admin, // admin
|
||||
]
|
||||
}
|
||||
|
||||
export function isEncryptPage(page: Page<ThemePageData>, encrypt?: EncryptOptions): boolean {
|
||||
|
||||
@ -50,8 +50,8 @@ export default defineConfig((cli) => {
|
||||
...DEFAULT_OPTIONS,
|
||||
entry: ['./src/node/index.ts'],
|
||||
outDir: './lib/node',
|
||||
external: sharedExternal,
|
||||
target: 'node20.6.0',
|
||||
external: [...sharedExternal, '@pinyin-pro/data/complete'],
|
||||
target: 'node20.19.0',
|
||||
watch: false,
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@internal/md-power/replEditorData": ["./plugins/plugin-md-power/src/client/shim.d.ts"],
|
||||
"@internal/*": ["./docs/.vuepress/.temp/internal/*"],
|
||||
"@theme/*": ["./theme/src/client/components/*"]
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user