rozsireni
This commit is contained in:
+683
@@ -35,6 +35,14 @@ type ServiceAccountTokenBody = {
|
||||
privateKey?: string;
|
||||
};
|
||||
|
||||
type GoogleRouteOptions = {
|
||||
baseUrl: string;
|
||||
path: string;
|
||||
method?: string;
|
||||
query?: Record<string, string | number | boolean | null | undefined>;
|
||||
body?: JsonValue;
|
||||
};
|
||||
|
||||
const app = express();
|
||||
const port = Number(process.env.PORT || 3000);
|
||||
const rootPath = normalizeRootPath(process.env.ROOT_PATH || "");
|
||||
@@ -261,6 +269,435 @@ app.get("/google/oauth/tokeninfo", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/google/calendar/calendars", async (req, res) => {
|
||||
await callGoogle(req, res, { baseUrl: "https://www.googleapis.com", path: "/calendar/v3/users/me/calendarList" });
|
||||
});
|
||||
|
||||
app.post("/google/calendar/calendars", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: "/calendar/v3/calendars",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/calendar/calendars/:calendarId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.patch("/google/calendar/calendars/:calendarId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}`,
|
||||
method: "PATCH",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.delete("/google/calendar/calendars/:calendarId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}`,
|
||||
method: "DELETE"
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/calendar/calendars/:calendarId/events", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}/events`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/calendar/calendars/:calendarId/events", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}/events`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/calendar/calendars/:calendarId/events/:eventId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}/events/${encodePathParam(req.params.eventId)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.patch("/google/calendar/calendars/:calendarId/events/:eventId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}/events/${encodePathParam(req.params.eventId)}`,
|
||||
method: "PATCH",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.delete("/google/calendar/calendars/:calendarId/events/:eventId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}/events/${encodePathParam(req.params.eventId)}`,
|
||||
method: "DELETE"
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/calendar/calendars/:calendarId/events/:eventId/move", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/calendar/v3/calendars/${encodePathParam(req.params.calendarId)}/events/${encodePathParam(req.params.eventId)}/move`,
|
||||
method: "POST"
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/sheets/spreadsheets", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://sheets.googleapis.com",
|
||||
path: "/v4/spreadsheets",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/sheets/spreadsheets/:spreadsheetId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://sheets.googleapis.com",
|
||||
path: `/v4/spreadsheets/${encodePathParam(req.params.spreadsheetId)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/sheets/spreadsheets/:spreadsheetId/batch-update", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://sheets.googleapis.com",
|
||||
path: `/v4/spreadsheets/${encodePathParam(req.params.spreadsheetId)}:batchUpdate`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/sheets/spreadsheets/:spreadsheetId/values", async (req, res) => {
|
||||
const range = requireQueryString(req, res, "range");
|
||||
if (!range) return;
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://sheets.googleapis.com",
|
||||
path: `/v4/spreadsheets/${encodePathParam(req.params.spreadsheetId)}/values/${encodePathParam(range)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.put("/google/sheets/spreadsheets/:spreadsheetId/values", async (req, res) => {
|
||||
const range = requireQueryString(req, res, "range");
|
||||
if (!range) return;
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://sheets.googleapis.com",
|
||||
path: `/v4/spreadsheets/${encodePathParam(req.params.spreadsheetId)}/values/${encodePathParam(range)}`,
|
||||
method: "PUT",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/sheets/spreadsheets/:spreadsheetId/values/append", async (req, res) => {
|
||||
const range = requireQueryString(req, res, "range");
|
||||
if (!range) return;
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://sheets.googleapis.com",
|
||||
path: `/v4/spreadsheets/${encodePathParam(req.params.spreadsheetId)}/values/${encodePathParam(range)}:append`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/sheets/spreadsheets/:spreadsheetId/values/batch-update", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://sheets.googleapis.com",
|
||||
path: `/v4/spreadsheets/${encodePathParam(req.params.spreadsheetId)}/values:batchUpdate`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/sheets/spreadsheets/:spreadsheetId/values/batch-clear", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://sheets.googleapis.com",
|
||||
path: `/v4/spreadsheets/${encodePathParam(req.params.spreadsheetId)}/values:batchClear`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/drive/files", async (req, res) => {
|
||||
await callGoogle(req, res, { baseUrl: "https://www.googleapis.com", path: "/drive/v3/files" });
|
||||
});
|
||||
|
||||
app.post("/google/drive/files", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: "/drive/v3/files",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/drive/files/:fileId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/drive/v3/files/${encodePathParam(req.params.fileId)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.patch("/google/drive/files/:fileId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/drive/v3/files/${encodePathParam(req.params.fileId)}`,
|
||||
method: "PATCH",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.delete("/google/drive/files/:fileId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/drive/v3/files/${encodePathParam(req.params.fileId)}`,
|
||||
method: "DELETE"
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/drive/files/:fileId/export", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/drive/v3/files/${encodePathParam(req.params.fileId)}/export`
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/drive/files/:fileId/permissions", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/drive/v3/files/${encodePathParam(req.params.fileId)}/permissions`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/drive/files/:fileId/permissions", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/drive/v3/files/${encodePathParam(req.params.fileId)}/permissions`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.delete("/google/drive/files/:fileId/permissions/:permissionId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://www.googleapis.com",
|
||||
path: `/drive/v3/files/${encodePathParam(req.params.fileId)}/permissions/${encodePathParam(req.params.permissionId)}`,
|
||||
method: "DELETE"
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/gmail/profile", async (req, res) => {
|
||||
await callGoogle(req, res, { baseUrl: "https://gmail.googleapis.com", path: "/gmail/v1/users/me/profile" });
|
||||
});
|
||||
|
||||
app.get("/google/gmail/messages", async (req, res) => {
|
||||
await callGoogle(req, res, { baseUrl: "https://gmail.googleapis.com", path: "/gmail/v1/users/me/messages" });
|
||||
});
|
||||
|
||||
app.get("/google/gmail/messages/:messageId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://gmail.googleapis.com",
|
||||
path: `/gmail/v1/users/me/messages/${encodePathParam(req.params.messageId)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/gmail/messages/send", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://gmail.googleapis.com",
|
||||
path: "/gmail/v1/users/me/messages/send",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/gmail/labels", async (req, res) => {
|
||||
await callGoogle(req, res, { baseUrl: "https://gmail.googleapis.com", path: "/gmail/v1/users/me/labels" });
|
||||
});
|
||||
|
||||
app.post("/google/gmail/labels", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://gmail.googleapis.com",
|
||||
path: "/gmail/v1/users/me/labels",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/docs/documents", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://docs.googleapis.com",
|
||||
path: "/v1/documents",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/docs/documents/:documentId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://docs.googleapis.com",
|
||||
path: `/v1/documents/${encodePathParam(req.params.documentId)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/docs/documents/:documentId/batch-update", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://docs.googleapis.com",
|
||||
path: `/v1/documents/${encodePathParam(req.params.documentId)}:batchUpdate`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/slides/presentations", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://slides.googleapis.com",
|
||||
path: "/v1/presentations",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/slides/presentations/:presentationId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://slides.googleapis.com",
|
||||
path: `/v1/presentations/${encodePathParam(req.params.presentationId)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/slides/presentations/:presentationId/batch-update", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://slides.googleapis.com",
|
||||
path: `/v1/presentations/${encodePathParam(req.params.presentationId)}:batchUpdate`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/forms/forms/:formId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://forms.googleapis.com",
|
||||
path: `/v1/forms/${encodePathParam(req.params.formId)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/forms/forms", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://forms.googleapis.com",
|
||||
path: "/v1/forms",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/forms/forms/:formId/batch-update", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://forms.googleapis.com",
|
||||
path: `/v1/forms/${encodePathParam(req.params.formId)}:batchUpdate`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/forms/forms/:formId/responses", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://forms.googleapis.com",
|
||||
path: `/v1/forms/${encodePathParam(req.params.formId)}/responses`
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/people/connections", async (req, res) => {
|
||||
await callGoogle(req, res, { baseUrl: "https://people.googleapis.com", path: "/v1/people/me/connections" });
|
||||
});
|
||||
|
||||
app.get("/google/people/:resourceName", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://people.googleapis.com",
|
||||
path: `/v1/people/${encodePathParam(req.params.resourceName)}`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/people/contacts", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://people.googleapis.com",
|
||||
path: "/v1/people:createContact",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.patch("/google/people/:resourceName", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://people.googleapis.com",
|
||||
path: `/v1/people/${encodePathParam(req.params.resourceName)}:updateContact`,
|
||||
method: "PATCH",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.delete("/google/people/:resourceName", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://people.googleapis.com",
|
||||
path: `/v1/people/${encodePathParam(req.params.resourceName)}:deleteContact`,
|
||||
method: "DELETE"
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/tasks/lists", async (req, res) => {
|
||||
await callGoogle(req, res, { baseUrl: "https://tasks.googleapis.com", path: "/tasks/v1/users/@me/lists" });
|
||||
});
|
||||
|
||||
app.post("/google/tasks/lists", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://tasks.googleapis.com",
|
||||
path: "/tasks/v1/users/@me/lists",
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/google/tasks/lists/:tasklistId/tasks", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://tasks.googleapis.com",
|
||||
path: `/tasks/v1/lists/${encodePathParam(req.params.tasklistId)}/tasks`
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/tasks/lists/:tasklistId/tasks", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://tasks.googleapis.com",
|
||||
path: `/tasks/v1/lists/${encodePathParam(req.params.tasklistId)}/tasks`,
|
||||
method: "POST",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.patch("/google/tasks/lists/:tasklistId/tasks/:taskId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://tasks.googleapis.com",
|
||||
path: `/tasks/v1/lists/${encodePathParam(req.params.tasklistId)}/tasks/${encodePathParam(req.params.taskId)}`,
|
||||
method: "PATCH",
|
||||
body: req.body as JsonValue
|
||||
});
|
||||
});
|
||||
|
||||
app.delete("/google/tasks/lists/:tasklistId/tasks/:taskId", async (req, res) => {
|
||||
await callGoogle(req, res, {
|
||||
baseUrl: "https://tasks.googleapis.com",
|
||||
path: `/tasks/v1/lists/${encodePathParam(req.params.tasklistId)}/tasks/${encodePathParam(req.params.taskId)}`,
|
||||
method: "DELETE"
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/google/request", async (req, res) => {
|
||||
try {
|
||||
const requestBody = req.body as GoogleRequestBody;
|
||||
@@ -305,6 +742,73 @@ function withRootPath(path: string): string {
|
||||
return rootPath + path;
|
||||
}
|
||||
|
||||
async function callGoogle(req: Request, res: Response, options: GoogleRouteOptions): Promise<void> {
|
||||
try {
|
||||
const requestBody: GoogleRequestBody = {
|
||||
baseUrl: options.baseUrl,
|
||||
path: options.path,
|
||||
method: options.method || req.method,
|
||||
query: { ...queryToRecord(req.query), ...(options.query || {}) },
|
||||
body: options.body,
|
||||
accessToken: readBodyString(req.body, "accessToken"),
|
||||
accessTokenEnv: readBodyString(req.body, "accessTokenEnv"),
|
||||
apiKey: readBodyString(req.body, "apiKey"),
|
||||
apiKeyEnv: readBodyString(req.body, "apiKeyEnv")
|
||||
};
|
||||
|
||||
const targetUrl = buildGoogleUrl(requestBody);
|
||||
const headers = buildGoogleHeaders(req, requestBody);
|
||||
const method = (requestBody.method || "GET").toUpperCase();
|
||||
const init: RequestInit = { method, headers };
|
||||
|
||||
if (!["GET", "HEAD"].includes(method) && options.body !== undefined) {
|
||||
init.body = JSON.stringify(options.body);
|
||||
}
|
||||
|
||||
const response = await fetch(targetUrl, init);
|
||||
await relayResponse(res, response);
|
||||
} catch (error) {
|
||||
sendError(res, error);
|
||||
}
|
||||
}
|
||||
|
||||
function queryToRecord(query: Request["query"]): Record<string, string | number | boolean | null | undefined> {
|
||||
const result: Record<string, string | number | boolean | null | undefined> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (typeof value === "string") {
|
||||
result[key] = value;
|
||||
} else if (Array.isArray(value)) {
|
||||
result[key] = value.map((item) => String(item)).join(",");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function readBodyString(body: unknown, key: string): string | undefined {
|
||||
if (!body || typeof body !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const value = (body as Record<string, unknown>)[key];
|
||||
return typeof value === "string" ? value : undefined;
|
||||
}
|
||||
|
||||
function requireQueryString(req: Request, res: Response, key: string): string | undefined {
|
||||
const value = req.query[key];
|
||||
if (typeof value === "string" && value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
badRequest(res, `Missing required query parameter: ${key}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function encodePathParam(value: string): string {
|
||||
return encodeURIComponent(value);
|
||||
}
|
||||
|
||||
function buildGoogleUrl(body: GoogleRequestBody): string {
|
||||
const rawUrl = body.url || joinBaseAndPath(body.baseUrl || "https://www.googleapis.com", body.path || "");
|
||||
const url = new URL(rawUrl);
|
||||
@@ -486,6 +990,15 @@ function buildOpenApiDocument(): Record<string, unknown> {
|
||||
{ name: "System" },
|
||||
{ name: "Google Discovery" },
|
||||
{ name: "Google OAuth" },
|
||||
{ name: "Google Calendar" },
|
||||
{ name: "Google Sheets" },
|
||||
{ name: "Google Drive" },
|
||||
{ name: "Gmail" },
|
||||
{ name: "Google Docs" },
|
||||
{ name: "Google Slides" },
|
||||
{ name: "Google Forms" },
|
||||
{ name: "Google People" },
|
||||
{ name: "Google Tasks" },
|
||||
{ name: "Google API" }
|
||||
],
|
||||
paths: {
|
||||
@@ -553,6 +1066,7 @@ function buildOpenApiDocument(): Record<string, unknown> {
|
||||
responses: { "200": { description: "Token info" }, "400": { description: "Invalid request" } }
|
||||
}
|
||||
},
|
||||
...buildGoogleServiceOpenApiPaths(),
|
||||
"/google/request": {
|
||||
post: {
|
||||
tags: ["Google API"],
|
||||
@@ -591,3 +1105,172 @@ function jsonRequestBody(example: Record<string, unknown>): Record<string, unkno
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function buildGoogleServiceOpenApiPaths(): Record<string, unknown> {
|
||||
return {
|
||||
"/google/calendar/calendars": {
|
||||
get: googleOperation("Google Calendar", "List calendars"),
|
||||
post: googleOperation("Google Calendar", "Create calendar", { summary: "Team calendar" })
|
||||
},
|
||||
"/google/calendar/calendars/{calendarId}": {
|
||||
get: googleOperation("Google Calendar", "Get calendar", undefined, ["calendarId"]),
|
||||
patch: googleOperation("Google Calendar", "Update calendar", { summary: "Updated calendar" }, ["calendarId"]),
|
||||
delete: googleOperation("Google Calendar", "Delete calendar", undefined, ["calendarId"])
|
||||
},
|
||||
"/google/calendar/calendars/{calendarId}/events": {
|
||||
get: googleOperation("Google Calendar", "List events", undefined, ["calendarId"]),
|
||||
post: googleOperation("Google Calendar", "Create event", { summary: "Meeting", start: {}, end: {} }, ["calendarId"])
|
||||
},
|
||||
"/google/calendar/calendars/{calendarId}/events/{eventId}": {
|
||||
get: googleOperation("Google Calendar", "Get event", undefined, ["calendarId", "eventId"]),
|
||||
patch: googleOperation("Google Calendar", "Update event", { summary: "Updated meeting" }, ["calendarId", "eventId"]),
|
||||
delete: googleOperation("Google Calendar", "Delete event", undefined, ["calendarId", "eventId"])
|
||||
},
|
||||
"/google/calendar/calendars/{calendarId}/events/{eventId}/move": {
|
||||
post: googleOperation("Google Calendar", "Move event to another calendar", undefined, ["calendarId", "eventId"])
|
||||
},
|
||||
"/google/sheets/spreadsheets": {
|
||||
post: googleOperation("Google Sheets", "Create spreadsheet", { properties: { title: "New spreadsheet" } })
|
||||
},
|
||||
"/google/sheets/spreadsheets/{spreadsheetId}": {
|
||||
get: googleOperation("Google Sheets", "Get spreadsheet", undefined, ["spreadsheetId"])
|
||||
},
|
||||
"/google/sheets/spreadsheets/{spreadsheetId}/batch-update": {
|
||||
post: googleOperation("Google Sheets", "Batch update spreadsheet", { requests: [] }, ["spreadsheetId"])
|
||||
},
|
||||
"/google/sheets/spreadsheets/{spreadsheetId}/values": {
|
||||
get: googleOperation("Google Sheets", "Get values by range query parameter", undefined, ["spreadsheetId"], ["range"]),
|
||||
put: googleOperation("Google Sheets", "Update values by range query parameter", { values: [["value"]] }, ["spreadsheetId"], ["range"])
|
||||
},
|
||||
"/google/sheets/spreadsheets/{spreadsheetId}/values/append": {
|
||||
post: googleOperation("Google Sheets", "Append values by range query parameter", { values: [["value"]] }, ["spreadsheetId"], ["range"])
|
||||
},
|
||||
"/google/sheets/spreadsheets/{spreadsheetId}/values/batch-update": {
|
||||
post: googleOperation("Google Sheets", "Batch update values", { data: [], valueInputOption: "USER_ENTERED" }, ["spreadsheetId"])
|
||||
},
|
||||
"/google/sheets/spreadsheets/{spreadsheetId}/values/batch-clear": {
|
||||
post: googleOperation("Google Sheets", "Batch clear values", { ranges: [] }, ["spreadsheetId"])
|
||||
},
|
||||
"/google/drive/files": {
|
||||
get: googleOperation("Google Drive", "List files"),
|
||||
post: googleOperation("Google Drive", "Create file metadata", { name: "New file" })
|
||||
},
|
||||
"/google/drive/files/{fileId}": {
|
||||
get: googleOperation("Google Drive", "Get file metadata", undefined, ["fileId"]),
|
||||
patch: googleOperation("Google Drive", "Update file metadata", { name: "Renamed file" }, ["fileId"]),
|
||||
delete: googleOperation("Google Drive", "Delete file", undefined, ["fileId"])
|
||||
},
|
||||
"/google/drive/files/{fileId}/export": {
|
||||
get: googleOperation("Google Drive", "Export Google Workspace file", undefined, ["fileId"], ["mimeType"])
|
||||
},
|
||||
"/google/drive/files/{fileId}/permissions": {
|
||||
get: googleOperation("Google Drive", "List file permissions", undefined, ["fileId"]),
|
||||
post: googleOperation("Google Drive", "Create file permission", { type: "user", role: "reader", emailAddress: "user@example.com" }, ["fileId"])
|
||||
},
|
||||
"/google/drive/files/{fileId}/permissions/{permissionId}": {
|
||||
delete: googleOperation("Google Drive", "Delete file permission", undefined, ["fileId", "permissionId"])
|
||||
},
|
||||
"/google/gmail/profile": {
|
||||
get: googleOperation("Gmail", "Get Gmail profile")
|
||||
},
|
||||
"/google/gmail/messages": {
|
||||
get: googleOperation("Gmail", "List messages")
|
||||
},
|
||||
"/google/gmail/messages/{messageId}": {
|
||||
get: googleOperation("Gmail", "Get message", undefined, ["messageId"])
|
||||
},
|
||||
"/google/gmail/messages/send": {
|
||||
post: googleOperation("Gmail", "Send message", { raw: "base64url-rfc2822-message" })
|
||||
},
|
||||
"/google/gmail/labels": {
|
||||
get: googleOperation("Gmail", "List labels"),
|
||||
post: googleOperation("Gmail", "Create label", { name: "Label name" })
|
||||
},
|
||||
"/google/docs/documents": {
|
||||
post: googleOperation("Google Docs", "Create document", { title: "New document" })
|
||||
},
|
||||
"/google/docs/documents/{documentId}": {
|
||||
get: googleOperation("Google Docs", "Get document", undefined, ["documentId"])
|
||||
},
|
||||
"/google/docs/documents/{documentId}/batch-update": {
|
||||
post: googleOperation("Google Docs", "Batch update document", { requests: [] }, ["documentId"])
|
||||
},
|
||||
"/google/slides/presentations": {
|
||||
post: googleOperation("Google Slides", "Create presentation", { title: "New presentation" })
|
||||
},
|
||||
"/google/slides/presentations/{presentationId}": {
|
||||
get: googleOperation("Google Slides", "Get presentation", undefined, ["presentationId"])
|
||||
},
|
||||
"/google/slides/presentations/{presentationId}/batch-update": {
|
||||
post: googleOperation("Google Slides", "Batch update presentation", { requests: [] }, ["presentationId"])
|
||||
},
|
||||
"/google/forms/forms": {
|
||||
post: googleOperation("Google Forms", "Create form", { info: { title: "New form" } })
|
||||
},
|
||||
"/google/forms/forms/{formId}": {
|
||||
get: googleOperation("Google Forms", "Get form", undefined, ["formId"])
|
||||
},
|
||||
"/google/forms/forms/{formId}/batch-update": {
|
||||
post: googleOperation("Google Forms", "Batch update form", { requests: [] }, ["formId"])
|
||||
},
|
||||
"/google/forms/forms/{formId}/responses": {
|
||||
get: googleOperation("Google Forms", "List form responses", undefined, ["formId"])
|
||||
},
|
||||
"/google/people/connections": {
|
||||
get: googleOperation("Google People", "List connections")
|
||||
},
|
||||
"/google/people/{resourceName}": {
|
||||
get: googleOperation("Google People", "Get person/contact", undefined, ["resourceName"]),
|
||||
patch: googleOperation("Google People", "Update contact", {}, ["resourceName"]),
|
||||
delete: googleOperation("Google People", "Delete contact", undefined, ["resourceName"])
|
||||
},
|
||||
"/google/people/contacts": {
|
||||
post: googleOperation("Google People", "Create contact", { names: [{ givenName: "Ada", familyName: "Lovelace" }] })
|
||||
},
|
||||
"/google/tasks/lists": {
|
||||
get: googleOperation("Google Tasks", "List task lists"),
|
||||
post: googleOperation("Google Tasks", "Create task list", { title: "Task list" })
|
||||
},
|
||||
"/google/tasks/lists/{tasklistId}/tasks": {
|
||||
get: googleOperation("Google Tasks", "List tasks", undefined, ["tasklistId"]),
|
||||
post: googleOperation("Google Tasks", "Create task", { title: "Task" }, ["tasklistId"])
|
||||
},
|
||||
"/google/tasks/lists/{tasklistId}/tasks/{taskId}": {
|
||||
patch: googleOperation("Google Tasks", "Update task", { title: "Updated task" }, ["tasklistId", "taskId"]),
|
||||
delete: googleOperation("Google Tasks", "Delete task", undefined, ["tasklistId", "taskId"])
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function googleOperation(
|
||||
tag: string,
|
||||
summary: string,
|
||||
example?: Record<string, unknown>,
|
||||
pathParams: string[] = [],
|
||||
queryParams: string[] = []
|
||||
): Record<string, unknown> {
|
||||
const parameters = [
|
||||
...pathParams.map((name) => ({ name, in: "path", required: true, schema: { type: "string" } })),
|
||||
...queryParams.map((name) => ({ name, in: "query", required: true, schema: { type: "string" } }))
|
||||
];
|
||||
|
||||
const operation: Record<string, unknown> = {
|
||||
tags: [tag],
|
||||
summary,
|
||||
security: [{ bearerAuth: [] }],
|
||||
responses: {
|
||||
"200": { description: "Google API response" },
|
||||
"400": { description: "Invalid request or Google API error" }
|
||||
}
|
||||
};
|
||||
|
||||
if (parameters.length > 0) {
|
||||
operation.parameters = parameters;
|
||||
}
|
||||
|
||||
if (example) {
|
||||
operation.requestBody = jsonRequestBody(example);
|
||||
}
|
||||
|
||||
return operation;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user