nworks-plus 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.js CHANGED
@@ -983,8 +983,7 @@ Content-Type: application/octet-stream\r
983
983
  if (!uploadRes.ok) return handleError2(uploadRes);
984
984
  return await uploadRes.json();
985
985
  }
986
- async function downloadFile(fileId, userId = "me", profile = "default") {
987
- const url = `${BASE_URL3}/users/${sanitizePathSegment(userId)}/drive/files/${sanitizePathSegment(fileId)}/download`;
986
+ async function downloadViaRedirect(url, profile) {
988
987
  if (process.env["NWORKS_VERBOSE"] === "1") {
989
988
  console.error(`[nworks] GET ${url} (get download URL)`);
990
989
  }
@@ -1019,6 +1018,48 @@ async function downloadFile(fileId, userId = "me", profile = "default") {
1019
1018
  }
1020
1019
  return { buffer, fileName };
1021
1020
  }
1021
+ async function downloadFile(fileId, userId = "me", profile = "default") {
1022
+ const url = `${BASE_URL3}/users/${sanitizePathSegment(userId)}/drive/files/${sanitizePathSegment(fileId)}/download`;
1023
+ return downloadViaRedirect(url, profile);
1024
+ }
1025
+ async function listSharedDrives(count = 100, cursor, profile = "default") {
1026
+ const params = new URLSearchParams();
1027
+ params.set("count", String(count));
1028
+ if (cursor) params.set("cursor", cursor);
1029
+ const url = `${BASE_URL3}/sharedrives?${params.toString()}`;
1030
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1031
+ console.error(`[nworks] GET ${url}`);
1032
+ }
1033
+ const res = await authedFetch2(url, { method: "GET" }, profile);
1034
+ if (!res.ok) return handleError2(res);
1035
+ const data = await res.json();
1036
+ const raw = data.sharedDrives ?? data.sharedrives ?? [];
1037
+ const sharedDrives = raw.map((d) => ({
1038
+ sharedriveId: d.sharedriveId,
1039
+ name: d.name ?? d.sharedriveName ?? "",
1040
+ permissionType: d.permissionType
1041
+ }));
1042
+ return { sharedDrives, responseMetaData: data.responseMetaData };
1043
+ }
1044
+ async function listSharedDriveFiles(sharedriveId, folderId, count = 20, cursor, profile = "default") {
1045
+ const base = `${BASE_URL3}/sharedrives/${sanitizePathSegment(sharedriveId)}/files`;
1046
+ const path = folderId ? `${base}/${sanitizePathSegment(folderId)}/children` : base;
1047
+ const params = new URLSearchParams();
1048
+ params.set("count", String(count));
1049
+ if (cursor) params.set("cursor", cursor);
1050
+ const url = `${path}?${params.toString()}`;
1051
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1052
+ console.error(`[nworks] GET ${url}`);
1053
+ }
1054
+ const res = await authedFetch2(url, { method: "GET" }, profile);
1055
+ if (!res.ok) return handleError2(res);
1056
+ const data = await res.json();
1057
+ return { files: data.files ?? [], responseMetaData: data.responseMetaData };
1058
+ }
1059
+ async function downloadSharedDriveFile(sharedriveId, fileId, profile = "default") {
1060
+ const url = `${BASE_URL3}/sharedrives/${sanitizePathSegment(sharedriveId)}/files/${sanitizePathSegment(fileId)}/download`;
1061
+ return downloadViaRedirect(url, profile);
1062
+ }
1022
1063
 
1023
1064
  // src/api/mail.ts
1024
1065
  var BASE_URL4 = "https://www.worksapis.com/v1.0";
@@ -2289,6 +2330,111 @@ OAuth Redirect URI: http://localhost:9876/callback`,
2289
2330
  }
2290
2331
  }
2291
2332
  );
