diff --git a/README.md b/README.md index bcb01d5..03b012b 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ https://sheets-json-api.netlify.app/1vufOODlks7O9PGak54hMNP4LWBUAoP-XB9n3VW_aw5Y ## Development -The Edge Function lives in `netlify/edge-functions/opensheet.ts`. +The Edge Function lives in `netlify/edge-functions/opensheet.js`. ### Environment variables diff --git a/netlify/edge-functions/opensheet.ts b/netlify/edge-functions/opensheet.js similarity index 83% rename from netlify/edge-functions/opensheet.ts rename to netlify/edge-functions/opensheet.js index 84607d1..d03a26c 100644 --- a/netlify/edge-functions/opensheet.ts +++ b/netlify/edge-functions/opensheet.js @@ -1,11 +1,9 @@ -// netlify/edge-functions/opensheet.ts +// netlify/edge-functions/opensheet.js -import type { Context } from "@netlify/edge-functions"; - -export default async function handler(request: Request, context: Context) { +export default async function handler(request, context) { const GOOGLE_API_KEY = - ((globalThis as any).process?.env?.GOOGLE_API_KEY ?? - (globalThis as any).Deno?.env?.get("GOOGLE_API_KEY"))?.trim() || + (globalThis.process?.env?.GOOGLE_API_KEY ?? + globalThis.Deno?.env?.get("GOOGLE_API_KEY"))?.trim() || "AIzaSyC6y93Jo0fA1GH54L7VOkJzgZkiaXSSOOU"; if (!GOOGLE_API_KEY) { return error("Missing GOOGLE_API_KEY environment variable", 500); @@ -49,7 +47,7 @@ export default async function handler(request: Request, context: Context) { sheet = decodeURIComponent(sheet.replace(/\+/g, " ")); // If numeric, treat as 1-based sheet index and look up sheet title - if (!isNaN(sheet as unknown as number)) { + if (!isNaN(sheet)) { if (parseInt(sheet, 10) === 0) { return error("For this API, sheet numbers start at 1"); } @@ -84,12 +82,12 @@ export default async function handler(request: Request, context: Context) { return error(result.error.message, valuesRes.status || 400); } - const rows: Record[] = []; - const rawRows: string[][] = result.values || []; - const headers: string[] = rawRows.shift() || []; + const rows = []; + const rawRows = result.values || []; + const headers = rawRows.shift() || []; rawRows.forEach((row) => { - const rowData: Record = {}; + const rowData = {}; row.forEach((item, index) => { rowData[headers[index]] = item; }); @@ -111,7 +109,7 @@ export default async function handler(request: Request, context: Context) { return apiResponse; } -function error(message: string, status = 400) { +function error(message, status = 400) { return new Response(JSON.stringify({ error: message }), { status, headers: { diff --git a/package-lock.json b/package-lock.json index bc8bdc5..0ff3ad7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,14 +7,10 @@ "": { "name": "google-sheets-api", "version": "1.0.0", - "license": "ISC", + "license": "MIT", "dependencies": { "@netlify/edge-functions": "^2.17.1", "dotenv": "^17.2.1" - }, - "devDependencies": { - "ts-node": "^10.9.2", - "typescript": "^5.9.2" } }, "node_modules/@babel/code-frame": { @@ -40,19 +36,6 @@ "node": ">=6.9.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@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/@envelop/instrumentation": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@envelop/instrumentation/-/instrumentation-1.0.0.tgz", @@ -515,34 +498,6 @@ "node": ">=18.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@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.npmjs.org/@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.npmjs.org/@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/@netlify/dev-utils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@netlify/dev-utils/-/dev-utils-4.1.1.tgz", @@ -641,45 +596,6 @@ "node": "^18.14.0 || >=20" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", - "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "undici-types": "~7.10.0" - } - }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", @@ -761,32 +677,6 @@ "node": ">=18.0.0" } }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -836,13 +726,6 @@ "node": ">=14" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, "node_modules/better-ajv-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-1.2.0.tgz", @@ -934,13 +817,6 @@ "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", "license": "ISC" }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -973,16 +849,6 @@ "callsite": "^1.0.0" } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dot-prop": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz", @@ -1299,13 +1165,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -1667,50 +1526,6 @@ "tmp": "^0.2.0" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -1729,28 +1544,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", @@ -1782,13 +1575,6 @@ "uuid": "dist/esm/bin/uuid" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -1826,16 +1612,6 @@ "node": ">=18" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", diff --git a/package.json b/package.json index fd5c15c..a90c844 100644 --- a/package.json +++ b/package.json @@ -12,17 +12,13 @@ "url": "git+https://github.com/patricktobias86/google-sheets-api.git" }, "author": "patricktobias86", - "type": "commonjs", + "type": "module", "main": "index.js", "scripts": { - "test": "node --test -r ts-node/register" + "test": "node --test" }, "dependencies": { "@netlify/edge-functions": "^2.17.1", "dotenv": "^17.2.1" - }, - "devDependencies": { - "ts-node": "^10.9.2", - "typescript": "^5.9.2" } } diff --git a/test/json-api.test.ts b/test/json-api.test.js similarity index 100% rename from test/json-api.test.ts rename to test/json-api.test.js diff --git a/test/opensheet.test.ts b/test/opensheet.test.js similarity index 86% rename from test/opensheet.test.ts rename to test/opensheet.test.js index 3462351..f30ec06 100644 --- a/test/opensheet.test.ts +++ b/test/opensheet.test.js @@ -1,11 +1,11 @@ import test from 'node:test'; import assert from 'node:assert'; -import handler from '../netlify/edge-functions/opensheet'; +import handler from '../netlify/edge-functions/opensheet.js'; -const context = { waitUntil: () => {} } as any; +const context = { waitUntil: () => {} }; test('returns rows from Google Sheet', async () => { - (globalThis as any).caches = { + globalThis.caches = { default: { async match() { return undefined; @@ -36,7 +36,7 @@ test('redirects to first sheet when sheet is missing', async () => { test('falls back to static content on root path', async () => { const nextResponse = new Response('ok'); const req = new Request('https://example.com/'); - const res = await handler(req, { next: () => nextResponse, waitUntil: () => {} } as any); + const res = await handler(req, { next: () => nextResponse, waitUntil: () => {} }); assert.strictEqual(res, nextResponse); }); @@ -44,8 +44,8 @@ test('uses Deno env when process env missing', async () => { const originalKey = process.env.GOOGLE_API_KEY; delete process.env.GOOGLE_API_KEY; - (globalThis as any).Deno = { env: { get: () => 'FAKE_KEY' } }; - (globalThis as any).caches = { + globalThis.Deno = { env: { get: () => 'FAKE_KEY' } }; + globalThis.caches = { default: { async match() { return undefined; @@ -66,6 +66,6 @@ test('uses Deno env when process env missing', async () => { assert.deepStrictEqual(data, [{ headline: "It's working!" }]); globalThis.fetch = originalFetch; - delete (globalThis as any).Deno; + delete globalThis.Deno; process.env.GOOGLE_API_KEY = originalKey; });