@on-panda/serve 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/bin/serve.js +65 -0
- package/package.json +23 -0
- package/server/bypassCorsProxyPlugin.js +120 -0
- package/server/runtimeImportPlugin.js +46 -0
- package/server/safeProxyMiddleware.js +18 -0
- package/server/urlVerification.js +8 -0
- package/server/usingServerProxyPlugin.js +123 -0
- package/server/webConfigPlugin.js +41 -0
- package/web/assets/AudioPlugin-B9D2vg7i.js +73 -0
- package/web/assets/AudioPlugin-Ctg1swNk.css +1 -0
- package/web/assets/ImagePlugin-B55vjXoR.css +1 -0
- package/web/assets/ImagePlugin-D-lN3l8G.js +1 -0
- package/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/web/assets/VideoPlugin-Bzko1Oof.css +1 -0
- package/web/assets/VideoPlugin-CwcxLwKM.js +1 -0
- package/web/assets/browserAgentMcp-Dpy7F3rj.js +35 -0
- package/web/assets/defaultCustom-FmFgRqLi.js +1 -0
- package/web/assets/index-6pA5bJ5o.css +10 -0
- package/web/assets/index-BWq4H1Vs.js +8 -0
- package/web/assets/index-VDofnkb1.js +701 -0
- package/web/assets/streamableHttp-P4toeGJI.js +5 -0
- package/web/assets/types-JPNfEfAJ.js +26 -0
- package/web/img/on-panda-demo-candidate-continue-generating-cn.mp4 +0 -0
- package/web/img/on-panda-logo-256x256.png +0 -0
- package/web/index.html +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @on-panda/serve
|
|
2
|
+
|
|
3
|
+
A production server for the onPanda web application. It serves the same Vite production build as `pnpm preview`, including the server proxy middleware.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @on-panda/serve --port 8080 --web_config config.json5
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Open `http://localhost:8080/`. The server listens on `0.0.0.0`, so it is also accessible through the host's network address.
|
|
12
|
+
|
|
13
|
+
| Option | Default | Meaning |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| `--web_config` | Omitted | JSON5 configuration file loaded by the web UI. When omitted, the config endpoint returns `{}`. |
|
|
16
|
+
| `--port` | `4173` | HTTP port. |
|
|
17
|
+
| `--help`, `-h` | | Print usage and exit. |
|
|
18
|
+
|
|
19
|
+
Relative paths for `--web_config` are resolved against the working directory where the command is run.
|
|
20
|
+
|
|
21
|
+
The server has no authentication. The web configuration is returned to browser clients, so its values should be treated as public.
|
package/bin/serve.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { preview } from 'vite'
|
|
6
|
+
|
|
7
|
+
import { createBypassCorsProxyPlugin } from '../server/bypassCorsProxyPlugin.js'
|
|
8
|
+
import { createRuntimeImportPlugin } from '../server/runtimeImportPlugin.js'
|
|
9
|
+
import { createUsingServerProxyPlugin } from '../server/usingServerProxyPlugin.js'
|
|
10
|
+
import { createWebConfigPlugin } from '../server/webConfigPlugin.js'
|
|
11
|
+
|
|
12
|
+
const packageDir = fileURLToPath(new URL('..', import.meta.url))
|
|
13
|
+
|
|
14
|
+
function parseArgs(args) {
|
|
15
|
+
const options = {
|
|
16
|
+
port: 4173,
|
|
17
|
+
webConfig: '',
|
|
18
|
+
}
|
|
19
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
20
|
+
const arg = args[index]
|
|
21
|
+
if (arg === '--web_config') {
|
|
22
|
+
options.webConfig = args[++index]
|
|
23
|
+
} else if (arg === '--port') {
|
|
24
|
+
options.port = Number(args[++index])
|
|
25
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
26
|
+
console.log('Usage: serve [--web_config web_config.json5] [--port 4173]')
|
|
27
|
+
process.exit(0)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
...options,
|
|
32
|
+
webConfig: options.webConfig ? path.resolve(options.webConfig) : '',
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function startServer(options) {
|
|
37
|
+
const runtimeImportPath = process.env.VITE_ON_PANDA_WEB_RUNTIME_IMPORT
|
|
38
|
+
? path.resolve(process.cwd(), process.env.VITE_ON_PANDA_WEB_RUNTIME_IMPORT)
|
|
39
|
+
: ''
|
|
40
|
+
const server = await preview({
|
|
41
|
+
root: packageDir,
|
|
42
|
+
appType: 'spa',
|
|
43
|
+
plugins: [
|
|
44
|
+
createBypassCorsProxyPlugin(process.env.VITE_ON_PANDA_BROWSER_AGENT_PROXY_PATH),
|
|
45
|
+
createRuntimeImportPlugin(runtimeImportPath),
|
|
46
|
+
createUsingServerProxyPlugin(),
|
|
47
|
+
createWebConfigPlugin(options.webConfig),
|
|
48
|
+
],
|
|
49
|
+
build: {
|
|
50
|
+
outDir: 'web',
|
|
51
|
+
},
|
|
52
|
+
preview: {
|
|
53
|
+
host: '0.0.0.0',
|
|
54
|
+
port: options.port,
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
const [url] = server.resolvedUrls.local
|
|
58
|
+
console.log(`onPanda web server: ${url}`)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const options = parseArgs(process.argv.slice(2))
|
|
62
|
+
startServer(options).catch(error => {
|
|
63
|
+
console.error(error)
|
|
64
|
+
process.exitCode = 1
|
|
65
|
+
})
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@on-panda/serve",
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "A production server for the onPanda web application",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"serve": "./bin/serve.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"server",
|
|
13
|
+
"web"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"json5": "^2.x",
|
|
17
|
+
"undici": "^7.x",
|
|
18
|
+
"vite": "^5.3.1"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"preview": "node bin/serve.js"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Readable } from 'node:stream'
|
|
2
|
+
|
|
3
|
+
import { withSafeProxyMiddleware } from './safeProxyMiddleware.js'
|
|
4
|
+
import { verifyUrlIsLlmApiCall, verifyUrlIsMcp } from './urlVerification.js'
|
|
5
|
+
|
|
6
|
+
export function createBypassCorsProxyPlugin(browserAgentProxyPath = '') {
|
|
7
|
+
const corsMiddleware = withSafeProxyMiddleware('Bypass CORS proxy', createBypassCorsProxyMiddleware({
|
|
8
|
+
verifyUrl: targetUrl => verifyUrlIsLlmApiCall(targetUrl) || verifyUrlIsMcp(targetUrl),
|
|
9
|
+
}))
|
|
10
|
+
// Browser-agent proxy: forwards arbitrary URLs as a fallback for cors-internet.
|
|
11
|
+
const browserAgentMiddleware = browserAgentProxyPath
|
|
12
|
+
? withSafeProxyMiddleware('Browser agent proxy', createBypassCorsProxyMiddleware())
|
|
13
|
+
: null
|
|
14
|
+
const register = (server) => {
|
|
15
|
+
server.middlewares.use('/bypass-CORS', corsMiddleware)
|
|
16
|
+
if (browserAgentMiddleware) server.middlewares.use(browserAgentProxyPath, browserAgentMiddleware)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
name: 'bypass-cors-proxy-middleware',
|
|
21
|
+
configureServer: register,
|
|
22
|
+
configurePreviewServer: register,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createBypassCorsProxyMiddleware({ verifyUrl } = {}) {
|
|
27
|
+
return async (req, res) => {
|
|
28
|
+
const abortController = new AbortController()
|
|
29
|
+
try {
|
|
30
|
+
const rawPath = req.url || ''
|
|
31
|
+
const withoutPrefix = rawPath.startsWith('/bypass-CORS/')
|
|
32
|
+
? rawPath.replace(/^\/bypass-CORS\//, '')
|
|
33
|
+
: rawPath.replace(/^\/+/, '')
|
|
34
|
+
const targetUrl = new URL(decodeURIComponent(withoutPrefix))
|
|
35
|
+
if (verifyUrl && !verifyUrl(targetUrl)) {
|
|
36
|
+
res.statusCode = 400
|
|
37
|
+
res.end(`Not an allowed target URL: ${targetUrl}`)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const method = req.method || 'GET'
|
|
42
|
+
const hopByHopHeaders = new Set(['connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'te', 'trailers', 'transfer-encoding', 'upgrade', 'host'])
|
|
43
|
+
const headers = new Headers()
|
|
44
|
+
const abortUpstream = () => abortController.abort()
|
|
45
|
+
req.on('aborted', abortUpstream)
|
|
46
|
+
res.on('close', () => {
|
|
47
|
+
if (!res.writableEnded) {
|
|
48
|
+
abortUpstream()
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
Object.entries(req.headers).forEach(([key, value]) => {
|
|
52
|
+
if (!value || hopByHopHeaders.has(key.toLowerCase()) || key.toLowerCase() === 'accept-encoding') {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
const values = Array.isArray(value) ? value : [value]
|
|
56
|
+
values.forEach(val => headers.append(key, val))
|
|
57
|
+
})
|
|
58
|
+
headers.set('accept-encoding', 'identity')
|
|
59
|
+
|
|
60
|
+
const fetchInit = {
|
|
61
|
+
method,
|
|
62
|
+
headers,
|
|
63
|
+
compress: false,
|
|
64
|
+
signal: abortController.signal,
|
|
65
|
+
}
|
|
66
|
+
const hasBody = !['GET', 'HEAD'].includes(method.toUpperCase())
|
|
67
|
+
if (hasBody) {
|
|
68
|
+
fetchInit.body = req
|
|
69
|
+
fetchInit.duplex = 'half'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const upstreamResponse = await fetch(targetUrl.toString(), fetchInit)
|
|
73
|
+
res.statusCode = upstreamResponse.status
|
|
74
|
+
const upstreamContentEncoding = upstreamResponse.headers.get('content-encoding')
|
|
75
|
+
const shouldNormalizeContentEncoding = upstreamContentEncoding && upstreamContentEncoding.toLowerCase() !== 'identity'
|
|
76
|
+
if (shouldNormalizeContentEncoding) {
|
|
77
|
+
res.setHeader('content-encoding', 'identity')
|
|
78
|
+
}
|
|
79
|
+
upstreamResponse.headers.forEach((value, key) => {
|
|
80
|
+
const lowerKey = key.toLowerCase()
|
|
81
|
+
if (hopByHopHeaders.has(lowerKey)) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
if (shouldNormalizeContentEncoding && ['content-encoding', 'content-length'].includes(lowerKey)) {
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
res.setHeader(key, value)
|
|
88
|
+
})
|
|
89
|
+
if (!upstreamResponse.body) {
|
|
90
|
+
res.end()
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
const proxyStream = Readable.fromWeb(upstreamResponse.body)
|
|
94
|
+
proxyStream.on('error', (err) => {
|
|
95
|
+
if (abortController.signal.aborted) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
console.error('Bypass CORS proxy stream failed', err)
|
|
99
|
+
if (!res.headersSent) {
|
|
100
|
+
res.statusCode = 502
|
|
101
|
+
res.setHeader('content-type', 'text/plain')
|
|
102
|
+
res.end('Proxy stream error')
|
|
103
|
+
} else {
|
|
104
|
+
res.destroy(err)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
proxyStream.pipe(res)
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (abortController.signal.aborted) {
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
console.error('Bypass CORS proxy failed', error)
|
|
113
|
+
if (!res.headersSent) {
|
|
114
|
+
res.statusCode = 500
|
|
115
|
+
res.setHeader('content-type', 'text/plain')
|
|
116
|
+
}
|
|
117
|
+
res.end(`Proxy error: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import fsPromises from 'node:fs/promises'
|
|
3
|
+
|
|
4
|
+
export function createRuntimeImportPlugin(runtimeImportPath) {
|
|
5
|
+
// For configurations that are included in `pnpm dev`/`preview` but not in git or the build.
|
|
6
|
+
if (!runtimeImportPath) {
|
|
7
|
+
return null
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(runtimeImportPath)) {
|
|
11
|
+
throw new Error(`VITE_ON_PANDA_WEB_RUNTIME_IMPORT file not found: ${runtimeImportPath}`)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
name: 'on-panda-web-runtime-import',
|
|
16
|
+
configureServer(server) {
|
|
17
|
+
server.middlewares.use('/on-panda-web-runtime.js', createRuntimeFileMiddleware(runtimeImportPath))
|
|
18
|
+
},
|
|
19
|
+
configurePreviewServer(server) {
|
|
20
|
+
server.middlewares.use('/on-panda-web-runtime.js', createRuntimeFileMiddleware(runtimeImportPath))
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createRuntimeFileMiddleware(filePath) {
|
|
26
|
+
return async (req, res) => {
|
|
27
|
+
if (!['GET', 'HEAD'].includes(req.method || 'GET')) {
|
|
28
|
+
res.statusCode = 405
|
|
29
|
+
res.end('Method Not Allowed')
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const data = await fsPromises.readFile(filePath)
|
|
34
|
+
res.statusCode = 200
|
|
35
|
+
res.setHeader('content-type', 'text/javascript; charset=utf-8')
|
|
36
|
+
if (req.method === 'HEAD') {
|
|
37
|
+
res.end()
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
res.end(data)
|
|
41
|
+
} catch {
|
|
42
|
+
res.statusCode = 404
|
|
43
|
+
res.end('Not Found')
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function withSafeProxyMiddleware(proxyName, middleware) {
|
|
2
|
+
return async (req, res) => {
|
|
3
|
+
try {
|
|
4
|
+
await middleware(req, res)
|
|
5
|
+
} catch (error) {
|
|
6
|
+
console.error(`${proxyName} crashed`, error)
|
|
7
|
+
if (res.headersSent) {
|
|
8
|
+
if (!res.writableEnded) {
|
|
9
|
+
res.end()
|
|
10
|
+
}
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
res.statusCode = 500
|
|
14
|
+
res.setHeader('content-type', 'text/plain')
|
|
15
|
+
res.end(`Proxy error: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function verifyUrlIsLlmApiCall(url) {
|
|
2
|
+
// check is LLM api call by /models or /completions
|
|
3
|
+
return /(^|\/)(models|completions|messages)(\/|$)/.test(url.pathname)
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function verifyUrlIsMcp(url) {
|
|
7
|
+
return /(^|\/)mcp(\/|$)/.test(url.pathname)
|
|
8
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Readable } from 'node:stream'
|
|
2
|
+
|
|
3
|
+
import { ProxyAgent } from 'undici'
|
|
4
|
+
|
|
5
|
+
import { withSafeProxyMiddleware } from './safeProxyMiddleware.js'
|
|
6
|
+
import { verifyUrlIsLlmApiCall } from './urlVerification.js'
|
|
7
|
+
|
|
8
|
+
export function createUsingServerProxyPlugin() {
|
|
9
|
+
const middleware = withSafeProxyMiddleware('Server proxy', createServerProxyMiddleware())
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
name: 'using-server-proxy-middleware',
|
|
13
|
+
configureServer(server) {
|
|
14
|
+
server.middlewares.use('/using-server-proxy', middleware)
|
|
15
|
+
},
|
|
16
|
+
configurePreviewServer(server) {
|
|
17
|
+
server.middlewares.use('/using-server-proxy', middleware)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function createServerProxyMiddleware() {
|
|
23
|
+
return async (req, res) => {
|
|
24
|
+
const abortController = new AbortController()
|
|
25
|
+
try {
|
|
26
|
+
const rawPath = req.url || ''
|
|
27
|
+
const withoutPrefix = rawPath.startsWith('/using-server-proxy/')
|
|
28
|
+
? rawPath.replace(/^\/using-server-proxy\//, '')
|
|
29
|
+
: rawPath.replace(/^\/+/, '')
|
|
30
|
+
const incomingPath = decodeURIComponent(withoutPrefix)
|
|
31
|
+
const match = incomingPath.match(/^(?<proxy>[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^/]+)\/(?<target>https?:\/\/.+)$/)
|
|
32
|
+
if (!match || !match.groups) {
|
|
33
|
+
res.statusCode = 400
|
|
34
|
+
res.end('Invalid proxy request: expected /using-server-proxy/<proxy>/<target>')
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
const { proxy: proxyUrl, target } = match.groups
|
|
38
|
+
const targetUrl = new URL(target)
|
|
39
|
+
if (!verifyUrlIsLlmApiCall(targetUrl)) {
|
|
40
|
+
throw new Error(`Not a valid LLM API call: ${targetUrl}`)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const method = req.method || 'GET'
|
|
44
|
+
const hopByHopHeaders = new Set(['connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'te', 'trailers', 'transfer-encoding', 'upgrade', 'host'])
|
|
45
|
+
const headers = new Headers()
|
|
46
|
+
const abortUpstream = () => abortController.abort()
|
|
47
|
+
req.on('aborted', abortUpstream)
|
|
48
|
+
res.on('close', () => {
|
|
49
|
+
if (!res.writableEnded) {
|
|
50
|
+
abortUpstream()
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
Object.entries(req.headers).forEach(([key, value]) => {
|
|
54
|
+
if (!value || hopByHopHeaders.has(key.toLowerCase()) || key.toLowerCase() === 'accept-encoding') {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
const values = Array.isArray(value) ? value : [value]
|
|
58
|
+
values.forEach(val => headers.append(key, val))
|
|
59
|
+
})
|
|
60
|
+
headers.set('accept-encoding', 'identity')
|
|
61
|
+
|
|
62
|
+
const fetchInit = {
|
|
63
|
+
method,
|
|
64
|
+
headers,
|
|
65
|
+
dispatcher: new ProxyAgent(proxyUrl),
|
|
66
|
+
compress: false,
|
|
67
|
+
signal: abortController.signal,
|
|
68
|
+
}
|
|
69
|
+
const hasBody = !['GET', 'HEAD'].includes(method.toUpperCase())
|
|
70
|
+
if (hasBody) {
|
|
71
|
+
fetchInit.body = req
|
|
72
|
+
fetchInit.duplex = 'half'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const upstreamResponse = await fetch(targetUrl.toString(), fetchInit)
|
|
76
|
+
res.statusCode = upstreamResponse.status
|
|
77
|
+
const upstreamContentEncoding = upstreamResponse.headers.get('content-encoding')
|
|
78
|
+
const shouldNormalizeContentEncoding = upstreamContentEncoding && upstreamContentEncoding.toLowerCase() !== 'identity'
|
|
79
|
+
if (shouldNormalizeContentEncoding) {
|
|
80
|
+
res.setHeader('content-encoding', 'identity')
|
|
81
|
+
}
|
|
82
|
+
upstreamResponse.headers.forEach((value, key) => {
|
|
83
|
+
const lowerKey = key.toLowerCase()
|
|
84
|
+
if (hopByHopHeaders.has(lowerKey)) {
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
if (shouldNormalizeContentEncoding && ['content-encoding', 'content-length'].includes(lowerKey)) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
res.setHeader(key, value)
|
|
91
|
+
})
|
|
92
|
+
if (!upstreamResponse.body) {
|
|
93
|
+
res.end()
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
const proxyStream = Readable.fromWeb(upstreamResponse.body)
|
|
97
|
+
proxyStream.on('error', (err) => {
|
|
98
|
+
if (abortController.signal.aborted) {
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
console.error('Server proxy stream failed', err)
|
|
102
|
+
if (!res.headersSent) {
|
|
103
|
+
res.statusCode = 502
|
|
104
|
+
res.setHeader('content-type', 'text/plain')
|
|
105
|
+
res.end('Proxy stream error')
|
|
106
|
+
} else {
|
|
107
|
+
res.destroy(err)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
proxyStream.pipe(res)
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (abortController.signal.aborted) {
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
console.error('Server proxy failed', error)
|
|
116
|
+
if (!res.headersSent) {
|
|
117
|
+
res.statusCode = 500
|
|
118
|
+
res.setHeader('content-type', 'text/plain')
|
|
119
|
+
}
|
|
120
|
+
res.end(`Proxy error: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
|
|
3
|
+
import JSON5 from 'json5'
|
|
4
|
+
|
|
5
|
+
const webConfigUrl = '/on-panda-web/web_config.json5'
|
|
6
|
+
|
|
7
|
+
export function createWebConfigPlugin(webConfigPath = '') {
|
|
8
|
+
const middleware = createWebConfigMiddleware(webConfigPath)
|
|
9
|
+
return {
|
|
10
|
+
name: 'on-panda-web-config',
|
|
11
|
+
configureServer(server) {
|
|
12
|
+
server.middlewares.use(webConfigUrl, middleware)
|
|
13
|
+
},
|
|
14
|
+
configurePreviewServer(server) {
|
|
15
|
+
server.middlewares.use(webConfigUrl, middleware)
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function createWebConfigMiddleware(webConfigPath) {
|
|
21
|
+
return async (req, res) => {
|
|
22
|
+
if (!['GET', 'HEAD'].includes(req.method || 'GET')) {
|
|
23
|
+
res.statusCode = 405
|
|
24
|
+
res.end('Method Not Allowed')
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const config = webConfigPath ? JSON5.parse(await fs.readFile(webConfigPath, 'utf8')) : {}
|
|
29
|
+
const body = JSON.stringify(config)
|
|
30
|
+
res.statusCode = 200
|
|
31
|
+
res.setHeader('content-type', 'application/json; charset=utf-8')
|
|
32
|
+
res.setHeader('cache-control', 'no-store')
|
|
33
|
+
res.setHeader('content-length', Buffer.byteLength(body))
|
|
34
|
+
res.end(req.method === 'HEAD' ? undefined : body)
|
|
35
|
+
} catch (error) {
|
|
36
|
+
res.statusCode = error.code === 'ENOENT' ? 404 : 400
|
|
37
|
+
res.setHeader('content-type', 'text/plain; charset=utf-8')
|
|
38
|
+
res.end(error.message)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import{_ as U,r as W,c as F,m as V,w as q,b as G,d as Y,o as $,a as B,e as j,f as J}from"./index-VDofnkb1.js";function y(c,t,e,i){return new(e||(e=Promise))(function(s,n){function r(o){try{l(i.next(o))}catch(h){n(h)}}function a(o){try{l(i.throw(o))}catch(h){n(h)}}function l(o){var h;o.done?s(o.value):(h=o.value,h instanceof e?h:new e(function(u){u(h)})).then(r,a)}l((i=i.apply(c,t||[])).next())})}let R=class{constructor(){this.listeners={}}on(t,e,i){if(this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),i==null?void 0:i.once){const s=()=>{this.un(t,s),this.un(t,e)};return this.on(t,s),s}return()=>this.un(t,e)}un(t,e){var i;(i=this.listeners[t])===null||i===void 0||i.delete(e)}once(t,e){return this.on(t,e,{once:!0})}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach(i=>i(...e))}};const L={decode:function(c,t){return y(this,void 0,void 0,function*(){const e=new AudioContext({sampleRate:t});return e.decodeAudioData(c).finally(()=>e.close())})},createBuffer:function(c,t){return typeof c[0]=="number"&&(c=[c]),function(e){const i=e[0];if(i.some(s=>s>1||s<-1)){const s=i.length;let n=0;for(let r=0;r<s;r++){const a=Math.abs(i[r]);a>n&&(n=a)}for(const r of e)for(let a=0;a<s;a++)r[a]/=n}}(c),{duration:t,length:c[0].length,sampleRate:c[0].length/t,numberOfChannels:c.length,getChannelData:e=>c==null?void 0:c[e],copyFromChannel:AudioBuffer.prototype.copyFromChannel,copyToChannel:AudioBuffer.prototype.copyToChannel}}};function H(c,t){const e=t.xmlns?document.createElementNS(t.xmlns,c):document.createElement(c);for(const[i,s]of Object.entries(t))if(i==="children")for(const[n,r]of Object.entries(t))typeof r=="string"?e.appendChild(document.createTextNode(r)):e.appendChild(H(n,r));else i==="style"?Object.assign(e.style,s):i==="textContent"?e.textContent=s:e.setAttribute(i,s.toString());return e}function z(c,t,e){const i=H(c,t||{});return e==null||e.appendChild(i),i}var K=Object.freeze({__proto__:null,createElement:z,default:z});const Q={fetchBlob:function(c,t,e){return y(this,void 0,void 0,function*(){const i=yield fetch(c,e);if(i.status>=400)throw new Error(`Failed to fetch ${c}: ${i.status} (${i.statusText})`);return function(s,n){y(this,void 0,void 0,function*(){if(!s.body||!s.headers)return;const r=s.body.getReader(),a=Number(s.headers.get("Content-Length"))||0;let l=0;const o=u=>y(this,void 0,void 0,function*(){l+=(u==null?void 0:u.length)||0;const d=Math.round(l/a*100);n(d)}),h=()=>y(this,void 0,void 0,function*(){let u;try{u=yield r.read()}catch{return}u.done||(o(u.value),yield h())});h()})}(i.clone(),t),i.blob()})}};class Z extends R{constructor(t){super(),this.isExternalMedia=!1,t.media?(this.media=t.media,this.isExternalMedia=!0):this.media=document.createElement("audio"),t.mediaControls&&(this.media.controls=!0),t.autoplay&&(this.media.autoplay=!0),t.playbackRate!=null&&this.onMediaEvent("canplay",()=>{t.playbackRate!=null&&(this.media.playbackRate=t.playbackRate)},{once:!0})}onMediaEvent(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e,i)}getSrc(){return this.media.currentSrc||this.media.src||""}revokeSrc(){const t=this.getSrc();t.startsWith("blob:")&&URL.revokeObjectURL(t)}canPlayType(t){return this.media.canPlayType(t)!==""}setSrc(t,e){const i=this.getSrc();if(t&&i===t)return;this.revokeSrc();const s=e instanceof Blob&&(this.canPlayType(e.type)||!t)?URL.createObjectURL(e):t;i&&(this.media.src="");try{this.media.src=s}catch{this.media.src=t}}destroy(){this.isExternalMedia||(this.media.pause(),this.media.remove(),this.revokeSrc(),this.media.src="",this.media.load())}setMediaElement(t){this.media=t}play(){return y(this,void 0,void 0,function*(){return this.media.play()})}pause(){this.media.pause()}isPlaying(){return!this.media.paused&&!this.media.ended}setTime(t){this.media.currentTime=Math.max(0,Math.min(t,this.getDuration()))}getDuration(){return this.media.duration}getCurrentTime(){return this.media.currentTime}getVolume(){return this.media.volume}setVolume(t){this.media.volume=t}getMuted(){return this.media.muted}setMuted(t){this.media.muted=t}getPlaybackRate(){return this.media.playbackRate}isSeeking(){return this.media.seeking}setPlaybackRate(t,e){e!=null&&(this.media.preservesPitch=e),this.media.playbackRate=t}getMediaElement(){return this.media}setSinkId(t){return this.media.setSinkId(t)}}class T extends R{constructor(t,e){super(),this.timeouts=[],this.isScrollable=!1,this.audioData=null,this.resizeObserver=null,this.lastContainerWidth=0,this.isDragging=!1,this.subscriptions=[],this.unsubscribeOnScroll=[],this.subscriptions=[],this.options=t;const i=this.parentFromOptionsContainer(t.container);this.parent=i;const[s,n]=this.initHtml();i.appendChild(s),this.container=s,this.scrollContainer=n.querySelector(".scroll"),this.wrapper=n.querySelector(".wrapper"),this.canvasWrapper=n.querySelector(".canvases"),this.progressWrapper=n.querySelector(".progress"),this.cursor=n.querySelector(".cursor"),e&&n.appendChild(e),this.initEvents()}parentFromOptionsContainer(t){let e;if(typeof t=="string"?e=document.querySelector(t):t instanceof HTMLElement&&(e=t),!e)throw new Error("Container not found");return e}initEvents(){const t=e=>{const i=this.wrapper.getBoundingClientRect(),s=e.clientX-i.left,n=e.clientY-i.top;return[s/i.width,n/i.height]};if(this.wrapper.addEventListener("click",e=>{const[i,s]=t(e);this.emit("click",i,s)}),this.wrapper.addEventListener("dblclick",e=>{const[i,s]=t(e);this.emit("dblclick",i,s)}),this.options.dragToSeek!==!0&&typeof this.options.dragToSeek!="object"||this.initDrag(),this.scrollContainer.addEventListener("scroll",()=>{const{scrollLeft:e,scrollWidth:i,clientWidth:s}=this.scrollContainer,n=e/i,r=(e+s)/i;this.emit("scroll",n,r,e,e+s)}),typeof ResizeObserver=="function"){const e=this.createDelay(100);this.resizeObserver=new ResizeObserver(()=>{e().then(()=>this.onContainerResize()).catch(()=>{})}),this.resizeObserver.observe(this.scrollContainer)}}onContainerResize(){const t=this.parent.clientWidth;t===this.lastContainerWidth&&this.options.height!=="auto"||(this.lastContainerWidth=t,this.reRender())}initDrag(){this.subscriptions.push(function(t,e,i,s,n=3,r=0,a=100){if(!t)return()=>{};const l=matchMedia("(pointer: coarse)").matches;let o=()=>{};const h=u=>{if(u.button!==r)return;u.preventDefault(),u.stopPropagation();let d=u.clientX,p=u.clientY,m=!1;const w=Date.now(),f=v=>{if(v.preventDefault(),v.stopPropagation(),l&&Date.now()-w<a)return;const S=v.clientX,x=v.clientY,P=S-d,M=x-p;if(m||Math.abs(P)>n||Math.abs(M)>n){const k=t.getBoundingClientRect(),{left:A,top:N}=k;m||(i==null||i(d-A,p-N),m=!0),e(P,M,S-A,x-N),d=S,p=x}},g=v=>{if(m){const S=v.clientX,x=v.clientY,P=t.getBoundingClientRect(),{left:M,top:k}=P;s==null||s(S-M,x-k)}o()},b=v=>{v.relatedTarget&&v.relatedTarget!==document.documentElement||g(v)},E=v=>{m&&(v.stopPropagation(),v.preventDefault())},C=v=>{m&&v.preventDefault()};document.addEventListener("pointermove",f),document.addEventListener("pointerup",g),document.addEventListener("pointerout",b),document.addEventListener("pointercancel",b),document.addEventListener("touchmove",C,{passive:!1}),document.addEventListener("click",E,{capture:!0}),o=()=>{document.removeEventListener("pointermove",f),document.removeEventListener("pointerup",g),document.removeEventListener("pointerout",b),document.removeEventListener("pointercancel",b),document.removeEventListener("touchmove",C),setTimeout(()=>{document.removeEventListener("click",E,{capture:!0})},10)}};return t.addEventListener("pointerdown",h),()=>{o(),t.removeEventListener("pointerdown",h)}}(this.wrapper,(t,e,i)=>{this.emit("drag",Math.max(0,Math.min(1,i/this.wrapper.getBoundingClientRect().width)))},t=>{this.isDragging=!0,this.emit("dragstart",Math.max(0,Math.min(1,t/this.wrapper.getBoundingClientRect().width)))},t=>{this.isDragging=!1,this.emit("dragend",Math.max(0,Math.min(1,t/this.wrapper.getBoundingClientRect().width)))}))}getHeight(t,e){var i;const s=((i=this.audioData)===null||i===void 0?void 0:i.numberOfChannels)||1;if(t==null)return 128;if(!isNaN(Number(t)))return Number(t);if(t==="auto"){const n=this.parent.clientHeight||128;return e!=null&&e.every(r=>!r.overlay)?n/s:n}return 128}initHtml(){const t=document.createElement("div"),e=t.attachShadow({mode:"open"}),i=this.options.cspNonce&&typeof this.options.cspNonce=="string"?this.options.cspNonce.replace(/"/g,""):"";return e.innerHTML=`
|
|
2
|
+
<style${i?` nonce="${i}"`:""}>
|
|
3
|
+
:host {
|
|
4
|
+
user-select: none;
|
|
5
|
+
min-width: 1px;
|
|
6
|
+
}
|
|
7
|
+
:host audio {
|
|
8
|
+
display: block;
|
|
9
|
+
width: 100%;
|
|
10
|
+
}
|
|
11
|
+
:host .scroll {
|
|
12
|
+
overflow-x: auto;
|
|
13
|
+
overflow-y: hidden;
|
|
14
|
+
width: 100%;
|
|
15
|
+
position: relative;
|
|
16
|
+
}
|
|
17
|
+
:host .noScrollbar {
|
|
18
|
+
scrollbar-color: transparent;
|
|
19
|
+
scrollbar-width: none;
|
|
20
|
+
}
|
|
21
|
+
:host .noScrollbar::-webkit-scrollbar {
|
|
22
|
+
display: none;
|
|
23
|
+
-webkit-appearance: none;
|
|
24
|
+
}
|
|
25
|
+
:host .wrapper {
|
|
26
|
+
position: relative;
|
|
27
|
+
overflow: visible;
|
|
28
|
+
z-index: 2;
|
|
29
|
+
}
|
|
30
|
+
:host .canvases {
|
|
31
|
+
min-height: ${this.getHeight(this.options.height,this.options.splitChannels)}px;
|
|
32
|
+
}
|
|
33
|
+
:host .canvases > div {
|
|
34
|
+
position: relative;
|
|
35
|
+
}
|
|
36
|
+
:host canvas {
|
|
37
|
+
display: block;
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: 0;
|
|
40
|
+
image-rendering: pixelated;
|
|
41
|
+
}
|
|
42
|
+
:host .progress {
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
position: absolute;
|
|
45
|
+
z-index: 2;
|
|
46
|
+
top: 0;
|
|
47
|
+
left: 0;
|
|
48
|
+
width: 0;
|
|
49
|
+
height: 100%;
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
}
|
|
52
|
+
:host .progress > div {
|
|
53
|
+
position: relative;
|
|
54
|
+
}
|
|
55
|
+
:host .cursor {
|
|
56
|
+
pointer-events: none;
|
|
57
|
+
position: absolute;
|
|
58
|
+
z-index: 5;
|
|
59
|
+
top: 0;
|
|
60
|
+
left: 0;
|
|
61
|
+
height: 100%;
|
|
62
|
+
border-radius: 2px;
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
65
|
+
|
|
66
|
+
<div class="scroll" part="scroll">
|
|
67
|
+
<div class="wrapper" part="wrapper">
|
|
68
|
+
<div class="canvases" part="canvases"></div>
|
|
69
|
+
<div class="progress" part="progress"></div>
|
|
70
|
+
<div class="cursor" part="cursor"></div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
`,[t,e]}setOptions(t){if(this.options.container!==t.container){const e=this.parentFromOptionsContainer(t.container);e.appendChild(this.container),this.parent=e}t.dragToSeek!==!0&&typeof this.options.dragToSeek!="object"||this.initDrag(),this.options=t,this.reRender()}getWrapper(){return this.wrapper}getWidth(){return this.scrollContainer.clientWidth}getScroll(){return this.scrollContainer.scrollLeft}setScroll(t){this.scrollContainer.scrollLeft=t}setScrollPercentage(t){const{scrollWidth:e}=this.scrollContainer,i=e*t;this.setScroll(i)}destroy(){var t,e;this.subscriptions.forEach(i=>i()),this.container.remove(),(t=this.resizeObserver)===null||t===void 0||t.disconnect(),(e=this.unsubscribeOnScroll)===null||e===void 0||e.forEach(i=>i()),this.unsubscribeOnScroll=[]}createDelay(t=10){let e,i;const s=()=>{e&&clearTimeout(e),i&&i()};return this.timeouts.push(s),()=>new Promise((n,r)=>{s(),i=r,e=setTimeout(()=>{e=void 0,i=void 0,n()},t)})}convertColorValues(t){if(!Array.isArray(t))return t||"";if(t.length<2)return t[0]||"";const e=document.createElement("canvas"),i=e.getContext("2d"),s=e.height*(window.devicePixelRatio||1),n=i.createLinearGradient(0,0,0,s),r=1/(t.length-1);return t.forEach((a,l)=>{const o=l*r;n.addColorStop(o,a)}),n}getPixelRatio(){return Math.max(1,window.devicePixelRatio||1)}renderBarWaveform(t,e,i,s){const n=t[0],r=t[1]||t[0],a=n.length,{width:l,height:o}=i.canvas,h=o/2,u=this.getPixelRatio(),d=e.barWidth?e.barWidth*u:1,p=e.barGap?e.barGap*u:e.barWidth?d/2:0,m=e.barRadius||0,w=l/(d+p)/a,f=m&&"roundRect"in i?"roundRect":"rect";i.beginPath();let g=0,b=0,E=0;for(let C=0;C<=a;C++){const v=Math.round(C*w);if(v>g){const P=Math.round(b*h*s),M=P+Math.round(E*h*s)||1;let k=h-P;e.barAlign==="top"?k=0:e.barAlign==="bottom"&&(k=o-M),i[f](g*(d+p),k,d,M,m),g=v,b=0,E=0}const S=Math.abs(n[C]||0),x=Math.abs(r[C]||0);S>b&&(b=S),x>E&&(E=x)}i.fill(),i.closePath()}renderLineWaveform(t,e,i,s){const n=r=>{const a=t[r]||t[0],l=a.length,{height:o}=i.canvas,h=o/2,u=i.canvas.width/l;i.moveTo(0,h);let d=0,p=0;for(let m=0;m<=l;m++){const w=Math.round(m*u);if(w>d){const g=h+(Math.round(p*h*s)||1)*(r===0?-1:1);i.lineTo(d,g),d=w,p=0}const f=Math.abs(a[m]||0);f>p&&(p=f)}i.lineTo(d,h)};i.beginPath(),n(0),n(1),i.fill(),i.closePath()}renderWaveform(t,e,i){if(i.fillStyle=this.convertColorValues(e.waveColor),e.renderFunction)return void e.renderFunction(t,i);let s=e.barHeight||1;if(e.normalize){const n=Array.from(t[0]).reduce((r,a)=>Math.max(r,Math.abs(a)),0);s=n?1/n:1}e.barWidth||e.barGap||e.barAlign?this.renderBarWaveform(t,e,i,s):this.renderLineWaveform(t,e,i,s)}renderSingleCanvas(t,e,i,s,n,r,a){const l=this.getPixelRatio(),o=document.createElement("canvas");o.width=Math.round(i*l),o.height=Math.round(s*l),o.style.width=`${i}px`,o.style.height=`${s}px`,o.style.left=`${Math.round(n)}px`,r.appendChild(o);const h=o.getContext("2d");if(this.renderWaveform(t,e,h),o.width>0&&o.height>0){const u=o.cloneNode(),d=u.getContext("2d");d.drawImage(o,0,0),d.globalCompositeOperation="source-in",d.fillStyle=this.convertColorValues(e.progressColor),d.fillRect(0,0,o.width,o.height),a.appendChild(u)}}renderMultiCanvas(t,e,i,s,n,r){const a=this.getPixelRatio(),{clientWidth:l}=this.scrollContainer,o=i/a;let h=Math.min(T.MAX_CANVAS_WIDTH,l,o),u={};if(h===0)return;if(e.barWidth||e.barGap){const f=e.barWidth||.5,g=f+(e.barGap||f/2);h%g!=0&&(h=Math.floor(h/g)*g)}const d=f=>{if(f<0||f>=p||u[f])return;u[f]=!0;const g=f*h,b=Math.min(o-g,h);if(b<=0)return;const E=t.map(C=>{const v=Math.floor(g/o*C.length),S=Math.floor((g+b)/o*C.length);return C.slice(v,S)});this.renderSingleCanvas(E,e,b,s,g,n,r)},p=Math.ceil(o/h);if(!this.isScrollable){for(let f=0;f<p;f++)d(f);return}const m=this.scrollContainer.scrollLeft/o,w=Math.floor(m*p);if(d(w-1),d(w),d(w+1),p>1){const f=this.on("scroll",()=>{const{scrollLeft:g}=this.scrollContainer,b=Math.floor(g/o*p);Object.keys(u).length>T.MAX_NODES&&(n.innerHTML="",r.innerHTML="",u={}),d(b-1),d(b),d(b+1)});this.unsubscribeOnScroll.push(f)}}renderChannel(t,e,i,s){var{overlay:n}=e,r=function(h,u){var d={};for(var p in h)Object.prototype.hasOwnProperty.call(h,p)&&u.indexOf(p)<0&&(d[p]=h[p]);if(h!=null&&typeof Object.getOwnPropertySymbols=="function"){var m=0;for(p=Object.getOwnPropertySymbols(h);m<p.length;m++)u.indexOf(p[m])<0&&Object.prototype.propertyIsEnumerable.call(h,p[m])&&(d[p[m]]=h[p[m]])}return d}(e,["overlay"]);const a=document.createElement("div"),l=this.getHeight(r.height,r.splitChannels);a.style.height=`${l}px`,n&&s>0&&(a.style.marginTop=`-${l}px`),this.canvasWrapper.style.minHeight=`${l}px`,this.canvasWrapper.appendChild(a);const o=a.cloneNode();this.progressWrapper.appendChild(o),this.renderMultiCanvas(t,r,i,l,a,o)}render(t){return y(this,void 0,void 0,function*(){var e;this.timeouts.forEach(l=>l()),this.timeouts=[],this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="",this.options.width!=null&&(this.scrollContainer.style.width=typeof this.options.width=="number"?`${this.options.width}px`:this.options.width);const i=this.getPixelRatio(),s=this.scrollContainer.clientWidth,n=Math.ceil(t.duration*(this.options.minPxPerSec||0));this.isScrollable=n>s;const r=this.options.fillParent&&!this.isScrollable,a=(r?s:n)*i;if(this.wrapper.style.width=r?"100%":`${n}px`,this.scrollContainer.style.overflowX=this.isScrollable?"auto":"hidden",this.scrollContainer.classList.toggle("noScrollbar",!!this.options.hideScrollbar),this.cursor.style.backgroundColor=`${this.options.cursorColor||this.options.progressColor}`,this.cursor.style.width=`${this.options.cursorWidth}px`,this.audioData=t,this.emit("render"),this.options.splitChannels)for(let l=0;l<t.numberOfChannels;l++){const o=Object.assign(Object.assign({},this.options),(e=this.options.splitChannels)===null||e===void 0?void 0:e[l]);this.renderChannel([t.getChannelData(l)],o,a,l)}else{const l=[t.getChannelData(0)];t.numberOfChannels>1&&l.push(t.getChannelData(1)),this.renderChannel(l,this.options,a,0)}Promise.resolve().then(()=>this.emit("rendered"))})}reRender(){if(this.unsubscribeOnScroll.forEach(i=>i()),this.unsubscribeOnScroll=[],!this.audioData)return;const{scrollWidth:t}=this.scrollContainer,{right:e}=this.progressWrapper.getBoundingClientRect();if(this.render(this.audioData),this.isScrollable&&t!==this.scrollContainer.scrollWidth){const{right:i}=this.progressWrapper.getBoundingClientRect();let s=i-e;s*=2,s=s<0?Math.floor(s):Math.ceil(s),s/=2,this.scrollContainer.scrollLeft+=s}}zoom(t){this.options.minPxPerSec=t,this.reRender()}scrollIntoView(t,e=!1){const{scrollLeft:i,scrollWidth:s,clientWidth:n}=this.scrollContainer,r=t*s,a=i,l=i+n,o=n/2;if(this.isDragging)r+30>l?this.scrollContainer.scrollLeft+=30:r-30<a&&(this.scrollContainer.scrollLeft-=30);else{(r<a||r>l)&&(this.scrollContainer.scrollLeft=r-(this.options.autoCenter?o:0));const h=r-i-o;e&&this.options.autoCenter&&h>0&&(this.scrollContainer.scrollLeft+=Math.min(h,10))}{const h=this.scrollContainer.scrollLeft,u=h/s,d=(h+n)/s;this.emit("scroll",u,d,h,h+n)}}renderProgress(t,e){if(isNaN(t))return;const i=100*t;this.canvasWrapper.style.clipPath=`polygon(${i}% 0, 100% 0, 100% 100%, ${i}% 100%)`,this.progressWrapper.style.width=`${i}%`,this.cursor.style.left=`${i}%`,this.cursor.style.transform=`translateX(-${Math.round(i)===100?this.options.cursorWidth:0}px)`,this.isScrollable&&this.options.autoScroll&&this.scrollIntoView(t,e)}exportImage(t,e,i){return y(this,void 0,void 0,function*(){const s=this.canvasWrapper.querySelectorAll("canvas");if(!s.length)throw new Error("No waveform data");if(i==="dataURL"){const n=Array.from(s).map(r=>r.toDataURL(t,e));return Promise.resolve(n)}return Promise.all(Array.from(s).map(n=>new Promise((r,a)=>{n.toBlob(l=>{l?r(l):a(new Error("Could not export image"))},t,e)})))})}}T.MAX_CANVAS_WIDTH=8e3,T.MAX_NODES=10;class tt extends R{constructor(){super(...arguments),this.unsubscribe=()=>{}}start(){this.unsubscribe=this.on("tick",()=>{requestAnimationFrame(()=>{this.emit("tick")})}),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}}class O extends R{constructor(t=new AudioContext){super(),this.bufferNode=null,this.playStartTime=0,this.playedDuration=0,this._muted=!1,this._playbackRate=1,this._duration=void 0,this.buffer=null,this.currentSrc="",this.paused=!0,this.crossOrigin=null,this.seeking=!1,this.autoplay=!1,this.addEventListener=this.on,this.removeEventListener=this.un,this.audioContext=t,this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination)}load(){return y(this,void 0,void 0,function*(){})}get src(){return this.currentSrc}set src(t){if(this.currentSrc=t,this._duration=void 0,!t)return this.buffer=null,void this.emit("emptied");fetch(t).then(e=>{if(e.status>=400)throw new Error(`Failed to fetch ${t}: ${e.status} (${e.statusText})`);return e.arrayBuffer()}).then(e=>this.currentSrc!==t?null:this.audioContext.decodeAudioData(e)).then(e=>{this.currentSrc===t&&(this.buffer=e,this.emit("loadedmetadata"),this.emit("canplay"),this.autoplay&&this.play())})}_play(){var t;if(!this.paused)return;this.paused=!1,(t=this.bufferNode)===null||t===void 0||t.disconnect(),this.bufferNode=this.audioContext.createBufferSource(),this.buffer&&(this.bufferNode.buffer=this.buffer),this.bufferNode.playbackRate.value=this._playbackRate,this.bufferNode.connect(this.gainNode);let e=this.playedDuration*this._playbackRate;(e>=this.duration||e<0)&&(e=0,this.playedDuration=0),this.bufferNode.start(this.audioContext.currentTime,e),this.playStartTime=this.audioContext.currentTime,this.bufferNode.onended=()=>{this.currentTime>=this.duration&&(this.pause(),this.emit("ended"))}}_pause(){var t;this.paused=!0,(t=this.bufferNode)===null||t===void 0||t.stop(),this.playedDuration+=this.audioContext.currentTime-this.playStartTime}play(){return y(this,void 0,void 0,function*(){this.paused&&(this._play(),this.emit("play"))})}pause(){this.paused||(this._pause(),this.emit("pause"))}stopAt(t){const e=t-this.currentTime,i=this.bufferNode;i==null||i.stop(this.audioContext.currentTime+e),i==null||i.addEventListener("ended",()=>{i===this.bufferNode&&(this.bufferNode=null,this.pause())},{once:!0})}setSinkId(t){return y(this,void 0,void 0,function*(){return this.audioContext.setSinkId(t)})}get playbackRate(){return this._playbackRate}set playbackRate(t){this._playbackRate=t,this.bufferNode&&(this.bufferNode.playbackRate.value=t)}get currentTime(){return(this.paused?this.playedDuration:this.playedDuration+(this.audioContext.currentTime-this.playStartTime))*this._playbackRate}set currentTime(t){const e=!this.paused;e&&this._pause(),this.playedDuration=t/this._playbackRate,e&&this._play(),this.emit("seeking"),this.emit("timeupdate")}get duration(){var t,e;return(t=this._duration)!==null&&t!==void 0?t:((e=this.buffer)===null||e===void 0?void 0:e.duration)||0}set duration(t){this._duration=t}get volume(){return this.gainNode.gain.value}set volume(t){this.gainNode.gain.value=t,this.emit("volumechange")}get muted(){return this._muted}set muted(t){this._muted!==t&&(this._muted=t,this._muted?this.gainNode.disconnect():this.gainNode.connect(this.audioContext.destination))}canPlayType(t){return/^(audio|video)\//.test(t)}getGainNode(){return this.gainNode}getChannelData(){const t=[];if(!this.buffer)return t;const e=this.buffer.numberOfChannels;for(let i=0;i<e;i++)t.push(this.buffer.getChannelData(i));return t}}const et={waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,dragToSeek:!1,autoScroll:!0,autoCenter:!0,sampleRate:8e3};class D extends Z{static create(t){return new D(t)}constructor(t){const e=t.media||(t.backend==="WebAudio"?new O:void 0);super({media:e,mediaControls:t.mediaControls,autoplay:t.autoplay,playbackRate:t.audioRate}),this.plugins=[],this.decodedData=null,this.stopAtPosition=null,this.subscriptions=[],this.mediaSubscriptions=[],this.abortController=null,this.options=Object.assign({},et,t),this.timer=new tt;const i=e?void 0:this.getMediaElement();this.renderer=new T(this.options,i),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initPlugins();const s=this.options.url||this.getSrc()||"";Promise.resolve().then(()=>{this.emit("init");const{peaks:n,duration:r}=this.options;(s||n&&r)&&this.load(s,n,r).catch(()=>null)})}updateProgress(t=this.getCurrentTime()){return this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),t}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",()=>{if(!this.isSeeking()){const t=this.updateProgress();this.emit("timeupdate",t),this.emit("audioprocess",t),this.stopAtPosition!=null&&this.isPlaying()&&t>=this.stopAtPosition&&this.pause()}}))}initPlayerEvents(){this.isPlaying()&&(this.emit("play"),this.timer.start()),this.mediaSubscriptions.push(this.onMediaEvent("timeupdate",()=>{const t=this.updateProgress();this.emit("timeupdate",t)}),this.onMediaEvent("play",()=>{this.emit("play"),this.timer.start()}),this.onMediaEvent("pause",()=>{this.emit("pause"),this.timer.stop(),this.stopAtPosition=null}),this.onMediaEvent("emptied",()=>{this.timer.stop(),this.stopAtPosition=null}),this.onMediaEvent("ended",()=>{this.emit("timeupdate",this.getDuration()),this.emit("finish"),this.stopAtPosition=null}),this.onMediaEvent("seeking",()=>{this.emit("seeking",this.getCurrentTime())}),this.onMediaEvent("error",()=>{var t;this.emit("error",(t=this.getMediaElement().error)!==null&&t!==void 0?t:new Error("Media error")),this.stopAtPosition=null}))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(t,e)=>{this.options.interact&&(this.seekTo(t),this.emit("interaction",t*this.getDuration()),this.emit("click",t,e))}),this.renderer.on("dblclick",(t,e)=>{this.emit("dblclick",t,e)}),this.renderer.on("scroll",(t,e,i,s)=>{const n=this.getDuration();this.emit("scroll",t*n,e*n,i,s)}),this.renderer.on("render",()=>{this.emit("redraw")}),this.renderer.on("rendered",()=>{this.emit("redrawcomplete")}),this.renderer.on("dragstart",t=>{this.emit("dragstart",t)}),this.renderer.on("dragend",t=>{this.emit("dragend",t)}));{let t;this.subscriptions.push(this.renderer.on("drag",e=>{if(!this.options.interact)return;let i;this.renderer.renderProgress(e),clearTimeout(t),this.isPlaying()?i=0:this.options.dragToSeek===!0?i=200:typeof this.options.dragToSeek=="object"&&this.options.dragToSeek!==void 0&&(i=this.options.dragToSeek.debounceTime),t=setTimeout(()=>{this.seekTo(e)},i),this.emit("interaction",e*this.getDuration()),this.emit("drag",e)}))}}initPlugins(){var t;!((t=this.options.plugins)===null||t===void 0)&&t.length&&this.options.plugins.forEach(e=>{this.registerPlugin(e)})}unsubscribePlayerEvents(){this.mediaSubscriptions.forEach(t=>t()),this.mediaSubscriptions=[]}setOptions(t){this.options=Object.assign({},this.options,t),t.duration&&!t.peaks&&(this.decodedData=L.createBuffer(this.exportPeaks(),t.duration)),t.peaks&&t.duration&&(this.decodedData=L.createBuffer(t.peaks,t.duration)),this.renderer.setOptions(this.options),t.audioRate&&this.setPlaybackRate(t.audioRate),t.mediaControls!=null&&(this.getMediaElement().controls=t.mediaControls)}registerPlugin(t){return t._init(this),this.plugins.push(t),this.subscriptions.push(t.once("destroy",()=>{this.plugins=this.plugins.filter(e=>e!==t)})),t}getWrapper(){return this.renderer.getWrapper()}getWidth(){return this.renderer.getWidth()}getScroll(){return this.renderer.getScroll()}setScroll(t){return this.renderer.setScroll(t)}setScrollTime(t){const e=t/this.getDuration();this.renderer.setScrollPercentage(e)}getActivePlugins(){return this.plugins}loadAudio(t,e,i,s){return y(this,void 0,void 0,function*(){var n;if(this.emit("load",t),!this.options.media&&this.isPlaying()&&this.pause(),this.decodedData=null,this.stopAtPosition=null,!e&&!i){const a=this.options.fetchParams||{};window.AbortController&&!a.signal&&(this.abortController=new AbortController,a.signal=(n=this.abortController)===null||n===void 0?void 0:n.signal);const l=h=>this.emit("loading",h);e=yield Q.fetchBlob(t,l,a);const o=this.options.blobMimeType;o&&(e=new Blob([e],{type:o}))}this.setSrc(t,e);const r=yield new Promise(a=>{const l=s||this.getDuration();l?a(l):this.mediaSubscriptions.push(this.onMediaEvent("loadedmetadata",()=>a(this.getDuration()),{once:!0}))});if(!t&&!e){const a=this.getMediaElement();a instanceof O&&(a.duration=r)}if(i)this.decodedData=L.createBuffer(i,r||0);else if(e){const a=yield e.arrayBuffer();this.decodedData=yield L.decode(a,this.options.sampleRate)}this.decodedData&&(this.emit("decode",this.getDuration()),this.renderer.render(this.decodedData)),this.emit("ready",this.getDuration())})}load(t,e,i){return y(this,void 0,void 0,function*(){try{return yield this.loadAudio(t,void 0,e,i)}catch(s){throw this.emit("error",s),s}})}loadBlob(t,e,i){return y(this,void 0,void 0,function*(){try{return yield this.loadAudio("",t,e,i)}catch(s){throw this.emit("error",s),s}})}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(t),this.emit("zoom",t)}getDecodedData(){return this.decodedData}exportPeaks({channels:t=2,maxLength:e=8e3,precision:i=1e4}={}){if(!this.decodedData)throw new Error("The audio has not been decoded yet");const s=Math.min(t,this.decodedData.numberOfChannels),n=[];for(let r=0;r<s;r++){const a=this.decodedData.getChannelData(r),l=[],o=a.length/e;for(let h=0;h<e;h++){const u=a.slice(Math.floor(h*o),Math.ceil((h+1)*o));let d=0;for(let p=0;p<u.length;p++){const m=u[p];Math.abs(m)>Math.abs(d)&&(d=m)}l.push(Math.round(d*i)/i)}n.push(l)}return n}getDuration(){let t=super.getDuration()||0;return t!==0&&t!==1/0||!this.decodedData||(t=this.decodedData.duration),t}toggleInteraction(t){this.options.interact=t}setTime(t){this.stopAtPosition=null,super.setTime(t),this.updateProgress(t),this.emit("timeupdate",t)}seekTo(t){const e=this.getDuration()*t;this.setTime(e)}play(t,e){const i=Object.create(null,{play:{get:()=>super.play}});return y(this,void 0,void 0,function*(){t!=null&&this.setTime(t);const s=yield i.play.call(this);return e!=null&&(this.media instanceof O?this.media.stopAt(e):this.stopAtPosition=e),s})}playPause(){return y(this,void 0,void 0,function*(){return this.isPlaying()?this.pause():this.play()})}stop(){this.pause(),this.setTime(0)}skip(t){this.setTime(this.getCurrentTime()+t)}empty(){this.load("",[[0]],.001)}setMediaElement(t){this.unsubscribePlayerEvents(),super.setMediaElement(t),this.initPlayerEvents()}exportImage(){return y(this,arguments,void 0,function*(t="image/png",e=1,i="dataURL"){return this.renderer.exportImage(t,e,i)})}destroy(){var t;this.emit("destroy"),(t=this.abortController)===null||t===void 0||t.abort(),this.plugins.forEach(e=>e.destroy()),this.subscriptions.forEach(e=>e()),this.unsubscribePlayerEvents(),this.timer.destroy(),this.renderer.destroy(),super.destroy()}}D.BasePlugin=class extends R{constructor(c){super(),this.subscriptions=[],this.options=c}onInit(){}_init(c){this.wavesurfer=c,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach(c=>c())}},D.dom=K;class it{constructor(){this.listeners={}}on(t,e,i){if(this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),i==null?void 0:i.once){const s=()=>{this.un(t,s),this.un(t,e)};return this.on(t,s),s}return()=>this.un(t,e)}un(t,e){var i;(i=this.listeners[t])===null||i===void 0||i.delete(e)}once(t,e){return this.on(t,e,{once:!0})}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach(i=>i(...e))}}class st extends it{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}_init(t){this.wavesurfer=t,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach(t=>t())}}function X(c,t){const e=t.xmlns?document.createElementNS(t.xmlns,c):document.createElement(c);for(const[i,s]of Object.entries(t))if(i==="children")for(const[n,r]of Object.entries(t))typeof r=="string"?e.appendChild(document.createTextNode(r)):e.appendChild(X(n,r));else i==="style"?Object.assign(e.style,s):i==="textContent"?e.textContent=s:e.setAttribute(i,s.toString());return e}function I(c,t,e){const i=X(c,t||{});return e==null||e.appendChild(i),i}const nt={lineWidth:1,labelSize:11,formatTimeCallback:c=>`${Math.floor(c/60)}:${`0${Math.floor(c)%60}`.slice(-2)}`};class _ extends st{constructor(t){super(t||{}),this.unsubscribe=()=>{},this.onPointerMove=e=>{if(!this.wavesurfer)return;const i=this.wavesurfer.getWrapper().getBoundingClientRect(),{width:s}=i,n=e.clientX-i.left,r=Math.min(1,Math.max(0,n/s)),a=Math.min(s-this.options.lineWidth-1,n);this.wrapper.style.transform=`translateX(${a}px)`,this.wrapper.style.opacity="1";const l=this.wavesurfer.getDuration()||0;this.label.textContent=this.options.formatTimeCallback(l*r);const o=this.label.offsetWidth;this.label.style.transform=a+o>s?`translateX(-${o+this.options.lineWidth}px)`:"",this.emit("hover",r)},this.onPointerLeave=()=>{this.wrapper.style.opacity="0"},this.options=Object.assign({},nt,t),this.wrapper=I("div",{part:"hover"}),this.label=I("span",{part:"hover-label"},this.wrapper)}static create(t){return new _(t)}addUnits(t){return`${t}${typeof t=="number"?"px":""}`}onInit(){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");const t=this.wavesurfer.options,e=this.options.lineColor||t.cursorColor||t.progressColor;Object.assign(this.wrapper.style,{position:"absolute",zIndex:10,left:0,top:0,height:"100%",pointerEvents:"none",borderLeft:`${this.addUnits(this.options.lineWidth)} solid ${e}`,opacity:"0",transition:"opacity .1s ease-in"}),Object.assign(this.label.style,{display:"block",backgroundColor:this.options.labelBackground,color:this.options.labelColor,fontSize:`${this.addUnits(this.options.labelSize)}`,transition:"transform .1s ease-in",padding:"2px 3px"});const i=this.wavesurfer.getWrapper();i.appendChild(this.wrapper),i.addEventListener("pointermove",this.onPointerMove),i.addEventListener("pointerleave",this.onPointerLeave),i.addEventListener("wheel",this.onPointerMove),this.unsubscribe=()=>{i.removeEventListener("pointermove",this.onPointerMove),i.removeEventListener("pointerleave",this.onPointerLeave),i.removeEventListener("wheel",this.onPointerLeave)}}destroy(){super.destroy(),this.unsubscribe(),this.wrapper.remove()}}const rt={class:"on-panda-audio-plugin"},ot=["src"],at={key:0,class:"fallback-message"},lt={__name:"AudioPlugin",props:{content:{type:Object,default:()=>({})}},setup(c){const t=c,e=W(null),i=W(null),s=W(!1);let n=null;const r=F(()=>V(t.content).base64_url),a=()=>{if(!(!e.value||!i.value||!r.value))try{n=D.create({container:e.value,waveColor:"rgba(255, 165, 0, 1)",progressColor:"rgba(192, 192, 192, 1)",media:i.value,normalize:!0,height:60,plugins:[_.create({lineColor:"#ff0000",lineWidth:2,labelBackground:"#555",labelColor:"#fff",labelSize:"11px"})]}),n.on("ready",()=>{s.value=!0,e.value.addEventListener("click",l=>{const o=e.value.getBoundingClientRect(),u=(l.clientX-o.left)/o.width;n.seekTo(u),i.value.play()})}),n.on("error",l=>{console.error("WaveSurfer error:",l),s.value=!1})}catch(l){console.error("Failed to initialize WaveSurfer:",l),s.value=!1}};return q(r,()=>{n&&(n.destroy(),n=null,s.value=!1),r.value&&setTimeout(a,100)},{immediate:!1}),G(()=>{r.value&&a()}),Y(()=>{n&&n.destroy()}),(l,o)=>($(),B("div",rt,[j("div",{ref_key:"waveformContainer",ref:e,class:"waveform-container"},null,512),j("audio",{ref_key:"audioElement",ref:i,src:r.value,controls:"",class:"audio-controls"},null,8,ot),!s.value&&r.value?($(),B("div",at," Waveform visualization unavailable - using audio controls only ")):J("",!0)]))}},dt=U(lt,[["__scopeId","data-v-0e4cb895"]]);export{dt as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.on-panda-audio-plugin[data-v-0e4cb895]{width:100%;margin-bottom:10px;margin-top:10px;background-color:#f9f9f9;border-radius:8px;box-shadow:0 2px 4px #0000001a}.waveform-container[data-v-0e4cb895]{width:100%;cursor:pointer}.audio-controls[data-v-0e4cb895]{width:100%}.fallback-message[data-v-0e4cb895]{font-size:.9em;color:#666;font-style:italic;margin-top:.5rem}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.on-panda-image-plugin[data-v-3a06bfde]{max-width:min(100% - 5px,512px);max-height:512px;box-shadow:#00000080 0 0 8px;margin-left:5px;margin-right:5px;cursor:zoom-in}.on-panda-image-plugin.rawSizeImg[data-v-3a06bfde]{max-width:initial;max-height:initial;position:relative;z-index:1}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as l,c as s,o as i,a as r}from"./index-VDofnkb1.js";const u=["src"],_={__name:"ImagePlugin",props:{content:{type:Object,default:()=>({})}},setup(a){const e=a,n=s(()=>e.content.blob_url||e.content.image_url.url);function c(t){t.target.classList.toggle("rawSizeImg")}function o(){window.open(n.value,"_blank")}return(t,p)=>(i(),r("img",{class:"on-panda-image-plugin",src:n.value,alt:"ON_PANDA_IMAGE",onClick:c,onDblclick:o},null,40,u))}},m=l(_,[["__scopeId","data-v-3a06bfde"]]);export{m as default};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|