2333
+ server.tool(
2334
+ "nworks_drive_sharedrive_list",
2335
+ "\uD300 \uACF5\uC720 \uB4DC\uB77C\uC774\uBE0C(Shared Drive) \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. \uAC1C\uC778 '\uB0B4 \uB4DC\uB77C\uC774\uBE0C'\uAC00 \uC544\uB2CC \uD300 \uACF5\uC720 \uC800\uC7A5\uC18C\uB97C \uCC3E\uC744 \uB54C \uC0AC\uC6A9. '\uACF5\uC720 \uB4DC\uB77C\uC774\uBE0C \uBCF4\uC5EC\uC918', '\uD300 \uB4DC\uB77C\uC774\uBE0C \uBAA9\uB85D' \uB4F1\uC758 \uC694\uCCAD\uC5D0 \uC0AC\uC6A9. \uBC18\uD658\uB41C sharedriveId\uB85C nworks_drive_sharedrive_files\uB97C \uD638\uCD9C\uD574 \uB0B4\uBD80 \uD30C\uC77C\uC744 \uC870\uD68C\uD558\uC138\uC694. User OAuth \uC778\uC99D \uD544\uC694 (file.read scope)",
2336
+ {
2337
+ count: z.number().optional().describe("\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218 (\uAE30\uBCF8: 100)"),
2338
+ cursor: z.string().optional().describe("\uD398\uC774\uC9C0\uB124\uC774\uC158 \uCEE4\uC11C")
2339
+ },
2340
+ async ({ count, cursor }) => {
2341
+ try {
2342
+ const result = await listSharedDrives(count ?? 100, cursor);
2343
+ return {
2344
+ content: [{ type: "text", text: JSON.stringify({ sharedDrives: result.sharedDrives, count: result.sharedDrives.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }]
2345
+ };
2346
+ } catch (err) {
2347
+ return {
2348
+ content: [{ type: "text", text: mcpErrorHint(err, "drive.list") }],
2349
+ isError: true
2350
+ };
2351
+ }
2352
+ }
2353
+ );
2354
+ server.tool(
2355
+ "nworks_drive_sharedrive_files",
2356
+ "\uD2B9\uC815 \uACF5\uC720 \uB4DC\uB77C\uC774\uBE0C(Shared Drive) \uC548\uC758 \uD30C\uC77C/\uD3F4\uB354 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. sharedriveId\uB294 nworks_drive_sharedrive_list\uB85C \uC870\uD68C \uAC00\uB2A5. folderId\uB97C \uC9C0\uC815\uD558\uBA74 \uD574\uB2F9 \uD3F4\uB354 \uB0B4\uBD80\uB97C, \uBBF8\uC9C0\uC815 \uC2DC \uACF5\uC720 \uB4DC\uB77C\uC774\uBE0C \uB8E8\uD2B8\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. User OAuth \uC778\uC99D \uD544\uC694 (file.read scope)",
2357
+ {
2358
+ sharedriveId: z.string().describe("\uACF5\uC720 \uB4DC\uB77C\uC774\uBE0C ID (nworks_drive_sharedrive_list\uB85C \uC870\uD68C \uAC00\uB2A5)"),
2359
+ folderId: z.string().optional().describe("\uD3F4\uB354 ID (\uBBF8\uC9C0\uC815 \uC2DC \uACF5\uC720 \uB4DC\uB77C\uC774\uBE0C \uB8E8\uD2B8)"),
2360
+ count: z.number().optional().describe("\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218 (\uAE30\uBCF8: 20, \uCD5C\uB300: 200)"),
2361
+ cursor: z.string().optional().describe("\uD398\uC774\uC9C0\uB124\uC774\uC158 \uCEE4\uC11C")
2362
+ },
2363
+ async ({ sharedriveId, folderId, count, cursor }) => {
2364
+ try {
2365
+ const result = await listSharedDriveFiles(sharedriveId, folderId, count ?? 20, cursor);
2366
+ const files = result.files.map((f) => ({
2367
+ fileId: f.fileId,
2368
+ name: f.fileName,
2369
+ type: f.fileType,
2370
+ size: f.fileSize,
2371
+ modified: f.modifiedTime,
2372
+ path: f.filePath
2373
+ }));
2374
+ return {
2375
+ content: [{ type: "text", text: JSON.stringify({ files, count: files.length, hasMore: !!result.responseMetaData?.nextCursor, nextCursor: result.responseMetaData?.nextCursor ?? null }) }]
2376
+ };
2377
+ } catch (err) {
2378
+ return {
2379
+ content: [{ type: "text", text: mcpErrorHint(err, "drive.list") }],
2380
+ isError: true
2381
+ };
2382
+ }
2383
+ }
2384
+ );
2385
+ server.tool(
2386
+ "nworks_drive_sharedrive_download",
2387
+ "\uACF5\uC720 \uB4DC\uB77C\uC774\uBE0C(Shared Drive)\uC758 \uD30C\uC77C\uC744 \uB2E4\uC6B4\uB85C\uB4DC\uD569\uB2C8\uB2E4. sharedriveId\xB7fileId\uB294 nworks_drive_sharedrive_files\uB85C \uC870\uD68C \uAC00\uB2A5. outputDir\uC744 \uC9C0\uC815\uD558\uBA74 \uB85C\uCEEC\uC5D0 \uD30C\uC77C\uB85C \uC800\uC7A5\uD558\uACE0, \uBBF8\uC9C0\uC815 \uC2DC \uD30C\uC77C \uB0B4\uC6A9\uC744 \uC9C1\uC811 \uBC18\uD658\uD569\uB2C8\uB2E4 (\uD14D\uC2A4\uD2B8\uB294 text, \uBC14\uC774\uB108\uB9AC\uB294 base64). 5MB \uCD08\uACFC \uD30C\uC77C\uC740 \uBC18\uB4DC\uC2DC outputDir\uB97C \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4. User OAuth \uC778\uC99D \uD544\uC694 (file.read scope)",
2388
+ {
2389
+ sharedriveId: z.string().describe("\uACF5\uC720 \uB4DC\uB77C\uC774\uBE0C ID (nworks_drive_sharedrive_list\uB85C \uC870\uD68C \uAC00\uB2A5)"),
2390
+ fileId: z.string().describe("\uB2E4\uC6B4\uB85C\uB4DC\uD560 \uD30C\uC77C ID (nworks_drive_sharedrive_files\uB85C \uC870\uD68C \uAC00\uB2A5)"),
2391
+ outputDir: z.string().optional().describe("\uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC (\uC9C0\uC815 \uC2DC \uD30C\uC77C\uB85C \uC800\uC7A5, \uBBF8\uC9C0\uC815 \uC2DC \uB0B4\uC6A9\uC744 \uC9C1\uC811 \uBC18\uD658)"),
2392
+ outputName: z.string().optional().describe("\uC800\uC7A5 \uD30C\uC77C\uBA85 (\uBBF8\uC9C0\uC815 \uC2DC \uC6D0\uBCF8 \uD30C\uC77C\uBA85)")
2393
+ },
2394
+ async ({ sharedriveId, fileId, outputDir, outputName }) => {
2395
+ try {
2396
+ const result = await downloadSharedDriveFile(sharedriveId, fileId);
2397
+ const fileName = outputName ?? result.fileName ?? fileId;
2398
+ if (outputDir) {
2399
+ const { writeFile: writeFile2 } = await import("fs/promises");
2400
+ const { join: join2 } = await import("path");
2401
+ const safeDir = validateLocalPath(outputDir);
2402
+ const safeName = sanitizeFileName(fileName);
2403
+ const outPath = join2(safeDir, safeName);
2404
+ validateLocalPath(outPath, safeDir);
2405
+ await writeFile2(outPath, result.buffer);
2406
+ return {
2407
+ content: [{ type: "text", text: JSON.stringify({ success: true, fileName, path: outPath, size: result.buffer.length }) }]
2408
+ };
2409
+ }
2410
+ const MAX_INLINE_SIZE = 5 * 1024 * 1024;
2411
+ if (result.buffer.length > MAX_INLINE_SIZE) {
2412
+ const sizeMB = (result.buffer.length / (1024 * 1024)).toFixed(1);
2413
+ return {
2414
+ content: [{ type: "text", text: JSON.stringify({ error: true, message: `\uD30C\uC77C\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${sizeMB}MB). outputDir\uB97C \uC9C0\uC815\uD574\uC11C \uB85C\uCEEC\uC5D0 \uC800\uC7A5\uD558\uC138\uC694.`, fileName, size: result.buffer.length }) }],
2415
+ isError: true
2416
+ };
2417
+ }
2418
+ const textExtensions = /\.(txt|md|csv|json|xml|html|htm|css|js|ts|jsx|tsx|yaml|yml|toml|ini|cfg|conf|log|sh|bash|zsh|py|rb|java|go|rs|c|cpp|h|hpp|sql|graphql|env|gitignore|dockerignore|editorconfig)$/i;
2419
+ const isText = textExtensions.test(fileName);
2420
+ if (isText) {
2421
+ const text = result.buffer.toString("utf-8");
2422
+ return {
2423
+ content: [{ type: "text", text: JSON.stringify({ success: true, fileName, size: result.buffer.length, encoding: "text", content: text }) }]
2424
+ };
2425
+ }
2426
+ const base64 = result.buffer.toString("base64");
2427
+ return {
2428
+ content: [{ type: "text", text: JSON.stringify({ success: true, fileName, size: result.buffer.length, encoding: "base64", content: base64 }) }]
2429
+ };
2430
+ } catch (err) {
2431
+ return {
2432
+ content: [{ type: "text", text: mcpErrorHint(err, "drive.download") }],
2433
+ isError: true
2434
+ };
2435
+ }
2436
+ }
2437
+ );
2292
2438
  server.tool(
2293
2439
  "nworks_mail_send",
2294
2440
  "NAVER WORKS \uBA54\uC77C\uC744 \uC804\uC1A1\uD569\uB2C8\uB2E4. '\uBA54\uC77C \uBCF4\uB0B4\uC918', '\uC774\uBA54\uC77C \uC791\uC131\uD574\uC918' \uB4F1\uC758 \uC694\uCCAD\uC5D0 \uC0AC\uC6A9. \uBE44\uB3D9\uAE30 \uC804\uC1A1(\uC131\uACF5 \uC2DC 202). User OAuth \uC778\uC99D \uD544\uC694 (mail scope)",