try hono deploy

This commit is contained in:
adueck 2024-11-26 16:27:14 +05:00
parent 720868ebf0
commit e5bbcdf567
14 changed files with 3166 additions and 2267 deletions

View File

@ -1,34 +0,0 @@
name: Deploy Functions
on:
push:
branches:
- master
paths:
- "functions/**"
- ".github/workflows/deploy-functions.yml"
workflow_dispatch:
jobs:
deploy-functions:
runs-on: ubuntu-latest
env:
LINGDOCS_NPM_TOKEN: ${{ secrets.LINGDOCS_NPM_TOKEN }}
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
- run: npm install -g firebase-tools
- run: |
cp .npmrc functions
cd website
npm install
cd ..
cd functions
npm install
- name: deploy functions and hosting routes
run: firebase deploy -f --token ${FIREBASE_TOKEN}

18
.github/workflows/deploy-hono.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: Deploy Hono Worker
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 60
needs: test
steps:
- uses: actions/checkout@v4
- name: Build & Deploy Worker
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
workingDirectory: "new-functions"

File diff suppressed because it is too large Load Diff

View File

@ -20,8 +20,8 @@
"@types/google-spreadsheet": "^3.0.2", "@types/google-spreadsheet": "^3.0.2",
"@types/react": "^18.0.21", "@types/react": "^18.0.21",
"cors": "^2.8.5", "cors": "^2.8.5",
"firebase-admin": "^9.2.0", "firebase-admin": "^13.0.1",
"firebase-functions": "^3.24.1", "firebase-functions": "^6.1.1",
"googleapis": "^144.0.0", "googleapis": "^144.0.0",
"nano": "^9.0.3", "nano": "^9.0.3",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
@ -38,4 +38,4 @@
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"typescript": "^4.6.3" "typescript": "^4.6.3"
} }
} }

View File

@ -1,62 +1,63 @@
import * as functions from "firebase-functions"; import * as functions from "firebase-functions/v2";
import * as FT from "../../website/src/types/functions-types"; import * as FT from "../../website/src/types/functions-types";
import { receiveSubmissions } from "./submissions"; import { receiveSubmissions } from "./submissions";
import lingdocsAuth from "./middleware/lingdocs-auth"; import lingdocsAuth from "./middleware/lingdocs-auth";
import publish from "./publish"; import publish from "./publish";
export const publishDictionary = functions const couchdbUrl = functions.params.defineString("ABC");
.runWith({ console.log({ couchdb: couchdbUrl.value() });
timeoutSeconds: 525,
memory: "2GB",
})
.https.onRequest(
lingdocsAuth(
async (
req,
res: functions.Response<FT.PublishDictionaryResponse | FT.FunctionError>
) => {
if (req.user.level !== "editor") {
res.status(403).send({ ok: false, error: "403 forbidden" });
return;
}
try {
const response = await publish();
res.send(response);
} catch (e) {
// @ts-ignore
res.status(500).send({ ok: false, error: e.message });
}
}
)
);
export const submissions = functions export const publishDictionary = functions.https.onRequest(
.runWith({ {
timeoutSeconds: 60, timeoutSeconds: 525,
memory: "1GB", memory: "2GiB",
}) },
.https.onRequest( lingdocsAuth(
lingdocsAuth( async (
async ( req,
req, res // : functions.Response<FT.PublishDictionaryResponse | FT.FunctionError>
res: functions.Response<FT.SubmissionsResponse | FT.FunctionError> ) => {
) => { if (req.user.level !== "editor") {
if (!Array.isArray(req.body)) { res.status(403).send({ ok: false, error: "403 forbidden" });
res.status(400).send({ return;
ok: false,
error: "invalid submission",
});
return;
}
const suggestions = req.body as FT.SubmissionsRequest;
try {
const response = await receiveSubmissions(suggestions, true); // req.user.level === "editor");
// TODO: WARN IF ANY OF THE EDITS DIDN'T HAPPEN
res.send(response);
} catch (e) {
// @ts-ignore
res.status(500).send({ ok: false, error: e.message });
}
} }
) try {
); const response = await publish();
res.send(response);
} catch (e) {
// @ts-ignore
res.status(500).send({ ok: false, error: e.message });
}
}
)
);
export const submissions = functions.https.onRequest(
{
timeoutSeconds: 60,
memory: "1GiB",
},
lingdocsAuth(
async (
req,
res // : functions.Response<FT.SubmissionsResponse | FT.FunctionError>
) => {
if (!Array.isArray(req.body)) {
res.status(400).send({
ok: false,
error: "invalid submission",
});
return;
}
const suggestions = req.body as FT.SubmissionsRequest;
try {
const response = await receiveSubmissions(suggestions, true); // req.user.level === "editor");
// TODO: WARN IF ANY OF THE EDITS DIDN'T HAPPEN
res.send(response);
} catch (e) {
// @ts-ignore
res.status(500).send({ ok: false, error: e.message });
}
}
)
);

View File

