From 2d8303808d0f5cc9724502cedccf209b2498665c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=AA=E5=AD=90?= Date: Mon, 5 Jan 2026 19:51:09 +0800 Subject: [PATCH] first commit --- .gitignore | 5 + README.MD | 122 +++ functions/_middleware.ts | 10 + package-lock.json | 1604 ++++++++++++++++++++++++++++++++++++++ package.json | 17 + public/_headers | 6 + public/demo.css | 86 ++ public/index.html | 47 ++ public/summary.css | 178 +++++ public/summary.js | 208 +++++ src/api.ts | 197 +++++ src/styles.ts | 42 + src/worker.ts | 32 + tsconfig.json | 14 + wrangler.toml | 28 + 15 files changed, 2596 insertions(+) create mode 100644 .gitignore create mode 100644 README.MD create mode 100644 functions/_middleware.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/_headers create mode 100644 public/demo.css create mode 100644 public/index.html create mode 100644 public/summary.css create mode 100644 public/summary.js create mode 100644 src/api.ts create mode 100644 src/styles.ts create mode 100644 src/worker.ts create mode 100644 tsconfig.json create mode 100644 wrangler.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f1b34b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +dist/ +.wrangler/ +.DS_Store + diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..1bc2f1c --- /dev/null +++ b/README.MD @@ -0,0 +1,122 @@ +用 Cloudflare Workers(也可用于 Pages Functions)实现: + +- KV 作为数据库:以文章相对 URL 存摘要内容 +- Workers AI 负责生成摘要 +- 纯静态页面(HTML + JS):抽取指定元素(例如 `.post`)的正文,调用 API 生成/读取摘要并展示 +- 内置 4 种摘要风格:`tldr` / `bullets` / `outline` / `keywords` + +## 目录结构 + +- `src/worker.ts`:Workers API(KV 缓存 + Workers AI 生成) +- `public/index.html`:演示页面(静态) +- `public/summary.js`:前端抽取正文 + 请求摘要 + 渲染 +- `public/summary.css`:几种风格的 UI 设计 + +## 本地开发(Pages) + +1) 安装依赖 + +```bash +npm i +``` + +2) 本地启动(带本地 KV/AI 绑定) + +```bash +npm run dev +``` + +打开 Wrangler 输出的本地地址,访问 `/` 即可看到 demo。 + +> 说明:`npm run dev` 默认使用 `wrangler pages dev public --kv KV --ai AI ...`,KV 会持久化到 `.wrangler/state`。 + +## 部署(Pages) + +```bash +npm run deploy +``` + +在 Cloudflare Pages 项目设置里添加绑定: + +- KV Namespace:变量名 `KV` +- AI:变量名 `AI` +- 环境变量:`MODEL`(可选,默认 `@cf/meta/llama-3.1-8b-instruct`) + +> 注意:Pages Functions 也是跑在 Workers Runtime 上,调用 `/api/*` 仍会产生函数调用次数;本项目已用 KV 做缓存,只有首次/内容变化才会触发 AI 生成。 + +部署后: + +- 静态页面:`/` +- API: + - `GET /api/styles`:返回可用风格 + - `GET /api/summary?url=/post/xxx&style=tldr`:读取 KV 缓存(不存在返回 404) + - `POST /api/summary`:生成并写入 KV + +`POST /api/summary` 请求体示例: + +```json +{ + "url": "/post/hello", + "style": "bullets", + "text": "这里是文章正文纯文本…" +} +``` + +## 接入你的静态文章页 + +你的文章页只需要: + +1) 正文容器(可换选择器): + +```html +
文章内容...
+``` + +2) 放一个摘要组件容器: + +```html +
+``` + +`data-autoload="false"` 表示不自动请求(避免每次打开页面就触发 `/api/summary`);用户点击风格按钮时才生成/读取。 + +默认会隐藏下面的摘要内容框(避免占位太大),点击任意风格按钮后才会展开并展示结果。你也可以手动控制初始展开: + +```html +
+``` + +如果你的站点是深色主题,可以加 `data-theme="dark"`(或强制浅色 `data-theme="light"`): + +```html +
+``` + +3) 引入静态资源: + +```html + + +``` + +`summary.css` 只会影响 `.post-summary` 组件内部,不会污染你站点的全局样式;demo 页面用到的全局样式在 `public/demo.css`,集成时不要引用它。 + +跨域引入说明: + +- 如果你的文章站点(如 `https://blog.example.com`)要直接引用另一个域名上的 `summary.js`(并且 `type="module"`),脚本资源必须带 CORS 响应头。 +- 本项目已在 Worker(`src/worker.ts`)和 Pages(`public/_headers`)里为静态资源和 `/api/*` 增加了 `Access-Control-Allow-Origin: *`。 +- 默认情况下,组件会把 API 指向 `summary.js` 所在域名(避免跨域脚本被引入时,错误请求到当前文章站点的 `/api/*`)。 +- 如果前端和 API 不同域名,可在 `.post-summary` 上设置 `data-api-base="https://你的API域名"` 覆盖。 + +排查 KV 没写入: + +- 打开浏览器 DevTools → Network,确认有 `POST https://你的API域名/api/summary`,并且返回里有 `cached: false` +- 访问 `https://你的API域名/api/summary?url=/debug&style=tldr`:未缓存时应返回 404(缓存命中才会 200) + +## 仍想用 Workers(可选) + +如果你仍想用纯 Workers(不走 Pages): + +- `npm run dev:worker` +- `npm run deploy:worker` +- KV id 配置参考 `wrangler.toml` diff --git a/functions/_middleware.ts b/functions/_middleware.ts new file mode 100644 index 0000000..9ada9e9 --- /dev/null +++ b/functions/_middleware.ts @@ -0,0 +1,10 @@ +import { handleApi, type ApiEnv } from "../src/api"; + +export const onRequest: PagesFunction = async (context) => { + const url = new URL(context.request.url); + if (url.pathname.startsWith("/api/")) { + return handleApi(context.request, context.env); + } + return context.next(); +}; + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7c25a72 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1604 @@ +{ + "name": "aizhaiyao", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "aizhaiyao", + "devDependencies": { + "@cloudflare/workers-types": "^4.20260103.0", + "typescript": "^5.6.3", + "wrangler": "^3.99.0" + } + }, + "node_modules/@cloudflare/kv-asset-handler": { + "version": "0.3.4", + "resolved": "https://registry.npmmirror.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz", + "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==", + "dev": true, + "license": "MIT OR Apache-2.0", + "dependencies": { + "mime": "^3.0.0" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/@cloudflare/unenv-preset": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/@cloudflare/unenv-preset/-/unenv-preset-2.0.2.tgz", + "integrity": "sha512-nyzYnlZjjV5xT3LizahG1Iu6mnrCaxglJ04rZLpDwlDVDZ7v46lNsfxhV3A/xtfgQuSHmLnc6SVI+KwBpc3Lwg==", + "dev": true, + "license": "MIT OR Apache-2.0", + "peerDependencies": { + "unenv": "2.0.0-rc.14", + "workerd": "^1.20250124.0" + }, + "peerDependenciesMeta": { + "workerd": { + "optional": true + } + } + }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250718.0.tgz", + "integrity": "sha512-FHf4t7zbVN8yyXgQ/r/GqLPaYZSGUVzeR7RnL28Mwj2djyw2ZergvytVc7fdGcczl6PQh+VKGfZCfUqpJlbi9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250718.0.tgz", + "integrity": "sha512-fUiyUJYyqqp4NqJ0YgGtp4WJh/II/YZsUnEb6vVy5Oeas8lUOxnN+ZOJ8N/6/5LQCVAtYCChRiIrBbfhTn5Z8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250718.0.tgz", + "integrity": "sha512-5+eb3rtJMiEwp08Kryqzzu8d1rUcK+gdE442auo5eniMpT170Dz0QxBrqkg2Z48SFUPYbj+6uknuA5tzdRSUSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250718.0.tgz", + "integrity": "sha512-Aa2M/DVBEBQDdATMbn217zCSFKE+ud/teS+fFS+OQqKABLn0azO2qq6ANAHYOIE6Q3Sq4CxDIQr8lGdaJHwUog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20250718.0", + "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250718.0.tgz", + "integrity": "sha512-dY16RXKffmugnc67LTbyjdDHZn5NoTF1yHEf2fN4+OaOnoGSp3N1x77QubTDwqZ9zECWxgQfDLjddcH8dWeFhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20260103.0", + "resolved": "https://registry.npmmirror.com/@cloudflare/workers-types/-/workers-types-4.20260103.0.tgz", + "integrity": "sha512-jANmoGpJcXARnwlkvrQOeWyjYD1quTfHcs+++Z544XRHOSfLc4XSlts7snIhbiIGgA5bo66zDhraF+9lKUr2hw==", + "dev": true, + "license": "MIT OR Apache-2.0" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild-plugins/node-globals-polyfill": { + "version": "0.2.3", + "resolved": "https://registry.npmmirror.com/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", + "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild-plugins/node-modules-polyfill": { + "version": "0.2.2", + "resolved": "https://registry.npmmirror.com/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", + "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "dev": true, + "license": "ISC", + "dependencies": { + "escape-string-regexp": "^4.0.0", + "rollup-plugin-node-polyfills": "^0.2.1" + }, + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmmirror.com/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "printable-characters": "^1.0.42" + } + }, + "node_modules/blake3-wasm": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz", + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "dev": true, + "license": "MIT" + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmmirror.com/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmmirror.com/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/miniflare": { + "version": "3.20250718.3", + "resolved": "https://registry.npmmirror.com/miniflare/-/miniflare-3.20250718.3.tgz", + "integrity": "sha512-JuPrDJhwLrNLEJiNLWO7ZzJrv/Vv9kZuwMYCfv0LskQDM6Eonw4OvywO3CH/wCGjgHzha/qyjUh8JQ068TjDgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "0.8.1", + "acorn": "8.14.0", + "acorn-walk": "8.3.2", + "exit-hook": "2.2.1", + "glob-to-regexp": "0.4.1", + "stoppable": "1.1.0", + "undici": "^5.28.5", + "workerd": "1.20250718.0", + "ws": "8.18.0", + "youch": "3.3.4", + "zod": "3.22.3" + }, + "bin": { + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmmirror.com/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmmirror.com/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/rollup-plugin-inject": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", + "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^0.6.1", + "magic-string": "^0.25.3", + "rollup-pluginutils": "^2.8.1" + } + }, + "node_modules/rollup-plugin-node-polyfills": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", + "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rollup-plugin-inject": "^3.0.0" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmmirror.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, + "license": "MIT" + }, + "node_modules/stacktracey": { + "version": "2.1.8", + "resolved": "https://registry.npmmirror.com/stacktracey/-/stacktracey-2.1.8.tgz", + "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmmirror.com/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/unenv": { + "version": "2.0.0-rc.14", + "resolved": "https://registry.npmmirror.com/unenv/-/unenv-2.0.0-rc.14.tgz", + "integrity": "sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "exsolve": "^1.0.1", + "ohash": "^2.0.10", + "pathe": "^2.0.3", + "ufo": "^1.5.4" + } + }, + "node_modules/workerd": { + "version": "1.20250718.0", + "resolved": "https://registry.npmmirror.com/workerd/-/workerd-1.20250718.0.tgz", + "integrity": "sha512-kqkIJP/eOfDlUyBzU7joBg+tl8aB25gEAGqDap+nFWb+WHhnooxjGHgxPBy3ipw2hnShPFNOQt5lFRxbwALirg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20250718.0", + "@cloudflare/workerd-darwin-arm64": "1.20250718.0", + "@cloudflare/workerd-linux-64": "1.20250718.0", + "@cloudflare/workerd-linux-arm64": "1.20250718.0", + "@cloudflare/workerd-windows-64": "1.20250718.0" + } + }, + "node_modules/wrangler": { + "version": "3.114.16", + "resolved": "https://registry.npmmirror.com/wrangler/-/wrangler-3.114.16.tgz", + "integrity": "sha512-ve/ULRjrquu5BHNJ+1T0ipJJlJ6pD7qLmhwRkk0BsUIxatNe4HP4odX/R4Mq/RHG6LOnVAFs7SMeSHlz/1mNlQ==", + "dev": true, + "license": "MIT OR Apache-2.0", + "dependencies": { + "@cloudflare/kv-asset-handler": "0.3.4", + "@cloudflare/unenv-preset": "2.0.2", + "@esbuild-plugins/node-globals-polyfill": "0.2.3", + "@esbuild-plugins/node-modules-polyfill": "0.2.2", + "blake3-wasm": "2.1.5", + "esbuild": "0.17.19", + "miniflare": "3.20250718.3", + "path-to-regexp": "6.3.0", + "unenv": "2.0.0-rc.14", + "workerd": "1.20250718.0" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=16.17.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2", + "sharp": "^0.33.5" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20250408.0" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmmirror.com/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/youch": { + "version": "3.3.4", + "resolved": "https://registry.npmmirror.com/youch/-/youch-3.3.4.tgz", + "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cookie": "^0.7.1", + "mustache": "^4.2.0", + "stacktracey": "^2.1.8" + } + }, + "node_modules/zod": { + "version": "3.22.3", + "resolved": "https://registry.npmmirror.com/zod/-/zod-3.22.3.tgz", + "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..8736081 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "aizhaiyao", + "private": true, + "type": "module", + "scripts": { + "dev": "wrangler pages dev public --compatibility-date=2026-01-05 --kv KV --ai AI -b MODEL=@cf/meta/llama-3.1-8b-instruct", + "deploy": "wrangler pages deploy public --project-name aizhaiyao", + "dev:worker": "wrangler dev", + "deploy:worker": "wrangler deploy", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20260103.0", + "typescript": "^5.6.3", + "wrangler": "^3.99.0" + } +} diff --git a/public/_headers b/public/_headers new file mode 100644 index 0000000..f0e2a77 --- /dev/null +++ b/public/_headers @@ -0,0 +1,6 @@ +/* + Access-Control-Allow-Origin: * + Access-Control-Allow-Methods: GET, POST, OPTIONS + Access-Control-Allow-Headers: Content-Type + Cross-Origin-Resource-Policy: cross-origin + diff --git a/public/demo.css b/public/demo.css new file mode 100644 index 0000000..d10a5a5 --- /dev/null +++ b/public/demo.css @@ -0,0 +1,86 @@ +:root { + --bg: #0b0f1a; + --card: rgba(255, 255, 255, 0.06); + --text: rgba(255, 255, 255, 0.92); + --muted: rgba(255, 255, 255, 0.65); + --border: rgba(255, 255, 255, 0.12); + --shadow: 0 10px 30px rgba(0, 0, 0, 0.35); + --radius: 16px; + --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + --sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", + Arial, "Noto Sans", "Liberation Sans", sans-serif; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: var(--sans); + background: radial-gradient( + 1200px 700px at 10% 10%, + rgba(124, 92, 255, 0.25), + transparent 60% + ), + radial-gradient( + 1200px 700px at 90% 20%, + rgba(34, 197, 94, 0.18), + transparent 60% + ), + var(--bg); + color: var(--text); + line-height: 1.55; +} + +code { + font-family: var(--mono); + font-size: 0.95em; + padding: 0 0.35em; + border: 1px solid var(--border); + border-radius: 8px; + background: rgba(255, 255, 255, 0.06); +} + +.page { + max-width: 1100px; + margin: 0 auto; + padding: 32px 16px 60px; +} + +.header h1 { + margin: 0 0 8px; + letter-spacing: 0.2px; +} + +.demo-muted { + color: var(--muted); +} + +.layout { + display: grid; + grid-template-columns: 1.2fr 0.8fr; + gap: 16px; + align-items: start; +} + +@media (max-width: 900px) { + .layout { + grid-template-columns: 1fr; + } +} + +.card { + background: var(--card); + border: 1px solid var(--border); + border-radius: var(--radius); + box-shadow: var(--shadow); + padding: 18px 18px; + backdrop-filter: blur(10px); +} + +.post h2 { + margin: 4px 0 10px; +} + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..dfd554f --- /dev/null +++ b/public/index.html @@ -0,0 +1,47 @@ + + + + + + AI 摘要 Demo + + + + +
+
+

