try hono deploy
This commit is contained in:
parent
720868ebf0
commit
e5bbcdf567
|
@ -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}
|
|
|
@ -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
|
@ -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",
|
||||||
|
|
|
@ -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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -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 };
|
||||||
}
|
}
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,8 @@
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run deploy
|
||||||
|
```
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
@ -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"
|
||||||
|
},
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue