From db5a499e5c14a0087329a501072e36c5f26031ae Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 09:08:42 -0700 Subject: [PATCH] chore: add zod-openapi stack, multipart schema, and PUBLIC_BASE_URL - bump hono to ^4.12.0, add zod ^4.0.0 and @hono/zod-openapi ^1.4.0 - migration 0002: attachment_upload_sessions + attachment_upload_parts - wrangler/env: PUBLIC_BASE_URL for public file URLs Co-Authored-By: Claude --- migrations/0002_upload_sessions.sql | 30 +++++++++++ package.json | 4 +- pnpm-lock.yaml | 84 +++++++++++++++++++++++++---- src/env.ts | 1 + wrangler.jsonc | 3 +- 5 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 migrations/0002_upload_sessions.sql diff --git a/migrations/0002_upload_sessions.sql b/migrations/0002_upload_sessions.sql new file mode 100644 index 0000000..299a67c --- /dev/null +++ b/migrations/0002_upload_sessions.sql @@ -0,0 +1,30 @@ +-- 0002_upload_sessions.sql — 分片上传会话与分片记录(纯增量,不改既有表) +CREATE TABLE attachment_upload_sessions ( + id TEXT PRIMARY KEY, + attachment_id TEXT NOT NULL, + user_id TEXT NOT NULL, + object_key TEXT NOT NULL, + upload_id TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'active', + content_type TEXT NOT NULL, + part_count INTEGER NOT NULL DEFAULT 0, + byte_size INTEGER NOT NULL DEFAULT 0, + created_at TEXT NOT NULL, + completed_at TEXT, + aborted_at TEXT +); + +CREATE INDEX idx_upload_sessions_active ON attachment_upload_sessions(user_id, attachment_id, status); + +CREATE TABLE attachment_upload_parts ( + session_id TEXT NOT NULL, + user_id TEXT NOT NULL, + attachment_id TEXT NOT NULL, + part_number INTEGER NOT NULL, + etag TEXT NOT NULL, + byte_size INTEGER NOT NULL, + created_at TEXT NOT NULL, + PRIMARY KEY (session_id, part_number) +); + +CREATE INDEX idx_upload_parts_order ON attachment_upload_parts(session_id, part_number); diff --git a/package.json b/package.json index d0794e8..53e3597 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "ready": "pnpm typecheck && pnpm test" }, "dependencies": { - "hono": "^4.8.0" + "@hono/zod-openapi": "^1.4.0", + "hono": "^4.12.0", + "zod": "^4.0.0" }, "devDependencies": { "@cloudflare/workers-types": "^4.20260601.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20e2c22..b7c8bca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,15 @@ importers: .: dependencies: + '@hono/zod-openapi': + specifier: ^1.4.0 + version: 1.4.0(hono@4.12.27)(zod@4.4.3) hono: - specifier: ^4.8.0 + specifier: ^4.12.0 version: 4.12.27 + zod: + specifier: ^4.0.0 + version: 4.4.3 devDependencies: '@cloudflare/workers-types': specifier: ^4.20260601.0 @@ -20,13 +26,18 @@ importers: version: 5.9.3 vitest: specifier: ^3.2.0 - version: 3.2.6 + version: 3.2.6(yaml@2.9.0) wrangler: specifier: ^4.20.0 version: 4.106.0(@cloudflare/workers-types@4.20260702.1) packages: + '@asteasolutions/zod-to-openapi@8.5.0': + resolution: {integrity: sha512-SABbKiObg5dLRiTFnqiW1WWwGcg1BJfmHtT2asIBnBHg6Smy/Ms2KHc650+JI4Hw7lSkdiNebEGXpwoxfben8Q==} + peerDependencies: + zod: ^4.0.0 + '@cloudflare/kv-asset-handler@0.5.0': resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} engines: {node: '>=22.0.0'} @@ -236,6 +247,19 @@ packages: cpu: [x64] os: [win32] + '@hono/zod-openapi@1.4.0': + resolution: {integrity: sha512-AFchqR1N/NxfI4hUOSGI2/g8zLROxA1OE7Oh5JJFlTaGxhrdRyH+93gd0tIBpb0z8s9r8hUoNnaOBfHbdb4NMw==} + engines: {node: '>=16.0.0'} + peerDependencies: + hono: '>=4.10.0' + zod: ^4.0.0 + + '@hono/zod-validator@0.8.0': + resolution: {integrity: sha512-5uS4S1/LKtZQYvD4BtpPUFkOv8d1wNxHHrChm26buMiEYc1FrHWvDUaKVBwkiVtvSExHSpLGDvcnpI2Copyj9w==} + peerDependencies: + hono: '>=4.10.0' + zod: ^3.25.0 || ^4.0.0 + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -693,6 +717,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + openapi3-ts@4.6.0: + resolution: {integrity: sha512-a4sfn6L2sIShhtzJqmjGrARvxAW/3F2BJDdyRVvNF9VhAsZSh5hSyI3a9TNvmzBxXmq66nY5LNT5bQcBxYAZZg==} + path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} @@ -890,14 +917,27 @@ packages: utf-8-validate: optional: true + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + youch-core@0.3.3: resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} youch@4.1.0-beta.10: resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + snapshots: + '@asteasolutions/zod-to-openapi@8.5.0(zod@4.4.3)': + dependencies: + openapi3-ts: 4.6.0 + zod: 4.4.3 + '@cloudflare/kv-asset-handler@0.5.0': {} '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260630.1)': @@ -1010,6 +1050,19 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true + '@hono/zod-openapi@1.4.0(hono@4.12.27)(zod@4.4.3)': + dependencies: + '@asteasolutions/zod-to-openapi': 8.5.0(zod@4.4.3) + '@hono/zod-validator': 0.8.0(hono@4.12.27)(zod@4.4.3) + hono: 4.12.27 + openapi3-ts: 4.6.0 + zod: 4.4.3 + + '@hono/zod-validator@0.8.0(hono@4.12.27)(zod@4.4.3)': + dependencies: + hono: 4.12.27 + zod: 4.4.3 + '@img/colour@1.1.0': {} '@img/sharp-darwin-arm64@0.34.5': @@ -1223,13 +1276,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.6(vite@7.3.6)': + '@vitest/mocker@3.2.6(vite@7.3.6(yaml@2.9.0))': dependencies: '@vitest/spy': 3.2.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.6 + vite: 7.3.6(yaml@2.9.0) '@vitest/pretty-format@3.2.6': dependencies: @@ -1357,6 +1410,10 @@ snapshots: nanoid@3.3.15: {} + openapi3-ts@4.6.0: + dependencies: + yaml: 2.9.0 + path-to-regexp@6.3.0: {} pathe@2.0.3: {} @@ -1477,13 +1534,13 @@ snapshots: dependencies: pathe: 2.0.3 - vite-node@3.2.4: + vite-node@3.2.4(yaml@2.9.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.6 + vite: 7.3.6(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - jiti @@ -1498,7 +1555,7 @@ snapshots: - tsx - yaml - vite@7.3.6: + vite@7.3.6(yaml@2.9.0): dependencies: esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.4) @@ -1508,12 +1565,13 @@ snapshots: tinyglobby: 0.2.17 optionalDependencies: fsevents: 2.3.3 + yaml: 2.9.0 - vitest@3.2.6: + vitest@3.2.6(yaml@2.9.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.6 - '@vitest/mocker': 3.2.6(vite@7.3.6) + '@vitest/mocker': 3.2.6(vite@7.3.6(yaml@2.9.0)) '@vitest/pretty-format': 3.2.6 '@vitest/runner': 3.2.6 '@vitest/snapshot': 3.2.6 @@ -1531,8 +1589,8 @@ snapshots: tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.6 - vite-node: 3.2.4 + vite: 7.3.6(yaml@2.9.0) + vite-node: 3.2.4(yaml@2.9.0) why-is-node-running: 2.3.0 transitivePeerDependencies: - jiti @@ -1580,6 +1638,8 @@ snapshots: ws@8.21.0: {} + yaml@2.9.0: {} + youch-core@0.3.3: dependencies: '@poppinss/exception': 1.2.3 @@ -1592,3 +1652,5 @@ snapshots: '@speed-highlight/core': 1.2.17 cookie: 1.1.1 youch-core: 0.3.3 + + zod@4.4.3: {} diff --git a/src/env.ts b/src/env.ts index 5d0fbde..88efe59 100644 --- a/src/env.ts +++ b/src/env.ts @@ -7,4 +7,5 @@ export interface Env { DB: D1Database; ATTACHMENTS: R2Bucket; MAX_UPLOAD_BYTES?: string; + PUBLIC_BASE_URL?: string; } diff --git a/wrangler.jsonc b/wrangler.jsonc index 565cc11..8cac944 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -35,6 +35,7 @@ } ], "vars": { - "MAX_UPLOAD_BYTES": "52428800" + "MAX_UPLOAD_BYTES": "52428800", + "PUBLIC_BASE_URL": "https://cfw-attachment.bowong.cc" } }