From 01b868310c50d58e574a435836b7b8d8814c8629 Mon Sep 17 00:00:00 2001 From: Andrei Jiroh Halili Date: Fri, 26 Jul 2024 13:25:08 +0800 Subject: [PATCH] feat(golinks): update API docs and use @slack/oauth for all things bot tokens A lot of implementation details involve using Slack SDK packages, among other chores. To simplify bot token storage, we use a KV namespace for that in the moment. Relates to https://github.com/andreijiroh-dev/personal-launchpad/issues/4 Signed-off-by: Andrei Jiroh Halili --- apps/golinks-v2/package.json | 8 + apps/golinks-v2/src/api/golinks.ts | 91 +++-- apps/golinks-v2/src/api/meta.ts | 2 + apps/golinks-v2/src/api/slack.ts | 351 +++++++++++------- apps/golinks-v2/src/api/wikilinks.ts | 116 ++++++ apps/golinks-v2/src/index.tsx | 145 +++++--- apps/golinks-v2/src/lib/auth.ts | 67 +++- apps/golinks-v2/src/lib/db.ts | 168 ++++----- apps/golinks-v2/src/types.ts | 4 +- apps/golinks-v2/wrangler.toml | 11 +- yarn.lock | 528 +++++++++++++++++++++------ 11 files changed, 1086 insertions(+), 405 deletions(-) diff --git a/apps/golinks-v2/package.json b/apps/golinks-v2/package.json index 6a6541d..6142770 100644 --- a/apps/golinks-v2/package.json +++ b/apps/golinks-v2/package.json @@ -24,15 +24,23 @@ "dependencies": { "@prisma/adapter-d1": "^5.17.0", "@prisma/client": "^5.17.0", + "@slack/oauth": "^3.0.0", + "@slack/web-api": "^7.3.1", "chanfana": "^2.0.2", "cross-fetch": "^4.0.0", + "date-fns": "^3.6.0", "hono": "^4.5.1", + "jose": "^5.6.3", + "jsonwebtoken": "^9.0.2", + "url-search-params": "^1.1.0", "zod": "^3.23.8" }, "devDependencies": { "@cloudflare/workers-types": "^4.20240718.0", + "@types/jsonwebtoken": "^9", "@types/node": "^20.14.11", "@types/service-worker-mock": "^2.0.4", + "@types/url-search-params": "^1", "prisma": "^5.17.0", "ts-node": "^10.9.2", "typescript": "^5.5.3", diff --git a/apps/golinks-v2/src/api/golinks.ts b/apps/golinks-v2/src/api/golinks.ts index 078e369..7266be8 100644 --- a/apps/golinks-v2/src/api/golinks.ts +++ b/apps/golinks-v2/src/api/golinks.ts @@ -1,8 +1,7 @@ import { OpenAPIRoute, Num, Bool, Str, contentJson } from "chanfana"; import { z } from "zod"; import { GoLinks } from "types"; -import { addGoLink, getGoLinks, updateGoLink } from "lib/db"; -import { adminApiKey, userApiKey } from "lib/constants"; +import { addGoLink, getGoLinks, getLink, updateGoLink } from "lib/db"; import { Context } from "hono"; import { generateSlug } from "lib/utils"; @@ -85,7 +84,7 @@ export class GoLinkList extends OpenAPIRoute { schema = { tags: ["golinks"], summary: "List all golinks", - description: "Accessing this API route does not require authenication, although we also added it for higher API limits.", + description: "Accessing this API route does not require authenication, although we also added it for higher API limits.", request: { query: z.object({ page: Num({ @@ -99,14 +98,14 @@ export class GoLinkList extends OpenAPIRoute { }), }), }, - security: [ - { - adminApiKey: [] - }, - { - userApiKey: [] - } - ], + security: [ + { + adminApiKey: [], + }, + { + userApiKey: [], + }, + ], responses: { "200": { description: "Returns a list of golinks", @@ -143,8 +142,9 @@ export class GoLinkUpdate extends OpenAPIRoute { tags: ["golinks"], parameters: [ { - name: "golink", + name: "slug", in: "path", + description: "Slug name of the golink" }, ], request: { @@ -163,35 +163,66 @@ export class GoLinkUpdate extends OpenAPIRoute { { adminApiKey: [], }, - { - userApiKey: [] - } + { + userApiKey: [], + }, ], responses: { "200": { description: "Shows the updated information about a golink", content: { "application/json": { - schema: GoLinks, + schema: z.object({ + ok: Bool({default: true}), + result: GoLinks + }), }, }, }, }, }; - async handle(c) { - const data = await this.getValidatedData(); - const { slug, newSlug, targetUrl } = data.body - try { - const result = await updateGoLink(c.env.golinks, slug, targetUrl, "golinks", newSlug) - return c.json({ - ok: true, - result - }) - } catch(error) { - return c.json({ + async handle(c: Context) { + const data = await this.getValidatedData(); + const { newSlug, targetUrl } = data.body; + const { slug } = c.req.param() + try { + const result = await updateGoLink(c.env.golinks, slug, targetUrl, "golinks", newSlug); + return c.json({ + ok: true, + result, + }); + } catch (error) { + return c.json({ ok: false, - error + error, }); + } + } +} + +export class GoLinkInfo extends OpenAPIRoute { + schema = { + tags: ["golinks"], + summary: "Get an information about a golink", + parameters: [ + { + name: "slug", + in: "path", + description: "Slug name of the golink", + }, + ], + responses: { + "200": { + + } } - } - } + }; + async handle(context: Context) { + const { slug } = context.req.param(); + const result = await getLink(context.env.golinks, slug, "golinks"); + if (!result) { + return context.json({ ok: false, error: "Not found" }, 404); + } + return context.json({ ok: true, result }); + } +} diff --git a/apps/golinks-v2/src/api/meta.ts b/apps/golinks-v2/src/api/meta.ts index dde83cd..72f6402 100644 --- a/apps/golinks-v2/src/api/meta.ts +++ b/apps/golinks-v2/src/api/meta.ts @@ -6,6 +6,7 @@ import { z } from "zod"; export class CommitHash extends OpenAPIRoute { schema = { + tags: ["meta"], description: "Get the latest commit hash", responses: { "200": { @@ -34,6 +35,7 @@ export class CommitHash extends OpenAPIRoute { export class PingPong extends OpenAPIRoute { schema = { + tags: ["meta"], description: "Ping the API service if it's up.", responses: { "200": { diff --git a/apps/golinks-v2/src/api/slack.ts b/apps/golinks-v2/src/api/slack.ts index f15dc15..49c8712 100644 --- a/apps/golinks-v2/src/api/slack.ts +++ b/apps/golinks-v2/src/api/slack.ts @@ -4,9 +4,14 @@ import crypto from "node:crypto"; import { Buffer } from "node:buffer"; import { generateSlug } from "lib/utils"; import { PrismaD1 } from "@prisma/adapter-d1"; -import { Prisma, PrismaClient } from "@prisma/client"; -import { addBotToken, lookupBotToken, slackOAuthExchange, updateBotToken } from "lib/auth"; -import jwt from "jsonwebtoken" +import { PrismaClient } from "@prisma/client"; +import { addBotToken, lookupBotToken, slackAppInstaller, slackOAuthExchange, updateBotToken } from "lib/auth"; +import { SignJWT } from "jose"; +import URLSearchParams from "url-search-params"; +import { Installation, InstallationQuery } from "@slack/oauth"; +import { Bool, OpenAPIRoute, Str } from "chanfana"; +import { adminApiKey } from "lib/constants"; +import { z } from "zod"; type SlackSlashCommand = { token?: string; @@ -24,50 +29,50 @@ type SlackSlashCommand = { }; type SlackInteractivityPayload = { - type: string; - user: { - id: string, - username: string, - name: string, - team_id: string - }, - api_app_id: string - token: string, - container: { - channel_id: string, - is_epheral: boolean - message_ts: string, - type: string - }, - trigger_id: string, - team: { - id: string, - name: string - }, - enterprise: null | { - id: string, - name: string - } - is_enterprise_install: boolean, - channel: { - values: object - }, - response_url: string, - actions: SlackInteractivityActions[] -} + type: string; + user: { + id: string; + username: string; + name: string; + team_id: string; + }; + api_app_id: string; + token: string; + container: { + channel_id: string; + is_epheral: boolean; + message_ts: string; + type: string; + }; + trigger_id: string; + team: { + id: string; + name: string; + }; + enterprise: null | { + id: string; + name: string; + }; + is_enterprise_install: boolean; + channel: { + values: object; + }; + response_url: string; + actions: SlackInteractivityActions[]; +}; type SlackInteractivityActions = { - block_id: string, - action_id: string, - type: string, - text: { - type: string, - text: string, - emoji: boolean - }, - value: string, - action_ts: string -} + block_id: string; + action_id: string; + type: string; + text: { + type: string; + text: string; + emoji: boolean; + }; + value: string; + action_ts: string; +}; async function helpMessage(context: Context, params: SlackSlashCommand) { const challenge = generateSlug(24); @@ -153,19 +158,9 @@ async function helpMessage(context: Context, params: SlackSlashCommand) { } async function authChallengePrompt(context: Context, params: SlackInteractivityPayload) { + const secret = new TextEncoder().encode(context.env.JWT_SIGNING_KEY); const challenge = params.actions[0].value; - const jwtState = jwt.sign({ - slack_id: params.user.id, - slack_team: params.team.id, - slack_enterprise_id: params.enterprise !== null ? params.enterprise.id : null, - slack_enterprise_install: params.is_enterprise_install, - challenge -}, -context.env.JWT_SIGNING_KEY, -{ - issuer: context.env.BASE_URL, - expiresIn: '15m', -}) + const jwtState = await new SignJWT(); const githubAuthUrl = `${context.env.BASE_URL}/auth/github?client_id=slack&state=${jwtState}`; const templateCallback = { blocks: [ @@ -187,7 +182,7 @@ context.env.JWT_SIGNING_KEY, emoji: true, }, url: githubAuthUrl, - style: "primary" + style: "primary", }, ], }, @@ -216,51 +211,47 @@ context.env.JWT_SIGNING_KEY, }, ], }; - return context.json(templateCallback, 200); + return context.json(templateCallback, 200); } -async function sneakyWIPScreen(context: Context, params: SlackInteractivityPayload) { - const blocks = { - type: "modal", - close: { - type: "plain_text", - text: "Close", - emoji: true, - }, - title: { - type: "plain_text", - text: "You're a bit sneaky!", - emoji: true, +const sneakyWIPScreen = { + type: "modal", + close: { + type: "plain_text", + text: "Close", + emoji: true, + }, + title: { + type: "plain_text", + text: "You're a bit sneaky!", + emoji: true, + }, + blocks: [ + { + type: "section", + text: { + type: "mrkdwn", + text: "This feature is currently under development and working on stablizing this for you to use them soon.", + }, }, - blocks: [ - { - type: "section", - text: { - type: "mrkdwn", - text: "This feature is currently under development and working on stablizing this for you to use them soon.", - }, + { + type: "section", + text: { + type: "mrkdwn", + text: ":speech_balloon: *Send feedback*\nWe want to know your experience with our Slack integration for Andrei Jiroh's golinks service.", }, - { - type: "section", + accessory: { + type: "button", text: { - type: "mrkdwn", - text: ":speech_balloon: *Send feedback*\nWe want to know your experience with our Slack integration for @ajhalili2006's golinks service.", - }, - accessory: { - type: "button", - text: { - type: "plain_text", - text: "Open in GitHub", - emoji: true, - }, - url: "https://go.andreijiroh.xyz/feedback/slack-integration", + type: "plain_text", + text: "Open in GitHub", + emoji: true, }, + url: "https://go.andreijiroh.xyz/feedback/slack-integration", }, - ], - }; - return context.json(blocks, 200); -} - + }, + ], +}; /** * Handle requests for OAuth-based app installation * @param context @@ -290,33 +281,29 @@ export async function slackOAuthCallback(context: Context) { const result = await api.json(); console.log(`[slack-oauth] result: ${JSON.stringify(result)} (${api.status})`); + if (result.ok == false) { return context.json({ ok: false, error: result.error }, api.status); } - const team = await lookupBotToken( - context.env.golinks, - result.is_enterprise_install == true ? result.enterprise.id : result.team.id, - result.is_enterprise_install, - ); - console.log(`[prisma-client] ${JSON.stringify(team)}`); - - if (team == null) { - const deploy = await addBotToken( - context.env.golinks, - result.is_enterprise_install == true ? result.enterprise.id : result.team.id, - result.is_enterprise_install, - ); - console.log(`[db] ${deploy}`); - } else { - const deploy = await updateBotToken( - context.env.golinks, - result.team.id, - result.access_token, - result.is_enterprise_install == true ? result.enterprise.id : false, - ); - console.log(`[db] ${deploy}`); - } + const installation: Installation<"v2"> = { + isEnterpriseInstall: result.is_enterprise_install, + team: result.team, + appId: result.appId, + bot: { + id: result.bot_user_id, + token: result.access_token, + scopes: ["commands", "im:write"], + userId: result.bot_user_id, + }, + authVersion: "v2", + user: result.authed_user, + enterprise: result.enterprise, + enterpriseUrl: result.enterprise !== null ? `https://${result.enterprise.name}.enterprise.slack.com` : undefined, + incomingWebhook: undefined, + tokenType: "bot", + }; + await slackAppInstaller(context.env).installationStore.storeInstallation(installation); return context.newResponse(`Installation success! Try it now with "/go help" command.`); } catch (err) { console.error(err); @@ -381,17 +368,127 @@ export async function handleSlackCommand(context: Context) { export async function handleSlackInteractivity(context: Context) { const authToken = await context.req.query("token"); const { payload } = await context.req.parseBody(); - const parsedPayload: SlackInteractivityPayload = JSON.parse(payload) - const headers = await context.req.header() + const parsedPayload: SlackInteractivityPayload = JSON.parse(payload); + const headers = await context.req.header(); await console.log(`[slack-interactivity] data:`, parsedPayload); - await console.log(`[slack-interactivity] actions:`, parsedPayload.actions) + await console.log(`[slack-interactivity] actions:`, parsedPayload.actions); await console.log(`[slack-interactivity] headers:`, headers); - if (parsedPayload.actions[0].action_id == "github-auth-challenge") { - return await authChallengePrompt(context, parsedPayload) - } else { - return await sneakyWIPScreen(context, parsedPayload); - } + if (parsedPayload.actions[0].action_id == "github-auth-challenge") { + return await authChallengePrompt(context, parsedPayload); + } else { + return await context.json(sneakyWIPScreen, 200); + } +} + +export class debugApiGetSlackBotToken extends OpenAPIRoute { + schema = { + tags: ["debug"], + summary: "Get a Slack bot token for a installation for manual admin access to Slack APIs.", + description: "Note that due to its nature, this is currently off-limits to public access and only documented here for convenience.", + request: { + query: z.object({ + teamId: Str({ + description: "Slack team ID", + required: true, + }), + enterpriseInstall: Bool({ + description: "Set to `true` to enable queries to Enterprise Grid organization installs.", + required: false, + }), + enterpriseId: Str({ + description: "Enterprise Grid organization ID", + required: false, + }), + }), + }, + security: [ + { + adminApiKey: [], + }, + ], + }; + + async handle(context: Context) { + const data = await this.getValidatedData(); + const query = data.query; + const params: InstallationQuery = { + teamId: query.teamId, + enterpriseId: query.enterpriseInstall == true ? query.enterpriseId : undefined, + isEnterpriseInstall: query.enterpriseInstall, + }; + const installQuery = await slackAppInstaller(context.env).authorize(params); + return context.json({ + ok: true, + result: installQuery, + }); + } +} + +export class debugApiTestSlackBotToken extends OpenAPIRoute { + schema = { + tags: ["debug"], + summary: "Calls `auth.test` Slack API method to test if the bot token is valid", + request: { + query: z.object({ + teamId: Str({ + description: "Slack team ID", + required: true, + }), + enterpriseInstall: Bool({ + description: "Set to `true` to enable queries to Enterprise Grid organization installs.", + required: false, + }), + enterpriseId: Str({ + description: "Enterprise Grid organization ID", + required: false, + }), + }), + }, + security: [ + { + adminApiKey: [], + }, + ], + }; + + async handle(context: Context) { + const data = await this.getValidatedData(); + const query = data.query; + const enterpriseInstall = query.enterpriseInstall || false + const params: InstallationQuery = { + teamId: query.teamId, + enterpriseId: query.enterpriseInstall == true ? query.enterpriseId : undefined, + isEnterpriseInstall: enterpriseInstall, + }; + const botToken = await slackAppInstaller(context.env).installationStore.fetchInstallation(params); + if (!botToken) { + return context.json({ ok: false, error: "Installation not found" }, 404); + } + try { + const apiResult = await fetch("https://slack.com/api/auth.test", { + headers: { + Authorization: `Bearer ${botToken.bot.token}`, + }, + }); + return context.json({ + ok: true, + result: { + installation: botToken, + authTest: await apiResult.json(), + }, + }); + } catch (error) { + console.error(error); + return context.json( + { + ok: false, + error: "Something gone horribly wrong.", + }, + 500, + ); + } + } } /** diff --git a/apps/golinks-v2/src/api/wikilinks.ts b/apps/golinks-v2/src/api/wikilinks.ts index e69de29..3a9e2f1 100644 --- a/apps/golinks-v2/src/api/wikilinks.ts +++ b/apps/golinks-v2/src/api/wikilinks.ts @@ -0,0 +1,116 @@ +import { OpenAPIRoute, Num, Bool, Str, contentJson } from "chanfana"; +import { z } from "zod"; +import { GoLinks } from "types"; +import { addGoLink, getGoLinks, updateGoLink } from "lib/db"; +import { Context } from "hono"; + +export class WikiLinkCreate extends OpenAPIRoute { + schema = { + tags: ["wikilinks"], + summary: "Create a golink-styled wikilink for `wiki.andreijiroh.xyz/go/*` and `andreijiroh.xyz/go/*`", + request: { + body: { + content: { + "application/json": { + schema: z.object({ + slug: Str({ required: true }), + targetUrl: Str({ required: true, example: "https://github.com/integrations/slack" }), + }), + }, + }, + }, + }, + security: [ + { + adminApiKey: [], + }, + ], + }; + async handle(context) { + const data = await this.getValidatedData(); + const linkToCreate = data.body; + console.log(`[golinks-api] received body for link creation ${JSON.stringify(linkToCreate)}`); + try { + const result = await addGoLink(context.env.golink, linkToCreate.slug, linkToCreate.targetUrl, "wikilinks"); + if (result) { + return context.json({ + ok: true, + result, + }); + } else { + return context.json( + { + ok: false, + error: "Something gone wrong while handling this request.", + }, + 400, + ); + } + } catch (error) { + console.error(error); + return context.json( + { + ok: false, + error: "Internal server error", + }, + 500, + ); + } + } +} + +export class WikiLinkList extends OpenAPIRoute { + schema = { + tags: ["wikilinks"], + summary: "List all golink-styled wikilinks", + description: "Accessing this API route does not require authenication, although we also added it for higher API limits.", + request: { + query: z.object({ + page: Num({ + description: "Page number", + default: 0, + required: false, + }), + isActive: Bool({ + description: "Filter by is_active status", + required: false, + }), + }), + }, + security: [ + { + adminApiKey: [], + }, + { + userApiKey: [], + }, + ], + responses: { + "200": { + description: "Returns a list of golinks", + content: { + "application/json": { + schema: z.object({ + series: z.object({ + success: Bool(), + result: GoLinks.array(), + }), + }), + }, + }, + }, + }, + }; + + async handle(c) { + const data = await this.getValidatedData(); + const { page, isActive } = data.query; + + const links = await getGoLinks(c.env.golinks, page !== undefined ? page : 0, isActive, "wikilinks"); + + return { + success: true, + result: links, + }; + } +} diff --git a/apps/golinks-v2/src/index.tsx b/apps/golinks-v2/src/index.tsx index 210d5ae..33c9ad4 100644 --- a/apps/golinks-v2/src/index.tsx +++ b/apps/golinks-v2/src/index.tsx @@ -1,4 +1,4 @@ -import { GoLinkCreate, GoLinkList, GoLinkUpdate } from "api/golinks"; +import { GoLinkCreate, GoLinkInfo, GoLinkList, GoLinkUpdate } from "api/golinks"; import { fromHono } from "chanfana"; import { Context, Hono } from "hono"; import { cors } from "hono/cors"; @@ -13,16 +13,27 @@ import { discordServerNotFound, golinkNotFound, tags, - userApiKey, + userApiKey, } from "lib/constants"; import { DiscordInviteLinkCreate, DiscordInviteLinkList } from "api/discord"; -import { adminApiKeyAuth } from "lib/auth"; +import { adminApiKeyAuth, slackAppInstaller } from "lib/auth"; import { DeprecatedGoLinkPage } from "pages/deprecated-link"; import { CommitHash, PingPong } from "api/meta"; import { prettyJSON } from "hono/pretty-json"; import { generateNewIssueUrl, handleOldUrls } from "lib/utils"; -import { handleSlackCommand, handleSlackInteractivity, slackOAuth, slackOAuthCallback } from "api/slack"; +import { + debugApiGetSlackBotToken, + debugApiTestSlackBotToken, + handleSlackCommand, + handleSlackInteractivity, + slackOAuth, + slackOAuthCallback, +} from "api/slack"; import { githubAuth } from "api/github"; +import * as jose from "jose"; +import { IncomingMessage, ServerResponse } from "node:http"; +import { InstallationQuery } from "@slack/oauth"; +import { WikiLinkCreate } from "api/wikilinks"; // Start a Hono app const app = new Hono<{ Bindings: EnvBindings }>(); @@ -42,6 +53,7 @@ app.use( }), ); app.use("/api/*", adminApiKeyAuth); +app.use("/debug", adminApiKeyAuth); app.use("/*", async (c, next) => await handleOldUrls(c, next)); // Setup OpenAPI registry @@ -67,18 +79,24 @@ const openapi = fromHono(app, { }); openapi.registry.registerComponent("securitySchemes", "adminApiKey", adminApiKey); -openapi.registry.registerComponent("securitySchemes", "userApiKey", userApiKey) +openapi.registry.registerComponent("securitySchemes", "userApiKey", userApiKey); // Register OpenAPI endpoints in this section openapi.get("/api/links", GoLinkList); openapi.post("/api/links", GoLinkCreate); -openapi.put("/api/links/:slug", GoLinkUpdate) +openapi.get("/api/links/:slug", GoLinkInfo) +openapi.put("/api/links/:slug", GoLinkUpdate); +// category:wikilinks +openapi.post("/api/wikilinks", WikiLinkCreate) // category:discord-invites openapi.get("/api/discord-invites", DiscordInviteLinkList); openapi.post("/api/discord-invites", DiscordInviteLinkCreate); // category:meta openapi.get("/api/ping", PingPong); openapi.get("/api/commit", CommitHash); +// category: debug +openapi.get("/api/debug/slack/bot-token", debugApiGetSlackBotToken); +openapi.get("/api/debug/slack/auth-test", debugApiTestSlackBotToken); // Undocumented API endpoints: Slack integration app.post("/api/slack/slash-commands/:command", async (c) => handleSlackCommand(c)); @@ -109,18 +127,72 @@ app.get("/workers", (c) => { return c.redirect(`${origin}/workers/dashboard`); }); +/* Old /edit/* stuff */ +app.get("/edit", (c) => { + return c.redirect("/workers/edit"); +}); + +app.get("/landing/deprecated", (c) => { + const params = c.req.query(); + + if (!c.req.param()) { + return c.newResponse("This is unexpected request for this route", 400); + } + + return c.html(); +}); + +app.get("/feedback/:type", (c) => { + const { type } = c.req.param(); + const { url } = c.req.query(); + return c.redirect(generateNewIssueUrl(type, "golinks", url)); +}); + +app.get("/api/debug/bindings", (context) => { + console.log(context.env); + return context.json(context.env); +}); +app.get("/api/debug/jwt", async (c) => { + const { token } = c.req.query(); + const secret = new TextEncoder().encode(c.env.JWT_SIGNING_KEY); + const payload = { + slack_team_id: "T1234", + slack_user_id: "U1234", + slack_enterprise_id: "E1234", + slack_enterprise_install: true, + example_jwt: true, + }; + + if (token == null) { + const exampleToken = await new jose.SignJWT(payload) + .setProtectedHeader({ alg: "HS256" }) + .setAudience("challenge_1234abcd") + .setIssuer(c.env.BASE_URL) + .setIssuedAt() + .setExpirationTime("15 minutes") + .sign(secret); + return c.json({ ok: true, result: exampleToken }); + } + + const result = await jose.jwtVerify(token, secret, { + issuer: c.env.BASE_URL, + clockTolerance: 30, + }); + return c.json({ ok: true, result }); +}); + app.get("/:link", async (c) => { try { const { link } = c.req.param(); console.log(`[redirector]: incoming request with path - ${link}`); const result = await getLink(c.env.golinks, link); console.log(`[redirector]: resulting data - ${JSON.stringify(result)}`); - if (!result) { - return c.newResponse(golinkNotFound(c.req.url), 404) - } + if (!result) { + return c.newResponse(golinkNotFound(c.req.url), 404); + } return c.redirect(result.targetUrl); } catch (error) { - console.error(`[redirector]: error`, error) + console.error(`[redirector]: error`, error); return c.newResponse(golinkNotFound(c.req.url), 500); } }); @@ -129,50 +201,29 @@ app.get("/discord/:inviteCode", async (c) => { const { inviteCode } = c.req.param(); console.log(`[redirector]: incoming request with path - /discord/${inviteCode}`); const result = await getDiscordInvite(c.env.golinks, inviteCode); - if (!result) { - return c.newResponse(discordServerNotFound(c.req.url), 404) - } + if (!result) { + return c.newResponse(discordServerNotFound(c.req.url), 404); + } return c.redirect(`https://discord.gg/${result.inviteCode}`); } catch (error) { - console.error(`[redirector]: error`, error) + console.error(`[redirector]: error`, error); return c.newResponse(discordServerNotFound(c.req.url), 500); } }); app.get("/go/:link", async (c) => { - try { - const { link } = c.req.param(); - console.log(`[redirector]: incoming request with path - ${link}`); - const result = await getLink(c.env.golinks, link, "wikilinks"); - console.log(`[redirector]: resulting data - ${JSON.stringify(result)}`); - if (!result) { - return c.newResponse(golinkNotFound(c.req.url), 404) - } - return c.redirect(result.targetUrl); - } catch (error) { - console.error(`[redirector]: error`, error) - return c.newResponse(golinkNotFound(c.req.url), 500); - } -}) - -/* Old /edit/* stuff */ -app.get("/edit", (c) => { - return c.redirect("/workers/edit"); -}); - -app.get("/landing/deprecated", (c) => { - const params = c.req.query(); - - if (!c.req.param()) { - return c.newResponse("This is unexpected request for this route", 400); + try { + const { link } = c.req.param(); + console.log(`[redirector]: incoming request with path - ${link}`); + const result = await getLink(c.env.golinks, link, "wikilinks"); + console.log(`[redirector]: resulting data - ${JSON.stringify(result)}`); + if (!result) { + return c.newResponse(golinkNotFound(c.req.url), 404); + } + return c.redirect(result.targetUrl); + } catch (error) { + console.error(`[redirector]: error`, error); + return c.newResponse(golinkNotFound(c.req.url), 500); } - - return c.html(); -}); - -app.get("/feedback/:type", (c) => { - const { type } = c.req.param(); - const { url } = c.req.query(); - return c.redirect(generateNewIssueUrl(type, "golinks", url)); }); // Export the Hono app diff --git a/apps/golinks-v2/src/lib/auth.ts b/apps/golinks-v2/src/lib/auth.ts index b4b1362..c33dd6c 100644 --- a/apps/golinks-v2/src/lib/auth.ts +++ b/apps/golinks-v2/src/lib/auth.ts @@ -1,24 +1,71 @@ import { PrismaD1 } from "@prisma/adapter-d1"; import { PrismaClient } from "@prisma/client"; import { Context, Next } from "hono"; -import { EnvBindings, Env } from "types"; +import { EnvBindings } from "types"; import { generateSlug } from "./utils"; import { add } from "date-fns"; import { error } from "console"; +import { InstallProvider } from "@slack/oauth"; + +export const slackAppInstaller = (env: EnvBindings) => + new InstallProvider({ + clientId: env.SLACK_OAUTH_ID, + clientSecret: env.SLACK_OAUTH_SECRET, + stateSecret: env.SLACK_OAUTH_STATE_SECRET, + installationStore: { + storeInstallation: async (installation) => { + if (installation.isEnterpriseInstall) { + // support for org wide app installation + return await env.slackBotTokens.put(installation.enterprise.id, JSON.stringify(installation)); + } else { + // single team app installation + return await env.slackBotTokens.put(installation.team.id, JSON.stringify(installation)); + } + throw new Error("Failed saving installation data to installationStore"); + }, + fetchInstallation: async (query) => { + if (query.isEnterpriseInstall && query.enterpriseId !== undefined) { + return await env.slackBotTokens.get(query.enterpriseId, "json"); + } + if (query.teamId !== undefined) { + return await env.slackBotTokens.get(query.teamId, "json"); + } + throw new Error("Failed fetching installation"); + }, + deleteInstallation: async (query) => { + if (query.isEnterpriseInstall && query.enterpriseId !== undefined) { + // org wide app installation deletion + return await env.slackBotTokens.delete(query.enterpriseId); + } + if (query.teamId !== undefined) { + // single team app installation deletion + return await env.slackBotTokens.delete(query.teamId); + } + throw new Error("Failed to delete installation"); + }, + }, + }); export async function adminApiKeyAuth(c: Context, next: Next) { - if (c.req.method == "GET" || c.req.method == "HEAD") { - return await next(); - } + const adminApiKey = c.env.ADMIN_KEY; + const apiKeyHeader = c.req.header("X-Golinks-Admin-Key"); if (c.req.path.startsWith("/api/slack")) { return await next(); + } else if (c.req.path.startsWith("/debug") || c.req.path.startsWith("/api/debug")) { + if (c.env.DEPLOY_ENV == "development") { + return await next(); + } } - const adminApiKey = c.env.ADMIN_KEY; - const apiKeyHeader = c.req.header("X-Golinks-Admin-Key"); console.debug(`[auth] ${adminApiKey}:${apiKeyHeader}`); + if (c.req.method == "GET" || c.req.method == "HEAD") { + if (!c.req.path.startsWith("/api/debug")) { + return await next(); + } + } + if (!apiKeyHeader || apiKeyHeader !== adminApiKey) { return c.json( { @@ -43,7 +90,7 @@ export async function slackOAuthExchange(payload: object) { return api; } -export async function lookupBotToken(db: EnvBindings["golinks"], teamId: string, is_enterprise_install?: boolean) { +export async function lookupBotToken(db: EnvBindings["golinks"], teamId: string, is_enterprise_install?: boolean) { const adapter = new PrismaD1(db); const prisma = new PrismaClient({ adapter }); try { @@ -59,7 +106,7 @@ export async function lookupBotToken(db: EnvBindings["golinks"], teamId: st } } -export async function addBotToken(db: EnvBindings["golinks"], teamId: string, token: string, enterprise_install?: boolean) { +export async function addBotToken(db: EnvBindings["golinks"], teamId: string, token: string, enterprise_install?: boolean) { const adapter = new PrismaD1(db); const prisma = new PrismaClient({ adapter }); try { @@ -76,7 +123,7 @@ export async function addBotToken(db: EnvBindings["golinks"], teamId: strin } } -export async function updateBotToken(db: EnvBindings["golinks"], teamId: string, token: string, enterprise_install?: boolean) { +export async function updateBotToken(db: EnvBindings["golinks"], teamId: string, token: string, enterprise_install?: boolean) { const adapter = new PrismaD1(db); const prisma = new PrismaClient({ adapter }); try { @@ -122,7 +169,7 @@ export async function getUserInfoAndGenerateTicket(token: string, context: Conte } } -export async function addNewChallenge(db: EnvBindings["golinks"], challenge, metadata) { +export async function addNewChallenge(db: EnvBindings["golinks"], challenge, metadata) { const adapter = new PrismaD1(db); const prisma = new PrismaClient({ adapter }); try { diff --git a/apps/golinks-v2/src/lib/db.ts b/apps/golinks-v2/src/lib/db.ts index 903490f..ededd96 100644 --- a/apps/golinks-v2/src/lib/db.ts +++ b/apps/golinks-v2/src/lib/db.ts @@ -193,92 +193,92 @@ export async function updateGoLink( } export async function deprecateGoLink(db: EnvBindings["golinks"], slug: string, reason: string, type: "golinks" | "wikilinks" | null) { - const adapter = new PrismaD1(db); - const prisma = new PrismaClient({ adapter }); - - try { - if (type == "wikilinks") { - const result = prisma.wikiLinks.update({ - where: { - slug, - }, - data: { - is_active: false, - deactivation_reason: reason, - }, - }); - return result; - } else { - const result = prisma.goLink.update({ - where: { - slug, - }, - data: { - is_active: false, - deactivation_reason: reason, - }, - }); - return result; - } - } catch (error) { - if (error instanceof Prisma.PrismaClientKnownRequestError) { - console.error(`[prisma-client] known client error: ${error.code} - ${error.message}`); - - if (error.code === "P2002") { - return Promise.reject(new Error("A Discord invite code with that slug already exists.")); - } - - return Promise.reject(new Error("A error occurred while querying the database.")); - } else { - console.error(`[prisma-client]- Unexpected error`, error); - return Promise.reject(new Error("An unexpected error occurred.")); + const adapter = new PrismaD1(db); + const prisma = new PrismaClient({ adapter }); + + try { + if (type == "wikilinks") { + const result = prisma.wikiLinks.update({ + where: { + slug, + }, + data: { + is_active: false, + deactivation_reason: reason, + }, + }); + return result; + } else { + const result = prisma.goLink.update({ + where: { + slug, + }, + data: { + is_active: false, + deactivation_reason: reason, + }, + }); + return result; + } + } catch (error) { + if (error instanceof Prisma.PrismaClientKnownRequestError) { + console.error(`[prisma-client] known client error: ${error.code} - ${error.message}`); + + if (error.code === "P2002") { + return Promise.reject(new Error("A Discord invite code with that slug already exists.")); } + + return Promise.reject(new Error("A error occurred while querying the database.")); + } else { + console.error(`[prisma-client]- Unexpected error`, error); + return Promise.reject(new Error("An unexpected error occurred.")); } -}; + } +} export async function undeprecateGoLink(db: EnvBindings["golinks"], slug: string, type: "golinks" | "wikilinks" | null) { - const adapter = new PrismaD1(db); - const prisma = new PrismaClient({ adapter }); - - try { - if (type == "wikilinks") { - const result = prisma.wikiLinks.update({ - where: { - slug, - }, - data: { - is_active: true, - deactivation_reason: null, - }, - }); - return result; - } else { - const result = prisma.goLink.update({ - where: { - slug, - }, - data: { - is_active: true, - deactivation_reason: null, - }, - }); - return result; - } - } catch (error) { - if (error instanceof Prisma.PrismaClientKnownRequestError) { - console.error(`[prisma-client] known client error: ${error.code} - ${error.message}`); - - if (error.code === "P2002") { - return Promise.reject(new Error("A Discord invite code with that slug already exists.")); - } - - return Promise.reject(new Error("A error occurred while querying the database.")); - } else { - console.error(`[prisma-client]- Unexpected error`, error); - return Promise.reject(new Error("An unexpected error occurred.")); + const adapter = new PrismaD1(db); + const prisma = new PrismaClient({ adapter }); + + try { + if (type == "wikilinks") { + const result = prisma.wikiLinks.update({ + where: { + slug, + }, + data: { + is_active: true, + deactivation_reason: null, + }, + }); + return result; + } else { + const result = prisma.goLink.update({ + where: { + slug, + }, + data: { + is_active: true, + deactivation_reason: null, + }, + }); + return result; + } + } catch (error) { + if (error instanceof Prisma.PrismaClientKnownRequestError) { + console.error(`[prisma-client] known client error: ${error.code} - ${error.message}`); + + if (error.code === "P2002") { + return Promise.reject(new Error("A Discord invite code with that slug already exists.")); } + + return Promise.reject(new Error("A error occurred while querying the database.")); + } else { + console.error(`[prisma-client]- Unexpected error`, error); + return Promise.reject(new Error("An unexpected error occurred.")); } -}; + } +} export async function deleteGoLink(db: EnvBindings["golinks"], slug: string, type: "golinks" | "wikilinks" | null) { const adapter = new PrismaD1(db); @@ -286,16 +286,16 @@ export async function deleteGoLink(db: EnvBindings["golinks"], slug: string try { if (type == "wikilinks") { - const result = prisma.wikiLinks.delete({ + const result = prisma.wikiLinks.delete({ where: { slug }, }); return result; - } else { - const result = prisma.goLink.delete({ + } else { + const result = prisma.goLink.delete({ where: { slug }, }); return result; - } + } } catch (error) { if (error instanceof Prisma.PrismaClientKnownRequestError) { console.error(`[prisma-client] known client error: ${error.code} - ${error.message}`); diff --git a/apps/golinks-v2/src/types.ts b/apps/golinks-v2/src/types.ts index cc04fcf..a2d4c20 100644 --- a/apps/golinks-v2/src/types.ts +++ b/apps/golinks-v2/src/types.ts @@ -41,7 +41,9 @@ export interface EnvBindings { golinks: D1Database; ADMIN_KEY: string; BASE_URL: string; - JWT_SIGNING_KEY: string + JWT_SIGNING_KEY: string; + SLACK_OAUTH_STATE_SECRET: string; + slackBotTokens: KVNamespace; } /*type EnvBindings = { diff --git a/apps/golinks-v2/wrangler.toml b/apps/golinks-v2/wrangler.toml index adf81db..04cf6cf 100644 --- a/apps/golinks-v2/wrangler.toml +++ b/apps/golinks-v2/wrangler.toml @@ -13,7 +13,7 @@ compatibility_date = "2024-07-12" # TODO: Update this once a month account_id = "cf0bd808c6a294fd8c4d8f6d2cdeca05" placement = { mode = "smart" } -compatibility_flags = [ "nodejs_compat" ] +node_compat = true # Please do not leak your secrets here. vars = { DEPLOY_ENV = "development", ADMIN_KEY = "gostg_localdev-null", BASE_URL = "https://stellapent-cier.fawn-cod.ts.net" } @@ -21,6 +21,9 @@ vars = { DEPLOY_ENV = "development", ADMIN_KEY = "gostg_localdev-null", BASE_URL d1_databases = [ { binding = "golinks", database_name = "golinks-db-preview", database_id = "0b415a64-cc61-4c2b-a7c8-2d223f18e996", migrations_dir = "migrations" }, ] +kv_namespaces = [ + { binding = "slackBotTokens", id = "24a1f8bb9d434e97a490c43b74435e64" } +] [env.staging] workers_dev = true @@ -28,6 +31,9 @@ vars = { DEPLOY_ENV = "staging", BASE_URL = "https://staging.go-next.andreijiroh d1_databases = [ { binding = "golinks", database_name = "golinks-db-preview", database_id = "0b415a64-cc61-4c2b-a7c8-2d223f18e996", migrations_dir = "migrations" }, ] +kv_namespaces = [ + { binding = "slackBotTokens", id = "24a1f8bb9d434e97a490c43b74435e64" } +] routes = [ { custom_domain = true, pattern = "staging.go-next.andreijiroh.xyz", zone_name = "andreijiroh.xyz" }, { custom_domain = true, pattern = "go-next.andreijiroh.xyz", zone_name = "andreijiroh.xyz" }, @@ -39,6 +45,9 @@ vars = { DEPLOY_ENV = "production", BASE_URL = "https://go.andreijiroh.xyz" } d1_databases = [ { binding = "golinks", database_name = "golinks-db", database_id = "63e746f4-40de-4f8c-a3e5-7969cde040b3", migrations_dir = "migrations" }, ] +kv_namespaces = [ + { binding = "slackBotTokens", id = "21b6d6aaacbf4f04b52a66a9ed11fcd3" } +] routes = [ { pattern = "go.andreijiroh.xyz", zone_name = "andreijiroh.xyz", custom_domain = true }, # Inspired by @flanican's website on adding /go/ links to diff --git a/yarn.lock b/yarn.lock index 9efef16..5ed5f8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,13 +15,13 @@ __metadata: version: 0.0.0-use.local resolution: "@ajhalili2006/api-servers@workspace:." dependencies: - "@cloudflare/workers-types": "npm:^4.20240712.0" - "@types/node": "npm:^20.14.11" + "@cloudflare/workers-types": "npm:^4.20240722.0" + "@types/node": "npm:^20.14.12" "@yarnpkg/sdks": "npm:^3.1.3" prettier: "npm:^3.3.3" ts-node: "npm:^10.9.2" - typescript: "npm:^5.5.3" - wrangler: "npm:^3.65.0" + typescript: "npm:^5.5.4" + wrangler: "npm:^3.66.0" yarn-upgrade-all: "npm:^0.7.2" languageName: unknown linkType: soft @@ -30,7 +30,7 @@ __metadata: version: 0.0.0-use.local resolution: "@ajhalili2006/cfw-email-router@workspace:apps/cfw-email-router" dependencies: - wrangler: "npm:^3.60.0" + wrangler: "npm:^3.66.0" languageName: unknown linkType: soft @@ -41,14 +41,22 @@ __metadata: "@cloudflare/workers-types": "npm:^4.20240718.0" "@prisma/adapter-d1": "npm:^5.17.0" "@prisma/client": "npm:^5.17.0" + "@slack/oauth": "npm:^3.0.0" + "@slack/web-api": "npm:^7.3.1" + "@types/jsonwebtoken": "npm:^9" "@types/node": "npm:^20.14.11" "@types/service-worker-mock": "npm:^2.0.4" + "@types/url-search-params": "npm:^1" chanfana: "npm:^2.0.2" cross-fetch: "npm:^4.0.0" + date-fns: "npm:^3.6.0" hono: "npm:^4.5.1" + jose: "npm:^5.6.3" + jsonwebtoken: "npm:^9.0.2" prisma: "npm:^5.17.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.5.3" + url-search-params: "npm:^1.1.0" wrangler: "npm:^3.65.1" yarn-upgrade-all: "npm:^0.7.2" zod: "npm:^3.23.8" @@ -100,13 +108,6 @@ __metadata: languageName: node linkType: hard -"@cloudflare/workerd-darwin-64@npm:1.20240712.0": - version: 1.20240712.0 - resolution: "@cloudflare/workerd-darwin-64@npm:1.20240712.0" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - "@cloudflare/workerd-darwin-64@npm:1.20240718.0": version: 1.20240718.0 resolution: "@cloudflare/workerd-darwin-64@npm:1.20240718.0" @@ -121,13 +122,6 @@ __metadata: languageName: node linkType: hard -"@cloudflare/workerd-darwin-arm64@npm:1.20240712.0": - version: 1.20240712.0 - resolution: "@cloudflare/workerd-darwin-arm64@npm:1.20240712.0" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - "@cloudflare/workerd-darwin-arm64@npm:1.20240718.0": version: 1.20240718.0 resolution: "@cloudflare/workerd-darwin-arm64@npm:1.20240718.0" @@ -142,13 +136,6 @@ __metadata: languageName: node linkType: hard -"@cloudflare/workerd-linux-64@npm:1.20240712.0": - version: 1.20240712.0 - resolution: "@cloudflare/workerd-linux-64@npm:1.20240712.0" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - "@cloudflare/workerd-linux-64@npm:1.20240718.0": version: 1.20240718.0 resolution: "@cloudflare/workerd-linux-64@npm:1.20240718.0" @@ -163,13 +150,6 @@ __metadata: languageName: node linkType: hard -"@cloudflare/workerd-linux-arm64@npm:1.20240712.0": - version: 1.20240712.0 - resolution: "@cloudflare/workerd-linux-arm64@npm:1.20240712.0" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - "@cloudflare/workerd-linux-arm64@npm:1.20240718.0": version: 1.20240718.0 resolution: "@cloudflare/workerd-linux-arm64@npm:1.20240718.0" @@ -184,13 +164,6 @@ __metadata: languageName: node linkType: hard -"@cloudflare/workerd-windows-64@npm:1.20240712.0": - version: 1.20240712.0 - resolution: "@cloudflare/workerd-windows-64@npm:1.20240712.0" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@cloudflare/workerd-windows-64@npm:1.20240718.0": version: 1.20240718.0 resolution: "@cloudflare/workerd-windows-64@npm:1.20240718.0" @@ -212,13 +185,6 @@ __metadata: languageName: node linkType: hard -"@cloudflare/workers-types@npm:^4.20240712.0": - version: 4.20240712.0 - resolution: "@cloudflare/workers-types@npm:4.20240712.0" - checksum: 10c0/4a6c283c98699474f64ad87d8795596ecfd8fd1c22cfdb9be534c8cebdfd3e212d8a5881ecd9631c0cfdd2c1bca5b274e1a66f225f128fb5722efc65fd4e7341 - languageName: node - linkType: hard - "@cloudflare/workers-types@npm:^4.20240718.0": version: 4.20240718.0 resolution: "@cloudflare/workers-types@npm:4.20240718.0" @@ -226,6 +192,13 @@ __metadata: languageName: node linkType: hard +"@cloudflare/workers-types@npm:^4.20240722.0": + version: 4.20240722.0 + resolution: "@cloudflare/workers-types@npm:4.20240722.0" + checksum: 10c0/2e720d1c06afb523e54ea93f7d458af12bd59f0557b96ba441d22e68038e1c3d0571d1d7f1db8d3af579befaa709a92ef21b596657626a445f75698853bd9055 + languageName: node + linkType: hard + "@cspotcode/source-map-support@npm:0.8.1, @cspotcode/source-map-support@npm:^0.8.0": version: 0.8.1 resolution: "@cspotcode/source-map-support@npm:0.8.1" @@ -595,6 +568,56 @@ __metadata: languageName: node linkType: hard +"@slack/logger@npm:^4, @slack/logger@npm:^4.0.0": + version: 4.0.0 + resolution: "@slack/logger@npm:4.0.0" + dependencies: + "@types/node": "npm:>=18.0.0" + checksum: 10c0/32c4b1f3b4a832a506b7661855d1da88eae307334563916b7513748171545a120abaaca5146a8beed1130b44c9e92f37511010b1205710baa778f5626cc2f7fa + languageName: node + linkType: hard + +"@slack/oauth@npm:^3.0.0": + version: 3.0.0 + resolution: "@slack/oauth@npm:3.0.0" + dependencies: + "@slack/logger": "npm:^4" + "@slack/web-api": "npm:^7" + "@types/jsonwebtoken": "npm:^9" + "@types/node": "npm:>=18" + jsonwebtoken: "npm:^9" + lodash.isstring: "npm:^4" + checksum: 10c0/902015b8cb7e23d32c2a2da3ba3a58533d270fb71e7fd97de3e72182d48a32d063c2cbb3121a44f163594eca2f7922fa4165266d8c9097b517f221f259c9cbcc + languageName: node + linkType: hard + +"@slack/types@npm:^2.9.0": + version: 2.12.0 + resolution: "@slack/types@npm:2.12.0" + checksum: 10c0/78bc3766049f0cea498f0cba2f3c3c5155995d98a64e6a4e429961aafc59f6285e4f26851228a8cef2cbd5380c7a3b3ae30e584c12c633a0879f414447499a6e + languageName: node + linkType: hard + +"@slack/web-api@npm:^7, @slack/web-api@npm:^7.3.1": + version: 7.3.1 + resolution: "@slack/web-api@npm:7.3.1" + dependencies: + "@slack/logger": "npm:^4.0.0" + "@slack/types": "npm:^2.9.0" + "@types/node": "npm:>=18.0.0" + "@types/retry": "npm:0.12.0" + axios: "npm:^1.6.5" + eventemitter3: "npm:^5.0.1" + form-data: "npm:^4.0.0" + is-electron: "npm:2.2.2" + is-stream: "npm:^2" + p-queue: "npm:^6" + p-retry: "npm:^4" + retry: "npm:^0.13.1" + checksum: 10c0/949960962ce0e81b829370727fe2f02031b20590c09c467feca835b39f459e2847331bcc12e99491732980d7bb8e06c4edfdb575a61903e9a33a10fc5123bab4 + languageName: node + linkType: hard + "@szmarczak/http-timer@npm:^4.0.5": version: 4.0.6 resolution: "@szmarczak/http-timer@npm:4.0.6" @@ -658,6 +681,15 @@ __metadata: languageName: node linkType: hard +"@types/jsonwebtoken@npm:^9": + version: 9.0.6 + resolution: "@types/jsonwebtoken@npm:9.0.6" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/9c29e3896e5fb6056e54d87514643e59e0cfb966ae25171a107776270195bba955f0373e98c8ed6450c145b18984f5df9cf0fcac360f382cec3c7c4d3510b202 + languageName: node + linkType: hard + "@types/keyv@npm:^3.1.4": version: 3.1.4 resolution: "@types/keyv@npm:3.1.4" @@ -685,6 +717,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:>=18, @types/node@npm:>=18.0.0, @types/node@npm:^20.14.12": + version: 20.14.12 + resolution: "@types/node@npm:20.14.12" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10c0/59bc5fa11fdd23fd517f859063118f54a1ab53d3399ef63c926f8902429d7453abc0db22ef4b0a6110026b6ab81b6472fee894e1d235c24b01a0b3e10cfae0bb + languageName: node + linkType: hard + "@types/node@npm:^20.14.11": version: 20.14.11 resolution: "@types/node@npm:20.14.11" @@ -703,6 +744,13 @@ __metadata: languageName: node linkType: hard +"@types/retry@npm:0.12.0": + version: 0.12.0 + resolution: "@types/retry@npm:0.12.0" + checksum: 10c0/7c5c9086369826f569b83a4683661557cab1361bac0897a1cefa1a915ff739acd10ca0d62b01071046fe3f5a3f7f2aec80785fe283b75602dc6726781ea3e328 + languageName: node + linkType: hard + "@types/semver@npm:^7.1.0": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" @@ -724,6 +772,13 @@ __metadata: languageName: node linkType: hard +"@types/url-search-params@npm:^1": + version: 1.1.2 + resolution: "@types/url-search-params@npm:1.1.2" + checksum: 10c0/3575548b8d94b7f4509fc1645d4c32d75c12a180ed86a67d3521f730fcdddba67de9e43d282ff22d00cddf2dbc1dbb91b3e3cda698fdf3acd697c5124ebecd3e + languageName: node + linkType: hard + "@yarnpkg/core@npm:^4.1.0": version: 4.1.1 resolution: "@yarnpkg/core@npm:4.1.1" @@ -958,6 +1013,24 @@ __metadata: languageName: node linkType: hard +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d + languageName: node + linkType: hard + +"axios@npm:^1.6.5": + version: 1.7.2 + resolution: "axios@npm:1.7.2" + dependencies: + follow-redirects: "npm:^1.15.6" + form-data: "npm:^4.0.0" + proxy-from-env: "npm:^1.1.0" + checksum: 10c0/cbd47ce380fe045313364e740bb03b936420b8b5558c7ea36a4563db1258c658f05e40feb5ddd41f6633fdd96d37ac2a76f884dad599c5b0224b4c451b3fa7ae + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -997,6 +1070,13 @@ __metadata: languageName: node linkType: hard +"buffer-equal-constant-time@npm:1.0.1": + version: 1.0.1 + resolution: "buffer-equal-constant-time@npm:1.0.1" + checksum: 10c0/fb2294e64d23c573d0dd1f1e7a466c3e978fe94a4e0f8183937912ca374619773bef8e2aceb854129d2efecbbc515bbd0cc78d2734a3e3031edb0888531bbc8e + languageName: node + linkType: hard + "cacache@npm:^18.0.0": version: 18.0.3 resolution: "cacache@npm:18.0.3" @@ -1154,6 +1234,15 @@ __metadata: languageName: node linkType: hard +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: "npm:~1.0.0" + checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 + languageName: node + linkType: hard + "comment-json@npm:^2.2.0": version: 2.4.2 resolution: "comment-json@npm:2.4.2" @@ -1263,6 +1352,13 @@ __metadata: languageName: node linkType: hard +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 + languageName: node + linkType: hard + "diff@npm:^4.0.1": version: 4.0.2 resolution: "diff@npm:4.0.2" @@ -1291,6 +1387,15 @@ __metadata: languageName: node linkType: hard +"ecdsa-sig-formatter@npm:1.0.11": + version: 1.0.11 + resolution: "ecdsa-sig-formatter@npm:1.0.11" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 10c0/ebfbf19d4b8be938f4dd4a83b8788385da353d63307ede301a9252f9f7f88672e76f2191618fd8edfc2f24679236064176fab0b78131b161ee73daa37125408c + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -1438,6 +1543,20 @@ __metadata: languageName: node linkType: hard +"eventemitter3@npm:^4.0.4": + version: 4.0.7 + resolution: "eventemitter3@npm:4.0.7" + checksum: 10c0/5f6d97cbcbac47be798e6355e3a7639a84ee1f7d9b199a07017f1d2f1e2fe236004d14fa5dfaeba661f94ea57805385e326236a6debbc7145c8877fbc0297c6b + languageName: node + linkType: hard + +"eventemitter3@npm:^5.0.1": + version: 5.0.1 + resolution: "eventemitter3@npm:5.0.1" + checksum: 10c0/4ba5c00c506e6c786b4d6262cfbce90ddc14c10d4667e5c83ae993c9de88aa856033994dd2b35b83e8dc1170e224e66a319fa80adc4c32adcd2379bbc75da814 + languageName: node + linkType: hard + "exit-hook@npm:^2.2.1": version: 2.2.1 resolution: "exit-hook@npm:2.2.1" @@ -1483,6 +1602,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.6": + version: 1.15.6 + resolution: "follow-redirects@npm:1.15.6" + peerDependenciesMeta: + debug: + optional: true + checksum: 10c0/9ff767f0d7be6aa6870c82ac79cf0368cd73e01bbc00e9eb1c2a16fbb198ec105e3c9b6628bb98e9f3ac66fe29a957b9645bcb9a490bb7aa0d35f908b6b85071 + languageName: node + linkType: hard + "foreground-child@npm:^3.1.0": version: 3.1.1 resolution: "foreground-child@npm:3.1.1" @@ -1493,6 +1622,17 @@ __metadata: languageName: node linkType: hard +"form-data@npm:^4.0.0": + version: 4.0.0 + resolution: "form-data@npm:4.0.0" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + mime-types: "npm:^2.1.12" + checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -1748,6 +1888,13 @@ __metadata: languageName: node linkType: hard +"is-electron@npm:2.2.2": + version: 2.2.2 + resolution: "is-electron@npm:2.2.2" + checksum: 10c0/327bb373f7be01b16cdff3998b5ddaa87d28f576092affaa7fe0659571b3306fdd458afbf0683a66841e7999af13f46ad0e1b51647b469526cd05a4dd736438a + languageName: node + linkType: hard + "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -1785,6 +1932,13 @@ __metadata: languageName: node linkType: hard +"is-stream@npm:^2": + version: 2.0.1 + resolution: "is-stream@npm:2.0.1" + checksum: 10c0/7c284241313fc6efc329b8d7f08e16c0efeb6baab1b4cd0ba579eb78e5af1aa5da11e68559896a2067cd6c526bd29241dda4eb1225e627d5aa1a89a76d4635a5 + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -1812,6 +1966,13 @@ __metadata: languageName: node linkType: hard +"jose@npm:^5.6.3": + version: 5.6.3 + resolution: "jose@npm:5.6.3" + checksum: 10c0/c33d8d37b86a17b1f720c667a1208248171b602375131828f645fff0d71a2fbe9b5e2a47c3fd9b7c3e41f3bf25761398150d1f158a2ee1b616ac90cf56f5e862 + languageName: node + linkType: hard + "js-yaml@npm:^3.10.0": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" @@ -1849,6 +2010,45 @@ __metadata: languageName: node linkType: hard +"jsonwebtoken@npm:^9, jsonwebtoken@npm:^9.0.2": + version: 9.0.2 + resolution: "jsonwebtoken@npm:9.0.2" + dependencies: + jws: "npm:^3.2.2" + lodash.includes: "npm:^4.3.0" + lodash.isboolean: "npm:^3.0.3" + lodash.isinteger: "npm:^4.0.4" + lodash.isnumber: "npm:^3.0.3" + lodash.isplainobject: "npm:^4.0.6" + lodash.isstring: "npm:^4.0.1" + lodash.once: "npm:^4.0.0" + ms: "npm:^2.1.1" + semver: "npm:^7.5.4" + checksum: 10c0/d287a29814895e866db2e5a0209ce730cbc158441a0e5a70d5e940eb0d28ab7498c6bf45029cc8b479639bca94056e9a7f254e2cdb92a2f5750c7f358657a131 + languageName: node + linkType: hard + +"jwa@npm:^1.4.1": + version: 1.4.1 + resolution: "jwa@npm:1.4.1" + dependencies: + buffer-equal-constant-time: "npm:1.0.1" + ecdsa-sig-formatter: "npm:1.0.11" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/5c533540bf38702e73cf14765805a94027c66a0aa8b16bc3e89d8d905e61a4ce2791e87e21be97d1293a5ee9d4f3e5e47737e671768265ca4f25706db551d5e9 + languageName: node + linkType: hard + +"jws@npm:^3.2.2": + version: 3.2.2 + resolution: "jws@npm:3.2.2" + dependencies: + jwa: "npm:^1.4.1" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/e770704533d92df358adad7d1261fdecad4d7b66fa153ba80d047e03ca0f1f73007ce5ed3fbc04d2eba09ba6e7e6e645f351e08e5ab51614df1b0aa4f384dfff + languageName: node + linkType: hard + "keyv@npm:^4.0.0": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -1858,6 +2058,55 @@ __metadata: languageName: node linkType: hard +"lodash.includes@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.includes@npm:4.3.0" + checksum: 10c0/7ca498b9b75bf602d04e48c0adb842dfc7d90f77bcb2a91a2b2be34a723ad24bc1c8b3683ec6b2552a90f216c723cdea530ddb11a3320e08fa38265703978f4b + languageName: node + linkType: hard + +"lodash.isboolean@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isboolean@npm:3.0.3" + checksum: 10c0/0aac604c1ef7e72f9a6b798e5b676606042401dd58e49f051df3cc1e3adb497b3d7695635a5cbec4ae5f66456b951fdabe7d6b387055f13267cde521f10ec7f7 + languageName: node + linkType: hard + +"lodash.isinteger@npm:^4.0.4": + version: 4.0.4 + resolution: "lodash.isinteger@npm:4.0.4" + checksum: 10c0/4c3e023a2373bf65bf366d3b8605b97ec830bca702a926939bcaa53f8e02789b6a176e7f166b082f9365bfec4121bfeb52e86e9040cb8d450e64c858583f61b7 + languageName: node + linkType: hard + +"lodash.isnumber@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isnumber@npm:3.0.3" + checksum: 10c0/2d01530513a1ee4f72dd79528444db4e6360588adcb0e2ff663db2b3f642d4bb3d687051ae1115751ca9082db4fdef675160071226ca6bbf5f0c123dbf0aa12d + languageName: node + linkType: hard + +"lodash.isplainobject@npm:^4.0.6": + version: 4.0.6 + resolution: "lodash.isplainobject@npm:4.0.6" + checksum: 10c0/afd70b5c450d1e09f32a737bed06ff85b873ecd3d3d3400458725283e3f2e0bb6bf48e67dbe7a309eb371a822b16a26cca4a63c8c52db3fc7dc9d5f9dd324cbb + languageName: node + linkType: hard + +"lodash.isstring@npm:^4, lodash.isstring@npm:^4.0.1": + version: 4.0.1 + resolution: "lodash.isstring@npm:4.0.1" + checksum: 10c0/09eaf980a283f9eef58ef95b30ec7fee61df4d6bf4aba3b5f096869cc58f24c9da17900febc8ffd67819b4e29de29793190e88dc96983db92d84c95fa85d1c92 + languageName: node + linkType: hard + +"lodash.once@npm:^4.0.0": + version: 4.1.1 + resolution: "lodash.once@npm:4.1.1" + checksum: 10c0/46a9a0a66c45dd812fcc016e46605d85ad599fe87d71a02f6736220554b52ffbe82e79a483ad40f52a8a95755b0d1077fba259da8bfb6694a7abbf4a48f1fc04 + languageName: node + linkType: hard + "lodash@npm:^4.17.15": version: 4.17.21 resolution: "lodash@npm:4.17.21" @@ -1932,6 +2181,22 @@ __metadata: languageName: node linkType: hard +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa + languageName: node + linkType: hard + +"mime-types@npm:^2.1.12": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: "npm:1.52.0" + checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 + languageName: node + linkType: hard + "mime@npm:^3.0.0": version: 3.0.0 resolution: "mime@npm:3.0.0" @@ -1977,28 +2242,6 @@ __metadata: languageName: node linkType: hard -"miniflare@npm:3.20240712.0": - version: 3.20240712.0 - resolution: "miniflare@npm:3.20240712.0" - dependencies: - "@cspotcode/source-map-support": "npm:0.8.1" - acorn: "npm:^8.8.0" - acorn-walk: "npm:^8.2.0" - capnp-ts: "npm:^0.7.0" - exit-hook: "npm:^2.2.1" - glob-to-regexp: "npm:^0.4.1" - stoppable: "npm:^1.1.0" - undici: "npm:^5.28.4" - workerd: "npm:1.20240712.0" - ws: "npm:^8.17.1" - youch: "npm:^3.2.2" - zod: "npm:^3.22.3" - bin: - miniflare: bootstrap.js - checksum: 10c0/b458813348da463f911794216b96ad5169f78663977e052922b4e786448a6d9c0a426cfee3526c1f58676bdaeb34b9944ac95a984dea736a9e709f059de94a67 - languageName: node - linkType: hard - "miniflare@npm:3.20240718.0": version: 3.20240718.0 resolution: "miniflare@npm:3.20240718.0" @@ -2130,6 +2373,13 @@ __metadata: languageName: node linkType: hard +"ms@npm:^2.1.1": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + languageName: node + linkType: hard + "mustache@npm:^4.2.0": version: 4.2.0 resolution: "mustache@npm:4.2.0" @@ -2253,6 +2503,13 @@ __metadata: languageName: node linkType: hard +"p-finally@npm:^1.0.0": + version: 1.0.0 + resolution: "p-finally@npm:1.0.0" + checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 + languageName: node + linkType: hard + "p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -2271,6 +2528,35 @@ __metadata: languageName: node linkType: hard +"p-queue@npm:^6": + version: 6.6.2 + resolution: "p-queue@npm:6.6.2" + dependencies: + eventemitter3: "npm:^4.0.4" + p-timeout: "npm:^3.2.0" + checksum: 10c0/5739ecf5806bbeadf8e463793d5e3004d08bb3f6177bd1a44a005da8fd81bb90f80e4633e1fb6f1dfd35ee663a5c0229abe26aebb36f547ad5a858347c7b0d3e + languageName: node + linkType: hard + +"p-retry@npm:^4": + version: 4.6.2 + resolution: "p-retry@npm:4.6.2" + dependencies: + "@types/retry": "npm:0.12.0" + retry: "npm:^0.13.1" + checksum: 10c0/d58512f120f1590cfedb4c2e0c42cb3fa66f3cea8a4646632fcb834c56055bb7a6f138aa57b20cc236fb207c9d694e362e0b5c2b14d9b062f67e8925580c73b0 + languageName: node + linkType: hard + +"p-timeout@npm:^3.2.0": + version: 3.2.0 + resolution: "p-timeout@npm:3.2.0" + dependencies: + p-finally: "npm:^1.0.0" + checksum: 10c0/524b393711a6ba8e1d48137c5924749f29c93d70b671e6db761afa784726572ca06149c715632da8f70c090073afb2af1c05730303f915604fd38ee207b70a61 + languageName: node + linkType: hard + "p-try@npm:^2.0.0": version: 2.2.0 resolution: "p-try@npm:2.2.0" @@ -2374,6 +2660,13 @@ __metadata: languageName: node linkType: hard +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b + languageName: node + linkType: hard + "pump@npm:^3.0.0": version: 3.0.0 resolution: "pump@npm:3.0.0" @@ -2470,6 +2763,13 @@ __metadata: languageName: node linkType: hard +"retry@npm:^0.13.1": + version: 0.13.1 + resolution: "retry@npm:0.13.1" + checksum: 10c0/9ae822ee19db2163497e074ea919780b1efa00431d197c7afdb950e42bf109196774b92a49fc9821f0b8b328a98eea6017410bfc5e8a0fc19c85c6d11adb3772 + languageName: node + linkType: hard + "reusify@npm:^1.0.4": version: 1.0.4 resolution: "reusify@npm:1.0.4" @@ -2515,6 +2815,13 @@ __metadata: languageName: node linkType: hard +"safe-buffer@npm:^5.0.1": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + languageName: node + linkType: hard + "safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -2541,6 +2848,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.5.4": + version: 7.6.3 + resolution: "semver@npm:7.6.3" + bin: + semver: bin/semver.js + checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -2825,6 +3141,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^5.5.4": + version: 5.5.4 + resolution: "typescript@npm:5.5.4" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/422be60f89e661eab29ac488c974b6cc0a660fb2228003b297c3d10c32c90f3bcffc1009b43876a082515a3c376b1eefcce823d6e78982e6878408b9a923199c + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A^5.4.5#optional!builtin": version: 5.4.5 resolution: "typescript@patch:typescript@npm%3A5.4.5#optional!builtin::version=5.4.5&hash=5adc0c" @@ -2845,6 +3171,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A^5.5.4#optional!builtin": + version: 5.5.4 + resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin::version=5.5.4&hash=379a07" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/73409d7b9196a5a1217b3aaad929bf76294d3ce7d6e9766dd880ece296ee91cf7d7db6b16c6c6c630ee5096eccde726c0ef17c7dfa52b01a243e57ae1f09ef07 + languageName: node + linkType: hard + "ufo@npm:^1.5.3": version: 1.5.3 resolution: "ufo@npm:1.5.3" @@ -2900,6 +3236,13 @@ __metadata: languageName: node linkType: hard +"url-search-params@npm:^1.1.0": + version: 1.1.0 + resolution: "url-search-params@npm:1.1.0" + checksum: 10c0/3a823942d715b34b8cc05ae9b930f1c1774d00ef7967e2386287e8ca480beb7224b90d223560675690affb8ce339680d390c345ab2ebb4b0572fee61c01c79ed + languageName: node + linkType: hard + "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" @@ -2972,32 +3315,6 @@ __metadata: languageName: node linkType: hard -"workerd@npm:1.20240712.0": - version: 1.20240712.0 - resolution: "workerd@npm:1.20240712.0" - dependencies: - "@cloudflare/workerd-darwin-64": "npm:1.20240712.0" - "@cloudflare/workerd-darwin-arm64": "npm:1.20240712.0" - "@cloudflare/workerd-linux-64": "npm:1.20240712.0" - "@cloudflare/workerd-linux-arm64": "npm:1.20240712.0" - "@cloudflare/workerd-windows-64": "npm:1.20240712.0" - dependenciesMeta: - "@cloudflare/workerd-darwin-64": - optional: true - "@cloudflare/workerd-darwin-arm64": - optional: true - "@cloudflare/workerd-linux-64": - optional: true - "@cloudflare/workerd-linux-arm64": - optional: true - "@cloudflare/workerd-windows-64": - optional: true - bin: - workerd: bin/workerd - checksum: 10c0/01df3d2ef164125a96eb538e9897f6e6d9fbadbf773ced10fcb56758dee2c72b4fdeebbce516e0cbb51d87b9814e97a743bf495be87a21dc4b2e26f640711adb - languageName: node - linkType: hard - "workerd@npm:1.20240718.0": version: 1.20240718.0 resolution: "workerd@npm:1.20240718.0" @@ -3059,9 +3376,9 @@ __metadata: languageName: node linkType: hard -"wrangler@npm:^3.65.0": - version: 3.65.0 - resolution: "wrangler@npm:3.65.0" +"wrangler@npm:^3.65.1": + version: 3.65.1 + resolution: "wrangler@npm:3.65.1" dependencies: "@cloudflare/kv-asset-handler": "npm:0.3.4" "@esbuild-plugins/node-globals-polyfill": "npm:^0.2.3" @@ -3071,7 +3388,7 @@ __metadata: date-fns: "npm:^3.6.0" esbuild: "npm:0.17.19" fsevents: "npm:~2.3.2" - miniflare: "npm:3.20240712.0" + miniflare: "npm:3.20240718.0" nanoid: "npm:^3.3.3" path-to-regexp: "npm:^6.2.0" resolve: "npm:^1.22.8" @@ -3081,7 +3398,7 @@ __metadata: unenv: "npm:unenv-nightly@1.10.0-1717606461.a117952" xxhash-wasm: "npm:^1.0.1" peerDependencies: - "@cloudflare/workers-types": ^4.20240712.0 + "@cloudflare/workers-types": ^4.20240718.0 dependenciesMeta: fsevents: optional: true @@ -3091,13 +3408,13 @@ __metadata: bin: wrangler: bin/wrangler.js wrangler2: bin/wrangler.js - checksum: 10c0/f7e73f107a0cb2b27e17035b4d3b78ac86d953e90fde196d0149799d550c0f5714918beae53ef2506f142bba47eca801b14c26ea16bfa4289ba0b6d31f6d239d + checksum: 10c0/4091cead4cc461e3aa4398a685d39584db22a3127d6cf38a9a5313f1c54b9f243875c619ee377623d1a6fb2a5099d3546be4dc9c13c6af58f2569c89507a609c languageName: node linkType: hard -"wrangler@npm:^3.65.1": - version: 3.65.1 - resolution: "wrangler@npm:3.65.1" +"wrangler@npm:^3.66.0": + version: 3.66.0 + resolution: "wrangler@npm:3.66.0" dependencies: "@cloudflare/kv-asset-handler": "npm:0.3.4" "@esbuild-plugins/node-globals-polyfill": "npm:^0.2.3" @@ -3115,6 +3432,7 @@ __metadata: selfsigned: "npm:^2.0.1" source-map: "npm:^0.6.1" unenv: "npm:unenv-nightly@1.10.0-1717606461.a117952" + workerd: "npm:1.20240718.0" xxhash-wasm: "npm:^1.0.1" peerDependencies: "@cloudflare/workers-types": ^4.20240718.0 @@ -3127,7 +3445,7 @@ __metadata: bin: wrangler: bin/wrangler.js wrangler2: bin/wrangler.js - checksum: 10c0/4091cead4cc461e3aa4398a685d39584db22a3127d6cf38a9a5313f1c54b9f243875c619ee377623d1a6fb2a5099d3546be4dc9c13c6af58f2569c89507a609c + checksum: 10c0/5c672b157ebc1f6ff1c64bd540e8008b0794bf5c6406b4b8613b0d3a707d91ef07da66446d3256485333884e307d407d0486af3ad9d862d32df3b445641e51a9 languageName: node linkType: hard