@ -1,43 +1,63 @@
import cors from "cors"; import cors from "cors";
import fetch from "node-fetch"; import fetch from "node-fetch";
import type { https, Response } from "firebase-functions"; // unfortunately have to comment out all this typing because the new version
import * as FT from "../../../website/src/types/functions-types"; // of firebase-functions doesn't include it?
import type { LingdocsUser } from "../../../website/src/types/account-types"; // import type { https, Response } from "firebase-functions";
// import * as FT from "../../../website/src/types/functions-types";
// import type { LingdocsUser } from "../../../website/src/types/account-types";
const useCors = cors({ credentials: true, origin: /\.lingdocs\.com$/ }); const useCors = cors({ credentials: true, origin: /\.lingdocs\.com$/ });
interface ReqWUser extends https.Request { // interface ReqWUser extends https.Request {
user: LingdocsUser; // user: LingdocsUser;
} // }
/** /**
* creates a handler to pass to a firebase https.onRequest function * creates a handler to pass to a firebase https.onRequest function
* *
*/ */
export default function makeHandler(toRun: (req: ReqWUser, res: Response<FT.FunctionResponse>) => any | Promise<any>) { export default function makeHandler(
return function(reqPlain: https.Request, resPlain: Response<any>) { toRun: (
useCors(reqPlain, resPlain, async () => { req: any, //ReqWUser,
const { req, res } = await authorize(reqPlain, resPlain); res: any /*Response<FT.FunctionResponse> */
if (!req) { ) => any | Promise<any>
res.status(401).send({ ok: false, error: "unauthorized" }); ) {
return; return function (
}; reqPlain: any /* https.Request */,
toRun(req, res); resPlain: any /* Response<any> */
return; ) {
}); useCors(reqPlain, resPlain, async () => {
} const { req, res } = await authorize(reqPlain, resPlain);
if (!req) {
res.status(401).send({ ok: false, error: "unauthorized" });
return;
}
toRun(req, res);
return;
});
};
} }
async function authorize(req: https.Request, res: Response<any>): Promise<{ req: ReqWUser | null, res: Response<FT.FunctionResponse> }> { async function authorize(
const { headers: { cookie }} = req; req: any /* https.Request*/,
if (!cookie) { res: any /*Response<any>*/
return { req: null, res }; ): Promise<{
} req: any; // ReqWUser | null;
const r = await fetch("https://account.lingdocs.com/api/user", { headers: { cookie }}); res: any /*Response<FT.FunctionResponse>*/;
const { ok, user } = await r.json(); }> {
if (ok === true && user) { const {
req.user = user; headers: { cookie },
return { req: req as ReqWUser, res }; } = req;
} if (!cookie) {
return { req: null, res }; return { req: null, res };
} }
const r = await fetch("https://account.lingdocs.com/api/user", {
headers: { cookie },
});
const { ok, user } = await r.json();
if (ok === true && user) {
req.user = user;
return { req: req /* as ReqWUser*/, res };
}
return { req: null, res };
}

View File

@ -1,13 +1,20 @@
import Nano from "nano"; import Nano from "nano";
import * as FT from "../../website/src/types/functions-types"; import * as FT from "../../website/src/types/functions-types";
import * as functions from "firebase-functions"; // import * as functions from "firebase-functions/v2";
// import { // @ts-ignore
// addDictionaryEntries, import { defineString } from "firebase-functions/params";
// deleteEntry,
// updateDictionaryEntries,
// } from "./tools/spreadsheet-tools";
const nano = Nano(functions.config().couchdb.couchdb_url); // Define some parameters
// // import {
// // addDictionaryEntries,
// // deleteEntry,
// // updateDictionaryEntries,
// // } from "./tools/spreadsheet-tools";
const couchdbUrl = defineString("ABC");
console.log({ couchdb: couchdbUrl });
const nano = Nano("");
const reviewTasksDb = nano.db.use("review-tasks"); const reviewTasksDb = nano.db.use("review-tasks");
export async function receiveSubmissions( export async function receiveSubmissions(

33
new-functions/.gitignore vendored Normal file
View File

@ -0,0 +1,33 @@
# prod
dist/
# dev
.yarn/
!.yarn/releases
.vscode/*
!.vscode/launch.json
!.vscode/*.code-snippets
.idea/workspace.xml
.idea/usage.statistics.xml
.idea/shelf
# deps
node_modules/
.wrangler
# env
.env
.env.production
.dev.vars
# logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# misc
.DS_Store

8
new-functions/README.md Normal file
View File

@ -0,0 +1,8 @@
```
npm install
npm run dev
```
```
npm run deploy
```

1326
new-functions/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
{
"name": "new-functions",
"scripts": {
"dev": "wrangler dev",
"deploy": "wrangler deploy --minify"
},
"dependencies": {
"hono": "^4.6.12"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20241112.0",
"wrangler": "^3.88.0"
}
}

View File

@ -0,0 +1,10 @@
import { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => {
// c.env.LINGDOCS_COUCHDB
return c.text("Hi from hono");
});
export default app;

View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"skipLibCheck": true,
"lib": [
"ESNext"
],
"types": [
"@cloudflare/workers-types/2023-07-01"
],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
},
}

View File

@ -0,0 +1,28 @@
name = "new-functions"
main = "src/index.ts"
compatibility_date = "2024-11-26"
# compatibility_flags = [ "nodejs_compat" ]
# [vars]
# MY_VAR = "my-variable"
# [[kv_namespaces]]
# binding = "MY_KV_NAMESPACE"
# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# [[r2_buckets]]
# binding = "MY_BUCKET"
# bucket_name = "my-bucket"
# [[d1_databases]]
# binding = "DB"
# database_name = "my-database"
# database_id = ""
# [ai]
# binding = "AI"
# [observability]
# enabled = true
# head_sampling_rate = 1