From ab24432fa694f0f7ea86920440d9b2c4c9598bf7 Mon Sep 17 00:00:00 2001 From: KazumaOhashi Date: Fri, 31 Jan 2025 17:55:02 +0900 Subject: [PATCH] WIP --- src/app/commands/create.ts | 5 ++- src/app/commands/delete.ts | 4 +- src/app/commands/list.ts | 4 +- src/app/commands/update.ts | 4 +- src/channel/renewAccessToken.ts | 4 +- src/config/commands/index.ts | 9 ++++ src/config/commands/set.ts | 26 ++++++++++++ src/config/stores/common.ts | 17 ++++++++ src/config/stores/index.ts | 74 +++++++++++++++++++++++++++++++++ src/serve/serveAction.ts | 7 +++- src/setup.test.ts | 1 + src/setup.ts | 2 + 12 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 src/config/commands/index.ts create mode 100644 src/config/commands/set.ts create mode 100644 src/config/stores/common.ts create mode 100644 src/config/stores/index.ts diff --git a/src/app/commands/create.ts b/src/app/commands/create.ts index 9e240a0..20ea45f 100644 --- a/src/app/commands/create.ts +++ b/src/app/commands/create.ts @@ -1,6 +1,7 @@ import { createCommand } from "commander"; import { LiffApiClient } from "../../api/liff.js"; import { resolveChannel } from "../../channel/resolveChannel.js"; +import { getLineBaseUrl } from "../../config/stores/common.js"; const createAction = async (options: { channelId?: string; @@ -14,10 +15,10 @@ const createAction = async (options: { Please provide a valid channel ID or set the current channel first. `); } - + const lineBaseUrl = getLineBaseUrl(); const client = new LiffApiClient({ token: accessToken, - baseUrl: "https://api.line.me", + baseUrl: lineBaseUrl, }); const { liffId } = await client.addApp({ view: { diff --git a/src/app/commands/delete.ts b/src/app/commands/delete.ts index ee97eb0..e0d286e 100644 --- a/src/app/commands/delete.ts +++ b/src/app/commands/delete.ts @@ -2,6 +2,7 @@ import { Command } from "commander"; import { resolveChannel } from "../../channel/resolveChannel.js"; import { LiffApiClient } from "../../api/liff.js"; import inquirer from "inquirer"; +import { getLineBaseUrl } from "../../config/stores/common.js"; const deleteAction = async (options: { channelId?: string; @@ -24,9 +25,10 @@ const deleteAction = async (options: { ]); if (!confirmDelete) return; + const lineBaseUrl = getLineBaseUrl(); const client = new LiffApiClient({ token: accessToken, - baseUrl: "https://api.line.me", + baseUrl: lineBaseUrl, }); console.info(`Deleting LIFF app...`); await client.deleteApp(options.liffId); diff --git a/src/app/commands/list.ts b/src/app/commands/list.ts index 8240965..383bf9a 100644 --- a/src/app/commands/list.ts +++ b/src/app/commands/list.ts @@ -1,6 +1,7 @@ import { Command } from "commander"; import { LiffApiClient } from "../../api/liff.js"; import { resolveChannel } from "../../channel/resolveChannel.js"; +import { getLineBaseUrl } from "../../config/stores/common.js"; const listAction = async (options: { channelId?: string }) => { const accessToken = (await resolveChannel(options?.channelId))?.accessToken; @@ -10,9 +11,10 @@ const listAction = async (options: { channelId?: string }) => { `); } + const lineBaseUrl = getLineBaseUrl(); const client = new LiffApiClient({ token: accessToken, - baseUrl: "https://api.line.me", + baseUrl: lineBaseUrl, }); const { apps } = await client.fetchApps(); diff --git a/src/app/commands/update.ts b/src/app/commands/update.ts index 320f061..a5e8c61 100644 --- a/src/app/commands/update.ts +++ b/src/app/commands/update.ts @@ -1,6 +1,7 @@ import { createCommand } from "commander"; import { LiffApiClient } from "../../api/liff.js"; import { resolveChannel } from "../../channel/resolveChannel.js"; +import { getLineBaseUrl } from "../../config/stores/common.js"; const updateAction = async (options: { liffId: string; @@ -16,9 +17,10 @@ const updateAction = async (options: { `); } + const lineBaseUrl = getLineBaseUrl(); const client = new LiffApiClient({ token: accessToken, - baseUrl: "https://api.line.me", + baseUrl: lineBaseUrl, }); await client.updateApp(options.liffId, { view: { diff --git a/src/channel/renewAccessToken.ts b/src/channel/renewAccessToken.ts index b047cf6..2f913fb 100644 --- a/src/channel/renewAccessToken.ts +++ b/src/channel/renewAccessToken.ts @@ -1,4 +1,5 @@ import { AuthApiClient } from "../api/auth.js"; +import { getLineBaseUrl } from "../config/stores/common.js"; import { ChannelInfo, upsertChannel } from "./stores/channels.js"; export const renewAccessToken = async ( @@ -6,8 +7,9 @@ export const renewAccessToken = async ( channelSecret: string, issuedAt: number, ): Promise => { + const lineBaseUrl = getLineBaseUrl(); const client = new AuthApiClient({ - baseUrl: "https://api.line.me", + baseUrl: lineBaseUrl, }); const res = await client.fetchStatelessChannelAccessToken({ channelId: channelId, diff --git a/src/config/commands/index.ts b/src/config/commands/index.ts new file mode 100644 index 0000000..5b9f6d7 --- /dev/null +++ b/src/config/commands/index.ts @@ -0,0 +1,9 @@ +import { Command } from "commander"; +import { makeSetCommand } from "./set.js"; + +export const installConfigCommands = (program: Command) => { + const config = program.command("config"); + config.description("Configure common settings"); + + config.addCommand(makeSetCommand()); +}; diff --git a/src/config/commands/set.ts b/src/config/commands/set.ts new file mode 100644 index 0000000..673fa43 --- /dev/null +++ b/src/config/commands/set.ts @@ -0,0 +1,26 @@ +import { Command } from "commander"; +import { setLiffBaseUrl, setLineBaseUrl } from "../stores/common.js"; + +const setAction = async (key: string, value: string) => { + switch (key) { + case "baseUrl.line": + setLineBaseUrl(value); + break; + case "baseUrl.liff": + setLiffBaseUrl(value); + break; + default: + throw new Error(`Unknown key: ${key}`); + } +}; + +export const makeSetCommand = () => { + const set = new Command("set"); + set + .description("Set configuration") + .argument("", "The key to set") + .argument("", "The value to set") + .action(setAction); + + return set; +}; diff --git a/src/config/stores/common.ts b/src/config/stores/common.ts new file mode 100644 index 0000000..ce576f4 --- /dev/null +++ b/src/config/stores/common.ts @@ -0,0 +1,17 @@ +import { store } from "./index.js"; + +export const getLineBaseUrl = (): string => { + return store.get("common.baseUrl.line") ?? "https://api.line.me"; +}; + +export const setLineBaseUrl = (url: string) => { + store.set("common.baseUrl.line", url); +}; + +export const getLiffBaseUrl = (): string => { + return store.get("common.baseUrl.liff") ?? "https://liff.line.me"; +}; + +export const setLiffBaseUrl = (url: string) => { + store.set("common.baseUrl.liff", url); +}; diff --git a/src/config/stores/index.ts b/src/config/stores/index.ts new file mode 100644 index 0000000..ee0b5ab --- /dev/null +++ b/src/config/stores/index.ts @@ -0,0 +1,74 @@ +import Conf from "conf"; +import { promises as fs } from "fs"; + +const packageJson = JSON.parse( + await fs.readFile(new URL("../../../package.json", import.meta.url), "utf8"), +); + +export interface RootConfig { + currentChannelId?: string; + channels?: { + [channelId: string]: { + secret: string; + accessToken: string; + expiresIn: number; + issuedAt: number; + }; + }; + common?: { + baseUrl?: { + liff: string; + line: string; + }; + }; +} + +export const store = new Conf({ + projectName: packageJson.name, + projectVersion: packageJson.version, + schema: { + currentChannelId: { + type: "string", + }, + channels: { + type: "object", + properties: { + secret: { + type: "string", + description: "The secret for the channel", + }, + accessToken: { + type: "string", + description: "The access token for the channel", + }, + expiresIn: { + type: "number", + description: "The number of seconds the access token is valid for", + }, + issuedAt: { + type: "number", + description: + "The milliseconds timestamp when the access token was issued", + }, + }, + }, + common: { + type: "object", + properties: { + baseUrl: { + type: "object", + properties: { + liff: { + type: "string", + description: "The base URL for LIFF Application", + }, + line: { + type: "string", + description: "The base URL for LINE API", + }, + }, + }, + }, + }, + }, +}); diff --git a/src/serve/serveAction.ts b/src/serve/serveAction.ts index 46e7ebf..80ab529 100644 --- a/src/serve/serveAction.ts +++ b/src/serve/serveAction.ts @@ -5,6 +5,7 @@ import { getCurrentChannelId } from "../channel/stores/channels.js"; import { LocalProxy } from "../proxy/local-proxy.js"; import resolveEndpointUrl from "./resolveEndpointUrl.js"; import pc from "picocolors"; +import { getLiffBaseUrl, getLineBaseUrl } from "../config/stores/common.js"; export const serveAction = async ( options: { @@ -48,12 +49,14 @@ export const serveAction = async ( } const httpsUrl = await localProxy.connect(endpointUrl); - const liffUrl = new URL("https://liff.line.me/"); + const liffBaseUrl = getLiffBaseUrl(); + const liffUrl = new URL(liffBaseUrl); liffUrl.pathname = options.liffId; + const lineBaseUrl = getLineBaseUrl(); const client = new LiffApiClient({ token: accessToken, - baseUrl: "https://api.line.me", + baseUrl: lineBaseUrl, }); await client.updateApp(options.liffId, { view: { url: httpsUrl.toString() }, diff --git a/src/setup.test.ts b/src/setup.test.ts index f532bed..5737a68 100644 --- a/src/setup.test.ts +++ b/src/setup.test.ts @@ -26,6 +26,7 @@ Commands: channel Manage LIFF channels app Manage LIFF apps serve [options] Manage HTTPS dev server + config Configure common settings help [command] display help for command `); }); diff --git a/src/setup.ts b/src/setup.ts index 5387567..3b4d535 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -2,11 +2,13 @@ import { Command } from "commander"; import { installChannelCommands } from "./channel/commands/index.js"; import { installAppCommands } from "./app/commands/index.js"; import { serveCommands } from "./serve/index.js"; +import { installConfigCommands } from "./config/commands/index.js"; export const setupCLI = (program: Command) => { installChannelCommands(program); installAppCommands(program); serveCommands(program); + installConfigCommands(program); // TODO .version? return { run: (argv = process.argv) => {