AI 摘要 Demo

+

+ 选择风格后,脚本会读取 .post 内容并调用 /api/summary 获取/生成摘要(KV缓存)。 +

+
+ +
+
+

示例文章

+

+ 这是一段示例内容:你可以把它替换成你的文章正文。脚本会抽取纯文本并生成不同风格的摘要,比如 TL;DR、要点、结构化等。 +

+

+ 实际使用时,你的静态页面只要包含 <div class="post">...</div> 即可。 +

+
+ + +
+
+ + + + diff --git a/public/summary.css b/public/summary.css new file mode 100644 index 0000000..79f92d0 --- /dev/null +++ b/public/summary.css @@ -0,0 +1,178 @@ +.post-summary { + --ps-surface: #ffffff; + --ps-text: #111827; + --ps-muted: #6b7280; + --ps-border: rgba(17, 24, 39, 0.12); + --ps-content-bg: #f8fafc; + --ps-shadow: 0 10px 28px rgba(17, 24, 39, 0.08); + --ps-radius: 16px; + --ps-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + --ps-sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", + Arial, "Noto Sans", "Liberation Sans", sans-serif; + --ps-btn-bg: rgba(17, 24, 39, 0.04); + --ps-btn-bg-active: rgba(124, 92, 255, 0.14); + --ps-btn-border-active: rgba(124, 92, 255, 0.55); + + --ps-style-tldr: rgba(124, 92, 255, 0.9); + --ps-style-bullets: rgba(34, 197, 94, 0.9); + --ps-style-outline: rgba(245, 158, 11, 0.95); + --ps-style-keywords: rgba(59, 130, 246, 0.9); + + box-sizing: border-box; + font-family: var(--ps-sans); + color: var(--ps-text); + line-height: 1.55; + + background: var(--ps-surface); + border: 1px solid var(--ps-border); + border-radius: var(--ps-radius); + box-shadow: var(--ps-shadow); + padding: 18px 18px; + backdrop-filter: blur(10px); + + display: flex; + flex-direction: column; + gap: 12px; +} + +.post-summary[data-theme="dark"] { + --ps-surface: #0b1020; + --ps-text: rgba(255, 255, 255, 0.92); + --ps-muted: rgba(255, 255, 255, 0.65); + --ps-border: rgba(255, 255, 255, 0.14); + --ps-content-bg: rgba(0, 0, 0, 0.22); + --ps-shadow: 0 10px 30px rgba(0, 0, 0, 0.35); + --ps-btn-bg: rgba(255, 255, 255, 0.06); +} + +.post-summary[data-theme="light"] { + --ps-surface: #ffffff; + --ps-text: #111827; + --ps-muted: #6b7280; + --ps-border: rgba(17, 24, 39, 0.12); + --ps-content-bg: #f8fafc; + --ps-shadow: 0 10px 28px rgba(17, 24, 39, 0.08); + --ps-btn-bg: rgba(17, 24, 39, 0.04); +} + +@media (prefers-color-scheme: dark) { + .post-summary:not([data-theme="light"]) { + --ps-surface: #0b1020; + --ps-text: rgba(255, 255, 255, 0.92); + --ps-muted: rgba(255, 255, 255, 0.65); + --ps-border: rgba(255, 255, 255, 0.14); + --ps-content-bg: rgba(0, 0, 0, 0.22); + --ps-shadow: 0 10px 30px rgba(0, 0, 0, 0.35); + --ps-btn-bg: rgba(255, 255, 255, 0.06); + } +} + +.post-summary :where(*, *::before, *::after) { + box-sizing: border-box; +} + +.post-summary :where(code) { + font-family: var(--ps-mono); + font-size: 0.95em; + padding: 0 0.35em; + border: 1px solid var(--ps-border); + border-radius: 8px; + background: rgba(127, 127, 127, 0.12); +} + +.post-summary__muted { + color: var(--ps-muted); +} + +.post-summary__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.post-summary__title { + font-weight: 650; + letter-spacing: 0.2px; +} + +.post-summary__styles { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: flex-end; +} + +.post-summary__styles button { + appearance: none; + border: 1px solid var(--ps-border); + background: var(--ps-btn-bg); + color: var(--ps-text); + padding: 6px 10px; + border-radius: 999px; + cursor: pointer; + font-size: 13px; +} + +.post-summary__styles button[aria-pressed="true"] { + border-color: var(--ps-btn-border-active); + background: var(--ps-btn-bg-active); +} + +.post-summary__body { + display: grid; + gap: 10px; +} + +.post-summary__status { + font-size: 13px; +} + +.post-summary__content { + padding: 14px 14px; + border: 1px solid var(--ps-border); + border-radius: 14px; + background: var(--ps-content-bg); + min-height: 120px; + white-space: pre-wrap; +} + +.post-summary:not([data-expanded="true"]) .post-summary__content { + display: none; +} + +.post-summary__content :where(ul) { + margin: 0; + padding-left: 18px; + display: grid; + gap: 6px; +} + +.post-summary__content :where(h4) { + margin: 10px 0 6px; + font-size: 14px; + letter-spacing: 0.2px; +} + +.post-summary__content :where(p) { + margin: 0 0 8px; + color: var(--ps-text); +} + +.post-summary[data-style="tldr"] .post-summary__content { + border-left: 4px solid var(--ps-style-tldr); +} + +.post-summary[data-style="bullets"] .post-summary__content { + border-left: 4px solid var(--ps-style-bullets); +} + +.post-summary[data-style="outline"] .post-summary__content { + border-left: 4px solid var(--ps-style-outline); +} + +.post-summary[data-style="keywords"] .post-summary__content { + border-left: 4px solid var(--ps-style-keywords); + font-family: var(--ps-mono); +} diff --git a/public/summary.js b/public/summary.js new file mode 100644 index 0000000..5bd126e --- /dev/null +++ b/public/summary.js @@ -0,0 +1,208 @@ +const DEFAULT_POST_SELECTOR = ".post"; +const DEFAULT_STYLE = "tldr"; + +function $(root, selector) { + const el = root.querySelector(selector); + if (!el) throw new Error(`Missing element: ${selector}`); + return el; +} + +function compactText(text) { + return text.replace(/\s+/g, " ").trim(); +} + +function escapeHtml(s) { + return s + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">"); +} + +async function fetchJson(url, init) { + const res = await fetch(url, init); + const data = await res.json().catch(() => ({})); + return { res, data }; +} + +function renderMarkdownish(container, style, summary) { + if (style === "bullets") { + const lines = summary + .split("\n") + .map((l) => l.trim()) + .filter(Boolean); + const items = lines + .map((l) => (l.startsWith("-") ? l.replace(/^-+\s*/, "") : l)) + .filter(Boolean); + container.innerHTML = ``; + return; + } + + if (style === "outline") { + const blocks = summary.split("\n"); + const html = []; + for (const line of blocks) { + const l = line.trimEnd(); + if (!l) continue; + if (l.startsWith("###")) { + html.push(`

${escapeHtml(l.replace(/^###\s*/, ""))}

`); + } else { + html.push(`

${escapeHtml(l)}

`); + } + } + container.innerHTML = html.join(""); + return; + } + + container.textContent = summary; +} + +async function ensureSummary(root) { + const widget = root; + const title = widget.dataset.title || "摘要"; + const autoload = + widget.dataset.autoload !== "false" && widget.dataset.autoload !== "0"; + if (widget.dataset.expanded == null) widget.dataset.expanded = "false"; + const needsScaffold = + !widget.querySelector(".post-summary__status") || + !widget.querySelector(".post-summary__content") || + !widget.querySelector(".post-summary__styles"); + if (needsScaffold) { + widget.innerHTML = ` +
+
+
+
+
+
等待生成…
+
+
+ `.trim(); + const titleEl = widget.querySelector(".post-summary__title"); + if (titleEl) titleEl.textContent = title; + } else { + const titleEl = widget.querySelector(".post-summary__title"); + if (titleEl && !titleEl.textContent) titleEl.textContent = title; + } + + const postSelector = widget.dataset.postSelector || DEFAULT_POST_SELECTOR; + const inferredBase = (() => { + try { + return new URL(import.meta.url).origin; + } catch { + return ""; + } + })(); + const apiBase = (widget.dataset.apiBase || inferredBase).replace(/\/$/, ""); + const urlKey = widget.dataset.url || location.pathname + location.search; + + const statusEl = $(widget, ".post-summary__status"); + const contentEl = $(widget, ".post-summary__content"); + const stylesEl = $(widget, ".post-summary__styles"); + + const updatePressed = (style) => { + for (const btn of stylesEl.querySelectorAll("button[data-style]")) { + btn.setAttribute( + "aria-pressed", + btn.dataset.style === style ? "true" : "false" + ); + } + }; + + const setStyle = async (style) => { + widget.dataset.expanded = "true"; + widget.dataset.style = style; + updatePressed(style); + + statusEl.textContent = "读取缓存…"; + contentEl.textContent = ""; + + const { res, data } = await fetchJson( + `${apiBase}/api/summary?url=${encodeURIComponent(urlKey)}&style=${encodeURIComponent( + style + )}` + ); + + if (res.ok && typeof data?.summary === "string" && data.summary) { + statusEl.textContent = data.cached ? "来自 KV 缓存" : "已生成"; + renderMarkdownish(contentEl, style, data.summary || ""); + return; + } + + const isCacheMiss = res.status === 404 || data?.error === "Not found"; + if (!isCacheMiss) { + statusEl.textContent = `请求失败:${res.status}`; + contentEl.textContent = data?.error || "Unknown error"; + return; + } + + const postEl = document.querySelector(postSelector); + if (!postEl) { + statusEl.textContent = `未找到文章元素:${postSelector}`; + return; + } + + const rawText = compactText(postEl.innerText || postEl.textContent || ""); + if (!rawText) { + statusEl.textContent = "文章内容为空"; + return; + } + + const MAX_CHARS = 20000; + const text = rawText.slice(0, MAX_CHARS); + + statusEl.textContent = "AI 生成中…"; + const created = await fetchJson(`${apiBase}/api/summary`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ url: urlKey, style, text }), + }); + + if (!created.res.ok) { + statusEl.textContent = `生成失败:${created.res.status}`; + contentEl.textContent = created.data?.error || "Unknown error"; + return; + } + + statusEl.textContent = created.data.cached ? "来自 KV 缓存" : "已生成"; + renderMarkdownish(contentEl, style, created.data.summary || ""); + }; + + stylesEl.innerHTML = ""; + const styleList = [ + { key: "tldr", label: "TL;DR" }, + { key: "bullets", label: "要点" }, + { key: "outline", label: "结构化" }, + { key: "keywords", label: "关键词" }, + ]; + + for (const { key, label } of styleList) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.dataset.style = key; + btn.textContent = label; + btn.addEventListener("click", () => setStyle(key)); + stylesEl.appendChild(btn); + } + + const initialStyle = widget.dataset.style || DEFAULT_STYLE; + widget.dataset.style = initialStyle; + updatePressed(initialStyle); + + if (autoload) { + widget.dataset.expanded = "true"; + await setStyle(initialStyle); + } else { + widget.dataset.expanded = "false"; + statusEl.textContent = "点击上方风格生成摘要…"; + contentEl.textContent = ""; + } +} + +for (const widget of document.querySelectorAll(".post-summary")) { + ensureSummary(widget).catch((err) => { + const statusEl = widget.querySelector(".post-summary__status"); + if (statusEl) statusEl.textContent = `初始化失败:${err.message || err}`; + }); +} diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..33fa54d --- /dev/null +++ b/src/api.ts @@ -0,0 +1,197 @@ +import { parseStyle, STYLES, type SummaryStyle } from "./styles"; + +export type AiBinding = { run: (model: string, input: unknown) => Promise }; + +export type ApiEnv = { + KV?: KVNamespace; + AI?: AiBinding; + MODEL?: string; +}; + +export type SummaryRecord = { + url: string; + style: SummaryStyle; + summary: string; + sourceHash: string; + model: string; + createdAt: string; + updatedAt: string; +}; + +const MAX_INPUT_CHARS = 20_000; +const MAX_URL_CHARS = 500; + +function withCors(response: Response): Response { + const headers = new Headers(response.headers); + headers.set("Access-Control-Allow-Origin", "*"); + headers.set("Access-Control-Allow-Methods", "GET,POST,OPTIONS"); + headers.set("Access-Control-Allow-Headers", "Content-Type"); + headers.set("Access-Control-Max-Age", "86400"); + headers.set("Vary", "Origin"); + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers, + }); +} + +function json(data: unknown, init: ResponseInit = {}): Response { + const headers = new Headers(init.headers); + headers.set("Content-Type", "application/json; charset=utf-8"); + return withCors(new Response(JSON.stringify(data, null, 2), { ...init, headers })); +} + +function badRequest(message: string, details?: unknown): Response { + return json({ error: message, details }, { status: 400 }); +} + +function serverError(message: string, details?: unknown): Response { + return json({ error: message, details }, { status: 500 }); +} + +function normalizeRelativeUrl(input: string): string { + const trimmed = input.trim(); + if (!trimmed) return "/"; + try { + const u = new URL(trimmed); + return (u.pathname + u.search).slice(0, MAX_URL_CHARS) || "/"; + } catch { + const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`; + return withSlash.slice(0, MAX_URL_CHARS); + } +} + +function base64Url(bytes: ArrayBuffer): string { + const bin = String.fromCharCode(...new Uint8Array(bytes)); + const b64 = btoa(bin); + return b64.replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", ""); +} + +async function sha256(text: string): Promise { + const data = new TextEncoder().encode(text); + const digest = await crypto.subtle.digest("SHA-256", data); + return base64Url(digest); +} + +function kvKey(url: string, style: SummaryStyle): string { + return `summary:${style}:${encodeURIComponent(url)}`; +} + +async function readJson(request: Request): Promise { + const contentType = request.headers.get("Content-Type") || ""; + if (!contentType.toLowerCase().includes("application/json")) { + throw new Error("Content-Type must be application/json"); + } + return (await request.json()) as T; +} + +export async function handleApi(request: Request, env: ApiEnv): Promise { + const url = new URL(request.url); + + if (request.method === "OPTIONS") return withCors(new Response(null, { status: 204 })); + + if (url.pathname === "/api/styles" && request.method === "GET") { + return json({ + styles: Object.entries(STYLES).map(([key, spec]) => ({ + key, + label: spec.label, + maxCharsHint: spec.maxCharsHint, + })), + }); + } + + if (url.pathname === "/api/summary" && request.method === "GET") { + if (!env.KV) return serverError("KV binding not configured (KV)."); + const relativeUrl = normalizeRelativeUrl(url.searchParams.get("url") || "/"); + const style = parseStyle(url.searchParams.get("style")); + const record = (await env.KV.get(kvKey(relativeUrl, style), { + type: "json", + })) as SummaryRecord | null; + if (!record) return json({ error: "Not found" }, { status: 404 }); + return json({ ...record, cached: true }); + } + + if (url.pathname === "/api/summary" && request.method === "POST") { + if (!env.KV) return serverError("KV binding not configured (KV)."); + if (!env.AI?.run) return serverError("Workers AI binding not configured (AI)."); + + type Body = { + url: string; + style?: string; + text: string; + force?: boolean; + }; + + let body: Body; + try { + body = await readJson(request); + } catch (err) { + return badRequest((err as Error).message); + } + + if (!body?.url) return badRequest("Missing 'url'."); + if (!body?.text) return badRequest("Missing 'text'."); + + const relativeUrl = normalizeRelativeUrl(body.url); + const style = parseStyle(body.style ?? null); + const text = body.text.trim().slice(0, MAX_INPUT_CHARS); + const sourceHash = await sha256(text); + + const key = kvKey(relativeUrl, style); + const existing = (await env.KV.get(key, { type: "json" })) as SummaryRecord | null; + if (existing && existing.sourceHash === sourceHash && !body.force) { + return json({ ...existing, cached: true }); + } + + const model = env.MODEL || "@cf/meta/llama-3.1-8b-instruct"; + const spec = STYLES[style]; + + const messages = [ + { + role: "system" as const, + content: + "你是一个中文摘要助手。输入是网页文章正文的纯文本(可能包含少量导航/广告残留)。" + + "输出必须严格遵循用户指定的风格要求。不要编造信息;遇到缺失信息就写“文中未提及”。" + + "不要输出与摘要无关的前后缀(例如:'好的,以下是摘要')。", + }, + { + role: "user" as const, + content: + `风格:${style}(${spec.label})\n` + + `要求:${spec.instructions}\n\n` + + `文章URL:${relativeUrl}\n` + + "正文:\n" + + text, + }, + ]; + + let summaryText: string | undefined; + try { + const result = (await env.AI.run(model, { + messages, + temperature: 0.2, + })) as { response?: string }; + summaryText = result?.response?.trim(); + } catch (err) { + return serverError("AI generation failed.", { message: (err as Error).message }); + } + + if (!summaryText) return serverError("AI returned empty response."); + + const now = new Date().toISOString(); + const record: SummaryRecord = { + url: relativeUrl, + style, + summary: summaryText, + sourceHash, + model, + createdAt: existing?.createdAt ?? now, + updatedAt: now, + }; + + await env.KV.put(key, JSON.stringify(record)); + return json({ ...record, cached: false }); + } + + return json({ error: "Not found" }, { status: 404 }); +} diff --git a/src/styles.ts b/src/styles.ts new file mode 100644 index 0000000..d734993 --- /dev/null +++ b/src/styles.ts @@ -0,0 +1,42 @@ +export type SummaryStyle = "tldr" | "bullets" | "outline" | "keywords"; + +export type StyleSpec = { + label: string; + instructions: string; + maxCharsHint: number; +}; + +export const STYLES: Record = { + tldr: { + label: "TL;DR", + instructions: + "用中文输出 2-3 句话的摘要,先给结论再给理由;尽量具体,避免空话;不要输出标题或列表。", + maxCharsHint: 450, + }, + bullets: { + label: "要点", + instructions: + "用中文输出 5-8 条要点,每条 15-35 字,使用 Markdown 列表(以 '- ' 开头);不要重复句式;不要输出多余解释。", + maxCharsHint: 650, + }, + outline: { + label: "结构化", + instructions: + "用中文输出 3-6 个小节,每小节一个短标题(不超过 10 字)+ 1-2 句说明;使用 Markdown:'### 标题' 换行后写内容。", + maxCharsHint: 900, + }, + keywords: { + label: "关键词", + instructions: + "用中文输出 8-12 个关键词/短语,用顿号或逗号分隔;不加编号、不加解释、不要换行。", + maxCharsHint: 200, + }, +}; + +export function parseStyle(value: string | null): SummaryStyle { + if (!value) return "tldr"; + const normalized = value.trim().toLowerCase(); + if (normalized in STYLES) return normalized as SummaryStyle; + return "tldr"; +} + diff --git a/src/worker.ts b/src/worker.ts new file mode 100644 index 0000000..de39b05 --- /dev/null +++ b/src/worker.ts @@ -0,0 +1,32 @@ +import { handleApi, type ApiEnv } from "./api"; + +type Env = ApiEnv & { + ASSETS?: Fetcher; +}; + +function withCors(response: Response): Response { + const headers = new Headers(response.headers); + headers.set("Access-Control-Allow-Origin", "*"); + headers.set("Access-Control-Allow-Methods", "GET,POST,OPTIONS"); + headers.set("Access-Control-Allow-Headers", "Content-Type"); + headers.set("Access-Control-Max-Age", "86400"); + headers.set("Cross-Origin-Resource-Policy", "cross-origin"); + headers.set("Vary", "Origin"); + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers, + }); +} + +export default { + async fetch(request: Request, env: Env): Promise { + const url = new URL(request.url); + if (url.pathname.startsWith("/api/")) return handleApi(request, env); + if (env.ASSETS) { + const res = await env.ASSETS.fetch(request); + return withCors(res); + } + return withCors(new Response("Not found", { status: 404 })); + }, +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4bcdbdd --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "WebWorker"], + "module": "ES2022", + "moduleResolution": "Bundler", + "strict": true, + "skipLibCheck": true, + "types": ["@cloudflare/workers-types"], + "noEmit": true + }, + "include": ["src/**/*.ts"] +} + diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 0000000..9b0c852 --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,28 @@ +name = "aizhaiyao" +main = "src/worker.ts" +compatibility_date = "2026-01-05" + +[vars] +# Workers AI model id +MODEL = "@cf/meta/llama-3.1-8b-instruct" + +[ai] +binding = "AI" + +[assets] +directory = "./public" +binding = "ASSETS" + +# 1) Create KV namespace (replace ids below): +# wrangler kv namespace create KV +# wrangler kv namespace create KV --preview +# +# 2) Then uncomment and fill the ids: +# [[kv_namespaces]] +# binding = "KV" +# id = "REPLACE_WITH_ID" +# preview_id = "REPLACE_WITH_PREVIEW_ID" + +[[kv_namespaces]] +binding = "KV" +id = "5feef48eef8b43bbbb3487b7a1982fb4" \ No newline at end of file