From 80a2ad4f25cf3cc5b16fac769a24fd324fce70a9 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 18 Jul 2024 16:06:45 +0800 Subject: [PATCH] ci: add test and ci --- .editorconfig | 2 +- .github/workflows/CI.yaml | 20 + .prettierignore | 1 + .prettierrc | 6 - package.json | 56 +-- .../image-proxy/__test__/image-proxy.spec.ts | 15 + packages/image-proxy/package.json | 34 +- packages/image-proxy/src/index.ts | 81 ++--- packages/image-proxy/tsconfig.json | 12 +- packages/link-preview/README.md | 34 +- packages/link-preview/package.json | 27 +- packages/link-preview/src/auto_proxy.ts | 70 ++-- packages/link-preview/src/index.ts | 342 +++++++++--------- packages/link-preview/src/types.ts | 22 +- packages/link-preview/tsconfig.json | 12 +- packages/utils/package.json | 26 +- packages/utils/src/headers.ts | 68 ++-- packages/utils/src/index.ts | 2 +- packages/utils/src/response.ts | 144 ++++---- packages/utils/src/router.ts | 56 +-- packages/utils/src/types.ts | 2 +- packages/utils/src/url.ts | 44 +-- packages/utils/tsconfig.json | 12 +- packages/worker/package.json | 42 +-- packages/worker/src/affine.ts | 22 +- packages/worker/src/index.ts | 26 +- packages/worker/tsconfig.json | 12 +- pnpm-lock.yaml | 204 ++++++++++- tsconfig.json | 54 +-- 29 files changed, 838 insertions(+), 610 deletions(-) create mode 100644 .github/workflows/CI.yaml create mode 100644 .prettierignore delete mode 100644 .prettierrc create mode 100644 packages/image-proxy/__test__/image-proxy.spec.ts diff --git a/.editorconfig b/.editorconfig index 64ab260..67893f5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ root = true [*] -indent_style = tab +indent_style = space tab_width = 2 end_of_line = lf charset = utf-8 diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml new file mode 100644 index 0000000..ca25063 --- /dev/null +++ b/.github/workflows/CI.yaml @@ -0,0 +1,20 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: setup pnpm + uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: pnpm install + - run: pnpm run test diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..bd5535a --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +pnpm-lock.yaml diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 5c7b5d3..0000000 --- a/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "printWidth": 140, - "singleQuote": true, - "semi": true, - "useTabs": true -} diff --git a/package.json b/package.json index 602bfc6..ed3a013 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,33 @@ { - "name": "@affine/workers", - "version": "0.1.0", - "private": true, - "author": "DarkSky ", - "license": "MPL-2.0", - "type": "module", - "scripts": { - "dev": "pnpm --filter @affine/worker dev", - "deploy": "pnpm run --filter @affine/worker deploy", - "format": "pnpm prettier --write .", - "create-d1": "wrangler d1 create affine-worker", - "create-d1-schema": "pnpm run -r migrate:online" - }, - "devDependencies": { - "@cloudflare/workers-types": "^4.20231218.0", - "better-sqlite3": "^8.7.0", - "prettier": "3.1.1", - "typescript": "^5.3.3" - }, - "packageManager": "pnpm@9.2.0", - "pnpm": { - "overrides": { - "side-channel": "npm:@nolyfill/side-channel@latest" - } - } + "name": "@affine/workers", + "version": "0.1.0", + "private": true, + "author": "DarkSky ", + "license": "MPL-2.0", + "type": "module", + "scripts": { + "dev": "pnpm --filter @affine/worker dev", + "deploy": "pnpm run --filter @affine/worker deploy", + "format": "pnpm prettier --write .", + "create-d1": "wrangler d1 create affine-worker", + "create-d1-schema": "pnpm run -r migrate:online", + "test": "pnpm test --recursive" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20231218.0", + "better-sqlite3": "^8.7.0", + "prettier": "3.1.1", + "typescript": "^5.3.3" + }, + "packageManager": "pnpm@9.2.0", + "prettier": { + "printWidth": 140, + "singleQuote": true, + "semi": true + }, + "pnpm": { + "overrides": { + "side-channel": "npm:@nolyfill/side-channel@latest" + } + } } diff --git a/packages/image-proxy/__test__/image-proxy.spec.ts b/packages/image-proxy/__test__/image-proxy.spec.ts new file mode 100644 index 0000000..0db4574 --- /dev/null +++ b/packages/image-proxy/__test__/image-proxy.spec.ts @@ -0,0 +1,15 @@ +import { test } from 'node:test'; +import assert from 'node:assert'; + +import { imageProxy } from '../src/index.js'; + +await test('image-proxy', async () => { + const res = await imageProxy( + new Request('https://affine.pro', { + headers: { + origin: 'https://google.com', + }, + }), + ); + assert.strictEqual(res.status, 404, "Should return 404 if origin isn't allowed"); +}); diff --git a/packages/image-proxy/package.json b/packages/image-proxy/package.json index bdabb2b..7c6e42f 100644 --- a/packages/image-proxy/package.json +++ b/packages/image-proxy/package.json @@ -1,18 +1,20 @@ { - "name": "@affine/image-proxy", - "version": "0.0.1", - "author": "DarkSky ", - "license": "MPL-2.0", - "main": "src/index.ts", - "type": "module", - "private": true, - "scripts": {}, - "devDependencies": { - "@affine/utils": "workspace:*", - "@cloudflare/workers-types": "^4.20231218.0", - "@types/node": "^20.10.5", - "itty-router": "4.0.25", - "tldts": "^6.1.1", - "typescript": "^5.3.3" - } + "name": "@affine/image-proxy", + "version": "0.0.1", + "author": "DarkSky ", + "license": "MPL-2.0", + "main": "src/index.ts", + "type": "module", + "private": true, + "scripts": { + "test": "node --import @oxc-node/core/register --test __test__/**" + }, + "devDependencies": { + "@affine/utils": "workspace:*", + "@cloudflare/workers-types": "^4.20231218.0", + "@oxc-node/core": "^0.0.10", + "@types/node": "^20.10.5", + "tldts": "^6.1.1", + "typescript": "^5.3.3" + } } diff --git a/packages/image-proxy/src/index.ts b/packages/image-proxy/src/index.ts index 84e3047..404713f 100644 --- a/packages/image-proxy/src/index.ts +++ b/packages/image-proxy/src/index.ts @@ -1,48 +1,47 @@ import { cloneHeader, fixUrl, isOriginAllowed, isRefererAllowed, log, respBadRequest, respNotFound } from '@affine/utils'; -import type { IRequest } from 'itty-router'; -export async function imageProxy(request: IRequest) { - const origin = request.headers.get('Origin') ?? ''; - const referer = request.headers.get('Referer') ?? ''; - if (!isOriginAllowed(origin) && !isRefererAllowed(referer)) { - log('Invalid Origin', 'ERROR', { origin, referer }); - return respNotFound(); - } +export async function imageProxy(request: Request) { + const origin = request.headers.get('Origin') ?? ''; + const referer = request.headers.get('Referer') ?? ''; + if (!isOriginAllowed(origin) && !isRefererAllowed(referer)) { + log('Invalid Origin', 'ERROR', { origin, referer }); + return respNotFound(); + } - const url = new URL(request.url); - const imageURL = url.searchParams.get('url'); - if (!imageURL) { - return respBadRequest('Missing "url" parameter'); - } + const url = new URL(request.url); + const imageURL = url.searchParams.get('url'); + if (!imageURL) { + return respBadRequest('Missing "url" parameter'); + } - const targetURL = fixUrl(imageURL); - if (!targetURL) { - log('Invalid URL', 'ERROR', { origin, url: imageURL }); - return respBadRequest('Invalid URL', { allowOrigin: origin }); - } + const targetURL = fixUrl(imageURL); + if (!targetURL) { + log('Invalid URL', 'ERROR', { origin, url: imageURL }); + return respBadRequest('Invalid URL', { allowOrigin: origin }); + } - const imageRequest = new Request(targetURL.toString(), { - method: 'GET', - headers: cloneHeader(request.headers), - }); + const imageRequest = new Request(targetURL.toString(), { + method: 'GET', + headers: cloneHeader(request.headers), + }); - const accept = request.headers.get('accept'); - const response = await fetch(imageRequest, { - cf: { - image: { - fit: 'scale-down', - width: 1280, - format: accept && /image\/avif/.test(accept) ? 'avif' : 'webp', - }, - }, - }); - const modifiedResponse = new Response(response.body); - modifiedResponse.headers.set('Access-Control-Allow-Origin', request.headers.get('Origin') ?? 'null'); - modifiedResponse.headers.set('Vary', 'Origin'); - modifiedResponse.headers.set('Access-Control-Allow-Methods', 'GET'); - const contentType = response.headers.get('Content-Type'); - contentType && modifiedResponse.headers.set('Content-Type', contentType); - const contentDisposition = response.headers.get('Content-Disposition'); - contentDisposition && modifiedResponse.headers.set('Content-Disposition', contentDisposition); - return modifiedResponse; + const accept = request.headers.get('accept'); + const response = await fetch(imageRequest, { + cf: { + image: { + fit: 'scale-down', + width: 1280, + format: accept && /image\/avif/.test(accept) ? 'avif' : 'webp', + }, + }, + }); + const modifiedResponse = new Response(response.body); + modifiedResponse.headers.set('Access-Control-Allow-Origin', request.headers.get('Origin') ?? 'null'); + modifiedResponse.headers.set('Vary', 'Origin'); + modifiedResponse.headers.set('Access-Control-Allow-Methods', 'GET'); + const contentType = response.headers.get('Content-Type'); + contentType && modifiedResponse.headers.set('Content-Type', contentType); + const contentDisposition = response.headers.get('Content-Disposition'); + contentDisposition && modifiedResponse.headers.set('Content-Disposition', contentDisposition); + return modifiedResponse; } diff --git a/packages/image-proxy/tsconfig.json b/packages/image-proxy/tsconfig.json index 675e531..47a43e7 100644 --- a/packages/image-proxy/tsconfig.json +++ b/packages/image-proxy/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src/" - }, - "include": ["./src"], - "references": [] + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src/" + }, + "include": ["./src"], + "references": [] } diff --git a/packages/link-preview/README.md b/packages/link-preview/README.md index 318a622..d4f9891 100644 --- a/packages/link-preview/README.md +++ b/packages/link-preview/README.md @@ -4,16 +4,16 @@ A worker used to parse page metadata based on Open Graph Protocol. ```ts interface ResponseData { - url: string; - title?: string; - siteName?: string; - description?: string; - images?: string[]; - mediaType?: string; - contentType?: string; - charset?: string; - videos?: string[]; - favicons?: string[]; + url: string; + title?: string; + siteName?: string; + description?: string; + images?: string[]; + mediaType?: string; + contentType?: string; + charset?: string; + videos?: string[]; + favicons?: string[]; } ``` @@ -22,13 +22,13 @@ interface ResponseData { ```ts const url = 'https://github.com/toeverything/affine-workers'; const response = await fetch('https://affine-worker.toeverything.workers.dev/api/linkPreview', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - url, - }), + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + url, + }), }); const data = await response.json(); ``` diff --git a/packages/link-preview/package.json b/packages/link-preview/package.json index 2af18a1..768528e 100644 --- a/packages/link-preview/package.json +++ b/packages/link-preview/package.json @@ -1,16 +1,15 @@ { - "name": "@affine/link-preview", - "version": "0.0.1", - "author": "Flrande ", - "license": "MPL-2.0", - "main": "src/index.ts", - "type": "module", - "private": true, - "devDependencies": { - "@affine/utils": "workspace:*", - "@cloudflare/workers-types": "^4.20231218.0", - "@types/node": "^20.10.5", - "itty-router": "4.0.25", - "typescript": "^5.3.3" - } + "name": "@affine/link-preview", + "version": "0.0.1", + "author": "Flrande ", + "license": "MPL-2.0", + "main": "src/index.ts", + "type": "module", + "private": true, + "devDependencies": { + "@affine/utils": "workspace:*", + "@cloudflare/workers-types": "^4.20231218.0", + "@types/node": "^20.10.5", + "typescript": "^5.3.3" + } } diff --git a/packages/link-preview/src/auto_proxy.ts b/packages/link-preview/src/auto_proxy.ts index 65cb8ce..7ece9bb 100644 --- a/packages/link-preview/src/auto_proxy.ts +++ b/packages/link-preview/src/auto_proxy.ts @@ -3,47 +3,47 @@ const IMAGE_PROXY = '/api/worker/image-proxy'; const httpsDomain = new Set(); async function checkHttpsSupport(url: URL): Promise { - const httpsUrl = new URL(url.toString()); - httpsUrl.protocol = 'https:'; - try { - const response = await fetch(httpsUrl, { method: 'HEAD', redirect: 'manual' }); + const httpsUrl = new URL(url.toString()); + httpsUrl.protocol = 'https:'; + try { + const response = await fetch(httpsUrl, { method: 'HEAD', redirect: 'manual' }); - if (response.ok || (response.status >= 400 && response.status < 600)) { - return true; - } - } catch (_) {} - return false; + if (response.ok || (response.status >= 400 && response.status < 600)) { + return true; + } + } catch (_) {} + return false; } async function fixProtocol(url: string): Promise { - const targetUrl = new URL(url); - if (targetUrl.protocol !== 'http:') { - return targetUrl; - } else if (httpsDomain.has(targetUrl.hostname)) { - targetUrl.protocol = 'https:'; - return targetUrl; - } else if (await checkHttpsSupport(targetUrl)) { - httpsDomain.add(targetUrl.hostname); - targetUrl.protocol = 'https:'; - return targetUrl; - } - return targetUrl; + const targetUrl = new URL(url); + if (targetUrl.protocol !== 'http:') { + return targetUrl; + } else if (httpsDomain.has(targetUrl.hostname)) { + targetUrl.protocol = 'https:'; + return targetUrl; + } else if (await checkHttpsSupport(targetUrl)) { + httpsDomain.add(targetUrl.hostname); + targetUrl.protocol = 'https:'; + return targetUrl; + } + return targetUrl; } export function imageProxyBuilder(url: string): (url: string) => Promise { - try { - const proxy = new URL(url); - proxy.pathname = IMAGE_PROXY; + try { + const proxy = new URL(url); + proxy.pathname = IMAGE_PROXY; - return async (url) => { - try { - const targetUrl = await fixProtocol(url); - proxy.searchParams.set('url', targetUrl.toString()); - return proxy.toString(); - } catch (e) {} - return; - }; - } catch (e) { - return async (url) => url.toString(); - } + return async (url) => { + try { + const targetUrl = await fixProtocol(url); + proxy.searchParams.set('url', targetUrl.toString()); + return proxy.toString(); + } catch (e) {} + return; + }; + } catch (e) { + return async (url) => url.toString(); + } } diff --git a/packages/link-preview/src/index.ts b/packages/link-preview/src/index.ts index bfb8fe8..1262103 100644 --- a/packages/link-preview/src/index.ts +++ b/packages/link-preview/src/index.ts @@ -1,188 +1,188 @@ import { cloneHeader, fixUrl, isOriginAllowed, isRefererAllowed, log, respBadRequest } from '@affine/utils'; -import type { IRequest } from 'itty-router'; import type { RequestData, ResponseData } from './types'; import { imageProxyBuilder } from './auto_proxy'; function appendUrl(url: string | null, array?: string[]) { - if (url) { - const fixedUrl = fixUrl(url); - if (fixedUrl) { - array?.push(fixedUrl.toString()); - } - } + if (url) { + const fixedUrl = fixUrl(url); + if (fixedUrl) { + array?.push(fixedUrl.toString()); + } + } } async function reduceUrls(baseUrl: string, urls?: string[]) { - if (urls && urls.length > 0) { - const imageProxy = imageProxyBuilder(baseUrl); - const newUrls = await Promise.all(urls.map(imageProxy)); - return newUrls.filter((x): x is string => !!x); - } + if (urls && urls.length > 0) { + const imageProxy = imageProxyBuilder(baseUrl); + const newUrls = await Promise.all(urls.map(imageProxy)); + return newUrls.filter((x): x is string => !!x); + } + return []; } -export async function linkPreview(request: IRequest): Promise { - const origin = request.headers.get('Origin'); - const referer = request.headers.get('Referer'); - if ((origin && !isOriginAllowed(origin)) || (referer && !isRefererAllowed(referer))) { - log('Invalid Origin', 'ERROR', { origin, referer }); - return respBadRequest('Invalid header'); - } - - log('Received request', 'INFO', { origin, method: request.method }); - - const requestBody = await request.json().catch(() => { - log('Invalid request body', 'ERROR', { origin }); - return null; - }); - if (!requestBody) { - return respBadRequest('Invalid request body', { allowOrigin: origin }); - } - - const targetURL = fixUrl(requestBody.url); - if (!targetURL) { - log('Invalid URL', 'ERROR', { origin, url: requestBody.url }); - return respBadRequest('Invalid URL', { allowOrigin: origin }); - } - - log('Processing request', 'INFO', { origin, url: targetURL }); - - try { - const response: Response = await fetch(targetURL, { - headers: cloneHeader(request.headers), - cf: { - cacheTtl: 43200, - cacheEverything: true, - }, - }); - log('Fetched URL', 'INFO', { origin, url: targetURL, status: response.status }); - - const res: ResponseData = { - url: response.url, - images: [], - videos: [], - favicons: [], - }; - - if (response.body) { - const rewriter = new HTMLRewriter() - .on('meta', { - element(element) { - const property = element.getAttribute('property') ?? element.getAttribute('name'); - const content = element.getAttribute('content'); - if (property && content) { - switch (property.toLowerCase()) { - case 'og:title': - res.title = content; - break; - case 'og:site_name': - res.siteName = content; - break; - case 'og:description': - res.description = content; - break; - case 'og:image': - appendUrl(content, res.images); - break; - case 'og:video': - appendUrl(content, res.videos); - break; - case 'og:type': - res.mediaType = content; - break; - case 'description': - if (!res.description) { - res.description = content; - } - } - } - }, - }) - .on('link', { - element(element) { - if (element.getAttribute('rel')?.toLowerCase().includes('icon')) { - appendUrl(element.getAttribute('href'), res.favicons); - } - }, - }) - .on('title', { - text(text) { - if (!res.title) { - res.title = text.text; - } - }, - }) - .on('img', { - element(element) { - appendUrl(element.getAttribute('src'), res.images); - }, - }) - .on('video', { - element(element) { - appendUrl(element.getAttribute('src'), res.videos); - }, - }); - - await rewriter.transform(response).text(); - - res.images = await reduceUrls(request.url, res.images); - - log('Processed response with HTMLRewriter', 'INFO', { origin, url: response.url }); - } - - // fix favicon - { - // head default path of favicon - const faviconUrl = new URL('/favicon.ico', response.url); - const faviconResponse = await fetch(faviconUrl, { - method: 'HEAD', - cf: { - cacheTtl: 43200, - cacheEverything: true, - }, - }); - if (faviconResponse.ok) { - appendUrl(faviconUrl.toString(), res.favicons); - } - - res.favicons = await reduceUrls(request.url, res.favicons); - } - - const json = JSON.stringify(res); - log('Sending response', 'INFO', { origin, url: res.url, responseSize: json.length }); - return new Response(json, { - headers: { - 'content-type': 'application/json;charset=UTF-8', - ...getCorsHeaders(origin), - }, - }); - } catch (error) { - log('Error fetching URL', 'ERROR', { origin, url: targetURL, error }); - return new Response(null, { - status: 500, - statusText: 'Internal Server Error', - }); - } +export async function linkPreview(request: Request): Promise { + const origin = request.headers.get('Origin'); + const referer = request.headers.get('Referer'); + if ((origin && !isOriginAllowed(origin)) || (referer && !isRefererAllowed(referer))) { + log('Invalid Origin', 'ERROR', { origin, referer }); + return respBadRequest('Invalid header'); + } + + log('Received request', 'INFO', { origin, method: request.method }); + + const requestBody = await request.json().catch(() => { + log('Invalid request body', 'ERROR', { origin }); + return null; + }); + if (!requestBody) { + return respBadRequest('Invalid request body', { allowOrigin: origin }); + } + + const targetURL = fixUrl(requestBody.url); + if (!targetURL) { + log('Invalid URL', 'ERROR', { origin, url: requestBody.url }); + return respBadRequest('Invalid URL', { allowOrigin: origin }); + } + + log('Processing request', 'INFO', { origin, url: targetURL }); + + try { + const response: Response = await fetch(targetURL, { + headers: cloneHeader(request.headers), + cf: { + cacheTtl: 43200, + cacheEverything: true, + }, + }); + log('Fetched URL', 'INFO', { origin, url: targetURL, status: response.status }); + + const res: ResponseData = { + url: response.url, + images: [], + videos: [], + favicons: [], + }; + + if (response.body) { + const rewriter = new HTMLRewriter() + .on('meta', { + element(element) { + const property = element.getAttribute('property') ?? element.getAttribute('name'); + const content = element.getAttribute('content'); + if (property && content) { + switch (property.toLowerCase()) { + case 'og:title': + res.title = content; + break; + case 'og:site_name': + res.siteName = content; + break; + case 'og:description': + res.description = content; + break; + case 'og:image': + appendUrl(content, res.images); + break; + case 'og:video': + appendUrl(content, res.videos); + break; + case 'og:type': + res.mediaType = content; + break; + case 'description': + if (!res.description) { + res.description = content; + } + } + } + }, + }) + .on('link', { + element(element) { + if (element.getAttribute('rel')?.toLowerCase().includes('icon')) { + appendUrl(element.getAttribute('href'), res.favicons); + } + }, + }) + .on('title', { + text(text) { + if (!res.title) { + res.title = text.text; + } + }, + }) + .on('img', { + element(element) { + appendUrl(element.getAttribute('src'), res.images); + }, + }) + .on('video', { + element(element) { + appendUrl(element.getAttribute('src'), res.videos); + }, + }); + + await rewriter.transform(response).text(); + + res.images = await reduceUrls(request.url, res.images); + + log('Processed response with HTMLRewriter', 'INFO', { origin, url: response.url }); + } + + // fix favicon + { + // head default path of favicon + const faviconUrl = new URL('/favicon.ico', response.url); + const faviconResponse = await fetch(faviconUrl, { + method: 'HEAD', + cf: { + cacheTtl: 43200, + cacheEverything: true, + }, + }); + if (faviconResponse.ok) { + appendUrl(faviconUrl.toString(), res.favicons); + } + + res.favicons = await reduceUrls(request.url, res.favicons); + } + + const json = JSON.stringify(res); + log('Sending response', 'INFO', { origin, url: res.url, responseSize: json.length }); + return new Response(json, { + headers: { + 'content-type': 'application/json;charset=UTF-8', + ...getCorsHeaders(origin), + }, + }); + } catch (error) { + log('Error fetching URL', 'ERROR', { origin, url: targetURL, error }); + return new Response(null, { + status: 500, + statusText: 'Internal Server Error', + }); + } } -export function linkPreviewOption(request: IRequest): Response { - const origin = request.headers.get('Origin'); - log('Handling OPTIONS request', 'INFO', { origin }); - return new Response(null, { - headers: { - ...getCorsHeaders(origin), - 'Access-Control-Allow-Methods': 'POST, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type', - }, - }); +export function linkPreviewOption(request: Request): Response { + const origin = request.headers.get('Origin'); + log('Handling OPTIONS request', 'INFO', { origin }); + return new Response(null, { + headers: { + ...getCorsHeaders(origin), + 'Access-Control-Allow-Methods': 'POST, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type', + }, + }); } function getCorsHeaders(origin: string | null): { [key: string]: string } { - if (origin) { - return { - 'Access-Control-Allow-Origin': origin, - }; - } else { - return {}; - } + if (origin) { + return { + 'Access-Control-Allow-Origin': origin, + }; + } else { + return {}; + } } diff --git a/packages/link-preview/src/types.ts b/packages/link-preview/src/types.ts index 90b4124..5c0acf4 100644 --- a/packages/link-preview/src/types.ts +++ b/packages/link-preview/src/types.ts @@ -1,16 +1,16 @@ export interface RequestData { - url: string; + url: string; } export interface ResponseData { - url: string; - title?: string; - siteName?: string; - description?: string; - images?: string[]; - mediaType?: string; - contentType?: string; - charset?: string; - videos?: string[]; - favicons?: string[]; + url: string; + title?: string; + siteName?: string; + description?: string; + images?: string[]; + mediaType?: string; + contentType?: string; + charset?: string; + videos?: string[]; + favicons?: string[]; } diff --git a/packages/link-preview/tsconfig.json b/packages/link-preview/tsconfig.json index 675e531..47a43e7 100644 --- a/packages/link-preview/tsconfig.json +++ b/packages/link-preview/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src/" - }, - "include": ["./src"], - "references": [] + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src/" + }, + "include": ["./src"], + "references": [] } diff --git a/packages/utils/package.json b/packages/utils/package.json index a90e47c..6a60af6 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,15 +1,15 @@ { - "name": "@affine/utils", - "version": "0.0.1", - "author": "DarkSky ", - "license": "MPL-2.0", - "main": "src/index.ts", - "type": "module", - "private": true, - "devDependencies": { - "@cloudflare/workers-types": "^4.20231218.0", - "@types/node": "^20.10.5", - "tldts": "^6.1.1", - "typescript": "^5.3.3" - } + "name": "@affine/utils", + "version": "0.0.1", + "author": "DarkSky ", + "license": "MPL-2.0", + "main": "src/index.ts", + "type": "module", + "private": true, + "devDependencies": { + "@cloudflare/workers-types": "^4.20231218.0", + "@types/node": "^20.10.5", + "tldts": "^6.1.1", + "typescript": "^5.3.3" + } } diff --git a/packages/utils/src/headers.ts b/packages/utils/src/headers.ts index 984aec7..d50e821 100644 --- a/packages/utils/src/headers.ts +++ b/packages/utils/src/headers.ts @@ -1,52 +1,52 @@ type OriginRule = string | RegExp | ((origin: string) => boolean); const ALLOW_ORIGIN: OriginRule[] = [ - 'https://affine.pro', - 'https://app.affine.pro', - 'https://insider.affine.pro', - 'https://affine.fail', - 'https://try-blocksuite.vercel.app', - /https?:\/\/localhost(:\d+)/, - /https:\/\/.*?-toeverything\.vercel\.app$/, + 'https://affine.pro', + 'https://app.affine.pro', + 'https://insider.affine.pro', + 'https://affine.fail', + 'https://try-blocksuite.vercel.app', + /https?:\/\/localhost(:\d+)/, + /https:\/\/.*?-toeverything\.vercel\.app$/, ]; function isString(s: OriginRule): s is string { - return typeof s === 'string' || s instanceof String; + return typeof s === 'string' || s instanceof String; } export function isOriginAllowed(origin: string, allowedOrigin: OriginRule | OriginRule[] = ALLOW_ORIGIN) { - if (Array.isArray(allowedOrigin)) { - for (const allowed of allowedOrigin) { - if (isOriginAllowed(origin, allowed)) { - return true; - } - } - return false; - } else if (isString(allowedOrigin)) { - return origin === allowedOrigin; - } else if (allowedOrigin instanceof RegExp) { - return allowedOrigin.test(origin); - } - return allowedOrigin(origin); + if (Array.isArray(allowedOrigin)) { + for (const allowed of allowedOrigin) { + if (isOriginAllowed(origin, allowed)) { + return true; + } + } + return false; + } else if (isString(allowedOrigin)) { + return origin === allowedOrigin; + } else if (allowedOrigin instanceof RegExp) { + return allowedOrigin.test(origin); + } + return allowedOrigin(origin); } export function isRefererAllowed(referer: string, allowedOrigin: OriginRule | OriginRule[] = ALLOW_ORIGIN) { - try { - const origin = new URL(referer).origin; - return isOriginAllowed(origin, allowedOrigin); - } catch (_) { - return false; - } + try { + const origin = new URL(referer).origin; + return isOriginAllowed(origin, allowedOrigin); + } catch (_) { + return false; + } } const headerFilters = [/^Sec-/i, /^Accept/i, /^User-Agent$/i]; export function cloneHeader(source: Headers) { - let headers: Record = {}; - for (const [key, value] of source.entries()) { - if (headerFilters.some((filter) => filter.test(key))) { - headers[key] = value; - } - } - return headers; + let headers: Record = {}; + for (const [key, value] of source.entries()) { + if (headerFilters.some((filter) => filter.test(key))) { + headers[key] = value; + } + } + return headers; } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 161c162..2f70de8 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -5,5 +5,5 @@ export type { RouterHandler, Env } from './types'; export { fixUrl } from './url'; export function log(message: string | object, level: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR', data: object) { - console.log(JSON.stringify({ timestamp: new Date().toISOString(), level, message, ...data })); + console.log(JSON.stringify({ timestamp: new Date().toISOString(), level, message, ...data })); } diff --git a/packages/utils/src/response.ts b/packages/utils/src/response.ts index 4b96f0f..e754498 100644 --- a/packages/utils/src/response.ts +++ b/packages/utils/src/response.ts @@ -1,92 +1,92 @@ export function respBadRequest( - error: string, - options: { - allowOrigin?: string | null; - } = {}, + error: string, + options: { + allowOrigin?: string | null; + } = {}, ) { - const headers = new Headers(); - headers.set('content-type', 'application/json;charset=UTF-8'); - if (options.allowOrigin) { - headers.set('Access-Control-Allow-Origin', options.allowOrigin); - } - return new Response( - JSON.stringify({ - msg: error, - }), - { - headers, - status: 400, - }, - ); + const headers = new Headers(); + headers.set('content-type', 'application/json;charset=UTF-8'); + if (options.allowOrigin) { + headers.set('Access-Control-Allow-Origin', options.allowOrigin); + } + return new Response( + JSON.stringify({ + msg: error, + }), + { + headers, + status: 400, + }, + ); } export function respOk( - body: string | null, - options: { - allowOrigin?: string; - headers?: Record; - } = {}, + body: string | null, + options: { + allowOrigin?: string; + headers?: Record; + } = {}, ) { - const headers = new Headers(); - headers.set('content-type', 'application/json;charset=UTF-8'); - if (options.allowOrigin) { - headers.set('Access-Control-Allow-Origin', options.allowOrigin); - } - if (options.headers) { - for (const [key, value] of Object.entries(options.headers)) { - headers.set(key, value); - } - } + const headers = new Headers(); + headers.set('content-type', 'application/json;charset=UTF-8'); + if (options.allowOrigin) { + headers.set('Access-Control-Allow-Origin', options.allowOrigin); + } + if (options.headers) { + for (const [key, value] of Object.entries(options.headers)) { + headers.set(key, value); + } + } - return new Response(body, { - headers, - status: 200, - }); + return new Response(body, { + headers, + status: 200, + }); } export function respNoContent( - options: { - allowOrigin?: string; - } = {}, + options: { + allowOrigin?: string; + } = {}, ) { - const headers = new Headers(); - if (options.allowOrigin) { - headers.set('Access-Control-Allow-Origin', options.allowOrigin); - } - return new Response(null, { - headers, - status: 204, - }); + const headers = new Headers(); + if (options.allowOrigin) { + headers.set('Access-Control-Allow-Origin', options.allowOrigin); + } + return new Response(null, { + headers, + status: 204, + }); } export function respNotFound( - options: { - allowOrigin?: string; - } = {}, + options: { + allowOrigin?: string; + } = {}, ): Response { - const headers = new Headers(); - headers.set('content-type', 'application/json;charset=UTF-8'); - if (options.allowOrigin) { - headers.set('Access-Control-Allow-Origin', options.allowOrigin); - } - return new Response(null, { - headers, - status: 404, - }); + const headers = new Headers(); + headers.set('content-type', 'application/json;charset=UTF-8'); + if (options.allowOrigin) { + headers.set('Access-Control-Allow-Origin', options.allowOrigin); + } + return new Response(null, { + headers, + status: 404, + }); } export function respMethodNotAllowed( - options: { - allowOrigin?: string; - } = {}, + options: { + allowOrigin?: string; + } = {}, ): Response { - const headers = new Headers(); - headers.set('content-type', 'application/json;charset=UTF-8'); - if (options.allowOrigin) { - headers.set('Access-Control-Allow-Origin', options.allowOrigin); - } - return new Response(null, { - headers, - status: 405, - }); + const headers = new Headers(); + headers.set('content-type', 'application/json;charset=UTF-8'); + if (options.allowOrigin) { + headers.set('Access-Control-Allow-Origin', options.allowOrigin); + } + return new Response(null, { + headers, + status: 405, + }); } diff --git a/packages/utils/src/router.ts b/packages/utils/src/router.ts index 078ccc1..2353335 100644 --- a/packages/utils/src/router.ts +++ b/packages/utils/src/router.ts @@ -2,40 +2,40 @@ import { respNotFound } from './response'; import type { DomainRouters, RouterHandler } from './types'; export class DomainRouterBuilder { - private routers: DomainRouters = {}; + private routers: DomainRouters = {}; - static create(): DomainRouterBuilder { - return new DomainRouterBuilder(); - } + static create(): DomainRouterBuilder { + return new DomainRouterBuilder(); + } - public add(host: string, path: string, handler: RouterHandler) { - const hostRouter = this.routers[host] || {}; - hostRouter[path] = handler; - this.routers[host] = hostRouter; + public add(host: string, path: string, handler: RouterHandler) { + const hostRouter = this.routers[host] || {}; + hostRouter[path] = handler; + this.routers[host] = hostRouter; - return this; - } - public build(): DomainRouters { - return this.routers; - } + return this; + } + public build(): DomainRouters { + return this.routers; + } } export async function domainRoutersHandler( - routers: DomainRouters, - request: Request, - env: E, - ctx: ExecutionContext, + routers: DomainRouters, + request: Request, + env: E, + ctx: ExecutionContext, ): Promise { - const url = new URL(request.url); + const url = new URL(request.url); - const routerHandlers = routers[url.hostname]; - if (routerHandlers) { - for (const key in routerHandlers) { - if (url.pathname.startsWith(key)) { - const handler = routerHandlers[key]; - return handler(request, env, ctx); - } - } - } - return respNotFound(); + const routerHandlers = routers[url.hostname]; + if (routerHandlers) { + for (const key in routerHandlers) { + if (url.pathname.startsWith(key)) { + const handler = routerHandlers[key]; + return handler(request, env, ctx); + } + } + } + return respNotFound(); } diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index 2166889..839bb59 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -3,5 +3,5 @@ export type HostHandlers = Record>; export type DomainRouters = Record>; export interface Env { - Database: D1Database; + Database: D1Database; } diff --git a/packages/utils/src/url.ts b/packages/utils/src/url.ts index e3228ed..cbac4ed 100644 --- a/packages/utils/src/url.ts +++ b/packages/utils/src/url.ts @@ -1,32 +1,32 @@ import { getDomain, getSubdomain } from 'tldts'; export function fixUrl(url: string): URL | null { - if (typeof url !== 'string') { - return null; - } + if (typeof url !== 'string') { + return null; + } - let fullUrl = url; + let fullUrl = url; - // don't require // prefix, URL can handle protocol:domain - if (!url.startsWith('http:') && !url.startsWith('https:')) { - fullUrl = 'http://' + url; - } + // don't require // prefix, URL can handle protocol:domain + if (!url.startsWith('http:') && !url.startsWith('https:')) { + fullUrl = 'http://' + url; + } - try { - const parsed = new URL(fullUrl); + try { + const parsed = new URL(fullUrl); - const subDomain = getSubdomain(url); - const mainDomain = getDomain(url); - const fullDomain = subDomain ? `${subDomain}.${mainDomain}` : mainDomain; + const subDomain = getSubdomain(url); + const mainDomain = getDomain(url); + const fullDomain = subDomain ? `${subDomain}.${mainDomain}` : mainDomain; - if ( - ['http:', 'https:'].includes(parsed.protocol) && - // check hostname is a valid domain - fullDomain === parsed.hostname - ) { - return parsed; - } - } catch (_) {} + if ( + ['http:', 'https:'].includes(parsed.protocol) && + // check hostname is a valid domain + fullDomain === parsed.hostname + ) { + return parsed; + } + } catch (_) {} - return null; + return null; } diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json index 675e531..47a43e7 100644 --- a/packages/utils/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src/" - }, - "include": ["./src"], - "references": [] + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src/" + }, + "include": ["./src"], + "references": [] } diff --git a/packages/worker/package.json b/packages/worker/package.json index a509778..7530932 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,23 +1,23 @@ { - "name": "@affine/worker", - "version": "0.0.1", - "author": "DarkSky ", - "license": "MPL-2.0", - "private": true, - "type": "module", - "scripts": { - "deploy": "wrangler deploy -c wrangler.toml", - "dev": "wrangler dev -c wrangler-prod.toml" - }, - "devDependencies": { - "@affine/image-proxy": "workspace:*", - "@affine/link-preview": "workspace:*", - "@affine/utils": "workspace:*", - "@cloudflare/workers-types": "^4.20231218.0", - "@types/node": "^20.10.5", - "itty-router": "4.0.25", - "tldts": "^6.1.1", - "typescript": "^5.3.3", - "wrangler": "^3.22.1" - } + "name": "@affine/worker", + "version": "0.0.1", + "author": "DarkSky ", + "license": "MPL-2.0", + "private": true, + "type": "module", + "scripts": { + "deploy": "wrangler deploy -c wrangler.toml", + "dev": "wrangler dev -c wrangler-prod.toml" + }, + "devDependencies": { + "@affine/image-proxy": "workspace:*", + "@affine/link-preview": "workspace:*", + "@affine/utils": "workspace:*", + "@cloudflare/workers-types": "^4.20231218.0", + "@types/node": "^20.10.5", + "itty-router": "4.0.25", + "tldts": "^6.1.1", + "typescript": "^5.3.3", + "wrangler": "^3.22.1" + } } diff --git a/packages/worker/src/affine.ts b/packages/worker/src/affine.ts index 3acfd30..f63fb7c 100644 --- a/packages/worker/src/affine.ts +++ b/packages/worker/src/affine.ts @@ -4,19 +4,19 @@ import { respMethodNotAllowed, type Env, type RouterHandler } from '@affine/util import { Router } from 'itty-router'; export function AFFiNEWorker(): RouterHandler { - const router = Router(); + const router = Router(); - // deprecated - router.options('/api/worker/linkPreview', linkPreviewOption); - router.post('/api/worker/linkPreview', linkPreview); + // deprecated + router.options('/api/worker/linkPreview', linkPreviewOption); + router.post('/api/worker/linkPreview', linkPreview); - router.get('/api/worker/image-proxy', imageProxy); - router.options('/api/worker/link-preview', linkPreviewOption); - router.post('/api/worker/link-preview', linkPreview); + router.get('/api/worker/image-proxy', imageProxy); + router.options('/api/worker/link-preview', linkPreviewOption); + router.post('/api/worker/link-preview', linkPreview); - router.all('*', () => respMethodNotAllowed()); + router.all('*', () => respMethodNotAllowed()); - return (request: Request, env: Env, ctx: ExecutionContext) => { - return router.handle(request, env, ctx); - }; + return (request: Request, env: Env, ctx: ExecutionContext) => { + return router.handle(request, env, ctx); + }; } diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 2c839bb..c5ae8d9 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -9,17 +9,17 @@ const affine = AFFiNEWorker(); const routers = DomainRouterBuilder.create().add('localhost', '/api/', affine).add(WORKER_DOMAIN, '/api/', affine).build(); export default { - async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { - try { - return await domainRoutersHandler(routers, request, env, ctx); - } catch (e: any) { - return new Response( - JSON.stringify({ - success: false, - message: e.message || e.toString(), - }), - { status: 500 }, - ); - } - }, + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + try { + return await domainRoutersHandler(routers, request, env, ctx); + } catch (e: any) { + return new Response( + JSON.stringify({ + success: false, + message: e.message || e.toString(), + }), + { status: 500 }, + ); + } + }, }; diff --git a/packages/worker/tsconfig.json b/packages/worker/tsconfig.json index 675e531..47a43e7 100644 --- a/packages/worker/tsconfig.json +++ b/packages/worker/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src/" - }, - "include": ["./src"], - "references": [] + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src/" + }, + "include": ["./src"], + "references": [] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 602562b..8a09c4f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,12 +32,12 @@ importers: '@cloudflare/workers-types': specifier: ^4.20231218.0 version: 4.20231218.0 + '@oxc-node/core': + specifier: ^0.0.10 + version: 0.0.10 '@types/node': specifier: ^20.10.5 version: 20.10.5 - itty-router: - specifier: 4.0.25 - version: 4.0.25 tldts: specifier: ^6.1.1 version: 6.1.1 @@ -56,9 +56,6 @@ importers: '@types/node': specifier: ^20.10.5 version: 20.10.5 - itty-router: - specifier: 4.0.25 - version: 4.0.25 typescript: specifier: ^5.3.3 version: 5.3.3 @@ -150,6 +147,15 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@emnapi/core@1.2.0': + resolution: {integrity: sha512-E7Vgw78I93we4ZWdYCb4DGAwRROGkMIXk7/y87UmANR+J6qsWusmC3gLt0H+O0KOt5e6O38U8oJamgbudrES/w==} + + '@emnapi/runtime@1.2.0': + resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==} + + '@emnapi/wasi-threads@1.0.1': + resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} + '@esbuild-plugins/node-globals-polyfill@0.2.3': resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} peerDependencies: @@ -306,6 +312,95 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@napi-rs/wasm-runtime@0.2.4': + resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} + + '@oxc-node/core-android-arm-eabi@0.0.10': + resolution: {integrity: sha512-cyzVyKCQvLYfKGoe1FrAPAgFuUdpsNAYTMAUyMaLlgSSkcuJJwci/ZN68YjX5sNQd4n4aFfzE4YOvZbOhi9zxQ==} + cpu: [arm] + os: [android] + + '@oxc-node/core-android-arm64@0.0.10': + resolution: {integrity: sha512-NLuBh1h2AxSxuj/Ox/M5APFTAmNqqMVqsxiYS2KGjPLHENNDsoWDpEg0ppqrr0rzGaQM9CGhopKBWLrctnQ0uA==} + cpu: [arm64] + os: [android] + + '@oxc-node/core-darwin-arm64@0.0.10': + resolution: {integrity: sha512-ay3fc29nIG3ASXYnENlUBNAYnTcttdmzCbHcGJO9mZNxBZsT4x+zVLeazkNOZCjQq6LCt55zHqdLc/D5UWwF9A==} + cpu: [arm64] + os: [darwin] + + '@oxc-node/core-darwin-x64@0.0.10': + resolution: {integrity: sha512-CSJgW4d+qk5ZMl1fRPcK1ctpbcqN6FST5GvWNdKkOKJSDSJk/BWO/fyBBeq0KY/6RMK6AZphvapkuKwlrAejQQ==} + cpu: [x64] + os: [darwin] + + '@oxc-node/core-freebsd-x64@0.0.10': + resolution: {integrity: sha512-vU7d9iH+dppkxG5De//cbhEd8M+K7g116BHi1RyDQWQwiTYm+XLcF1ZJN6ZFfuIhtxaP0EZljz/t5E5oUUtvaQ==} + cpu: [x64] + os: [freebsd] + + '@oxc-node/core-linux-arm-gnueabihf@0.0.10': + resolution: {integrity: sha512-jKCD96DrplhYlktRK8YETTiJDpAkdHZGM+vFlYJzDwbsYEpf4GRrzBSzLk8gKXyb/F2RgJmyR/WFEuZL0AKBWA==} + cpu: [arm] + os: [linux] + + '@oxc-node/core-linux-arm64-gnu@0.0.10': + resolution: {integrity: sha512-j1SOGxfV5x7a0S9FbhrNsgZ6em23AX50kAnJYVDKjmeDdLWQA62719/+K5qzBZplo/orIwVPnh8gJRkfSNoLVQ==} + cpu: [arm64] + os: [linux] + + '@oxc-node/core-linux-arm64-musl@0.0.10': + resolution: {integrity: sha512-lXdD3IEHRQTwSHoUxMugb7WCJsLadQY8vSCne6CuznKWiDCDsoTXaoEhRV4DUZDp/69oebI31YO4VzYfn6J/pg==} + cpu: [arm64] + os: [linux] + + '@oxc-node/core-linux-ppc64-gnu@0.0.10': + resolution: {integrity: sha512-i+ORVJO2rSM74PWiJ0KCdNCIb5ppDGzaf1Dc9yA5NWe+q0J4oMXX8G+rrVre2mJboJD/it6nBs92RNjzoz1DAg==} + cpu: [ppc64] + os: [linux] + + '@oxc-node/core-linux-s390x-gnu@0.0.10': + resolution: {integrity: sha512-9skVvF5S+yJoBqDTL2EBhkcx/ht3qupbd77KKNDq7Akdlgx2gDlLMXwHzWUF3vVYbtZPB3GCmNOwUiEIStiP9A==} + cpu: [s390x] + os: [linux] + + '@oxc-node/core-linux-x64-gnu@0.0.10': + resolution: {integrity: sha512-0CIIUZ+o/9rz1Flq9u2kZKQBoP1NzD4gQzo1wkPKTUoIk6AGv81XBBW/Uwz06Mpa4rMn2BPidgTfqXq5E5+G0Q==} + cpu: [x64] + os: [linux] + + '@oxc-node/core-linux-x64-musl@0.0.10': + resolution: {integrity: sha512-fz4J9BHHMwOFT8k4EyIVUqO0LDSnGaTbXXCkm2Zei7b55s7agj4uJ711TqYj6lQccP2WYmnB5h6IqSTOMCe3hA==} + cpu: [x64] + os: [linux] + + '@oxc-node/core-wasm32-wasi@0.0.10': + resolution: {integrity: sha512-/NHK/6sGPP+j8iWLvyAGGNk6yy8ujw8nLVdg9qIxVGV9xcIl0CYMxb3GlymeqsLPYYtf5RbF/7dgYUmnEwb3pA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-node/core-win32-arm64-msvc@0.0.10': + resolution: {integrity: sha512-GZiwHOd+8A/uAHatgyPu8AfCrCOXDw+KWUoRKMMjWdYsEknTvc3tRlCx+XIjNE9G0ykwN4qAwT0aUly+oQ9Mog==} + cpu: [arm64] + os: [win32] + + '@oxc-node/core-win32-ia32-msvc@0.0.10': + resolution: {integrity: sha512-PS8Rmi86nUi9CJJHX7w6DWYjNXWkXJvXsS+IRz+xqdiqqJYnqDUfuO/37ZDn0VvwqIDhlsdMoiddmmhjc6kBAQ==} + cpu: [ia32] + os: [win32] + + '@oxc-node/core-win32-x64-msvc@0.0.10': + resolution: {integrity: sha512-TCiX5DUG1dFmHHAkzH5Adtz6PdCiYcqJccCMGqTsLPe/+7zFEWoXJbsoebLTs7XwTvm1gajwdVNm4JVaE6J/XQ==} + cpu: [x64] + os: [win32] + + '@oxc-node/core@0.0.10': + resolution: {integrity: sha512-o6xg0kyFMbbj6WErvoGnAkN1UhPXgrZufT+AyGpXiJtIUc98n83spzdAyMOTRFF1wN3YSko0pJAOk6CFbUh4bQ==} + + '@tybys/wasm-util@0.9.0': + resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + '@types/node-forge@1.3.10': resolution: {integrity: sha512-y6PJDYN4xYBxwd22l+OVH35N+1fCYWiuC3aiP2SlXVE6Lo7SS+rSx9r89hLxrP4pn6n1lBGhHJ12pj3F3Mpttw==} @@ -726,6 +821,22 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@emnapi/core@1.2.0': + dependencies: + '@emnapi/wasi-threads': 1.0.1 + tslib: 2.6.2 + optional: true + + '@emnapi/runtime@1.2.0': + dependencies: + tslib: 2.6.2 + optional: true + + '@emnapi/wasi-threads@1.0.1': + dependencies: + tslib: 2.6.2 + optional: true + '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': dependencies: esbuild: 0.17.19 @@ -813,6 +924,87 @@ snapshots: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + '@napi-rs/wasm-runtime@0.2.4': + dependencies: + '@emnapi/core': 1.2.0 + '@emnapi/runtime': 1.2.0 + '@tybys/wasm-util': 0.9.0 + optional: true + + '@oxc-node/core-android-arm-eabi@0.0.10': + optional: true + + '@oxc-node/core-android-arm64@0.0.10': + optional: true + + '@oxc-node/core-darwin-arm64@0.0.10': + optional: true + + '@oxc-node/core-darwin-x64@0.0.10': + optional: true + + '@oxc-node/core-freebsd-x64@0.0.10': + optional: true + + '@oxc-node/core-linux-arm-gnueabihf@0.0.10': + optional: true + + '@oxc-node/core-linux-arm64-gnu@0.0.10': + optional: true + + '@oxc-node/core-linux-arm64-musl@0.0.10': + optional: true + + '@oxc-node/core-linux-ppc64-gnu@0.0.10': + optional: true + + '@oxc-node/core-linux-s390x-gnu@0.0.10': + optional: true + + '@oxc-node/core-linux-x64-gnu@0.0.10': + optional: true + + '@oxc-node/core-linux-x64-musl@0.0.10': + optional: true + + '@oxc-node/core-wasm32-wasi@0.0.10': + dependencies: + '@napi-rs/wasm-runtime': 0.2.4 + optional: true + + '@oxc-node/core-win32-arm64-msvc@0.0.10': + optional: true + + '@oxc-node/core-win32-ia32-msvc@0.0.10': + optional: true + + '@oxc-node/core-win32-x64-msvc@0.0.10': + optional: true + + '@oxc-node/core@0.0.10': + optionalDependencies: + '@oxc-node/core-android-arm-eabi': 0.0.10 + '@oxc-node/core-android-arm64': 0.0.10 + '@oxc-node/core-darwin-arm64': 0.0.10 + '@oxc-node/core-darwin-x64': 0.0.10 + '@oxc-node/core-freebsd-x64': 0.0.10 + '@oxc-node/core-linux-arm-gnueabihf': 0.0.10 + '@oxc-node/core-linux-arm64-gnu': 0.0.10 + '@oxc-node/core-linux-arm64-musl': 0.0.10 + '@oxc-node/core-linux-ppc64-gnu': 0.0.10 + '@oxc-node/core-linux-s390x-gnu': 0.0.10 + '@oxc-node/core-linux-x64-gnu': 0.0.10 + '@oxc-node/core-linux-x64-musl': 0.0.10 + '@oxc-node/core-wasm32-wasi': 0.0.10 + '@oxc-node/core-win32-arm64-msvc': 0.0.10 + '@oxc-node/core-win32-ia32-msvc': 0.0.10 + '@oxc-node/core-win32-x64-msvc': 0.0.10 + + '@tybys/wasm-util@0.9.0': + dependencies: + tslib: 2.6.2 + optional: true + '@types/node-forge@1.3.10': dependencies: '@types/node': 20.10.5 diff --git a/tsconfig.json b/tsconfig.json index fe0b541..f211a28 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,29 +1,29 @@ { - "compilerOptions": { - "target": "ESNext", - "lib": ["ESNext"], - "module": "ESNext", - "moduleResolution": "Bundler", - "types": ["@cloudflare/workers-types"], - "resolveJsonModule": true, - "noEmit": true, - "isolatedModules": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "exactOptionalPropertyTypes": false, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitOverride": true, - "noImplicitThis": true, - "noUnusedParameters": true, - "noPropertyAccessFromIndexSignature": false, - "noUncheckedIndexedAccess": false, - "useUnknownInCatchVariables": true, - "skipLibCheck": true, - "verbatimModuleSyntax": true, - "esModuleInterop": true, - "noEmitOnError": true, - "noUnusedLocals": true, - "noImplicitReturns": true - } + "compilerOptions": { + "target": "ESNext", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["@cloudflare/workers-types"], + "resolveJsonModule": true, + "noEmit": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "exactOptionalPropertyTypes": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitOverride": true, + "noImplicitThis": true, + "noUnusedParameters": true, + "noPropertyAccessFromIndexSignature": false, + "noUncheckedIndexedAccess": false, + "useUnknownInCatchVariables": true, + "skipLibCheck": true, + "verbatimModuleSyntax": true, + "esModuleInterop": true, + "noEmitOnError": true, + "noUnusedLocals": true, + "noImplicitReturns": true + } }