gws-axi 0.10.2 → 0.12.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/src/commands/drive/mkdir.d.ts +7 -0
- package/dist/src/commands/drive/mkdir.js +101 -0
- package/dist/src/commands/drive/mkdir.js.map +1 -0
- package/dist/src/commands/drive/mkdir.test.d.ts +1 -0
- package/dist/src/commands/drive/mkdir.test.js +40 -0
- package/dist/src/commands/drive/mkdir.test.js.map +1 -0
- package/dist/src/commands/drive/upload.d.ts +17 -0
- package/dist/src/commands/drive/upload.js +217 -0
- package/dist/src/commands/drive/upload.js.map +1 -0
- package/dist/src/commands/drive/upload.test.d.ts +1 -0
- package/dist/src/commands/drive/upload.test.js +86 -0
- package/dist/src/commands/drive/upload.test.js.map +1 -0
- package/dist/src/commands/drive.js +20 -6
- package/dist/src/commands/drive.js.map +1 -1
- package/dist/src/util/mime-types.d.ts +7 -0
- package/dist/src/util/mime-types.js +95 -0
- package/dist/src/util/mime-types.js.map +1 -0
- package/dist/src/util/mime-types.test.d.ts +1 -0
- package/dist/src/util/mime-types.test.js +47 -0
- package/dist/src/util/mime-types.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const MKDIR_HELP = "usage: gws-axi drive mkdir <name> [flags]\nargs[1]:\n <name> REQUIRED \u2014 the folder name\nflags[2]:\n --parent <folder-id> Parent folder ID (default: My Drive root)\n --account <email> REQUIRED when 2+ accounts are authenticated\nexamples:\n gws-axi drive mkdir \"Q2 Reports\"\n gws-axi drive mkdir Invoices --parent 1AbC...\nnotes:\n Drive allows duplicate folder names \u2014 re-running creates ANOTHER folder.\n Capture the returned id to nest uploads with `drive upload --parent <id>`.\noutput:\n An `action: created` line plus a `folder{...}` object with id, name,\n parents, and web_view_link.\n";
|
|
2
|
+
export interface ParsedFlags {
|
|
3
|
+
name: string | undefined;
|
|
4
|
+
parent: string | undefined;
|
|
5
|
+
}
|
|
6
|
+
export declare function parseFlags(args: string[]): ParsedFlags;
|
|
7
|
+
export declare function driveMkdirCommand(account: string, args: string[]): Promise<string>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { driveClient, translateGoogleError } from "../../google/client.js";
|
|
3
|
+
import { joinBlocks, renderHelp, renderObject } from "../../output/index.js";
|
|
4
|
+
export const MKDIR_HELP = `usage: gws-axi drive mkdir <name> [flags]
|
|
5
|
+
args[1]:
|
|
6
|
+
<name> REQUIRED — the folder name
|
|
7
|
+
flags[2]:
|
|
8
|
+
--parent <folder-id> Parent folder ID (default: My Drive root)
|
|
9
|
+
--account <email> REQUIRED when 2+ accounts are authenticated
|
|
10
|
+
examples:
|
|
11
|
+
gws-axi drive mkdir "Q2 Reports"
|
|
12
|
+
gws-axi drive mkdir Invoices --parent 1AbC...
|
|
13
|
+
notes:
|
|
14
|
+
Drive allows duplicate folder names — re-running creates ANOTHER folder.
|
|
15
|
+
Capture the returned id to nest uploads with \`drive upload --parent <id>\`.
|
|
16
|
+
output:
|
|
17
|
+
An \`action: created\` line plus a \`folder{...}\` object with id, name,
|
|
18
|
+
parents, and web_view_link.
|
|
19
|
+
`;
|
|
20
|
+
const FOLDER_MIME = "application/vnd.google-apps.folder";
|
|
21
|
+
const MKDIR_FIELDS = "id,name,parents,webViewLink";
|
|
22
|
+
export function parseFlags(args) {
|
|
23
|
+
const flags = { name: undefined, parent: undefined };
|
|
24
|
+
for (let i = 0; i < args.length; i++) {
|
|
25
|
+
const arg = args[i];
|
|
26
|
+
const next = args[i + 1];
|
|
27
|
+
switch (arg) {
|
|
28
|
+
case "--parent":
|
|
29
|
+
flags.parent = next;
|
|
30
|
+
i++;
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
if (!arg.startsWith("--") && flags.name === undefined) {
|
|
34
|
+
flags.name = arg;
|
|
35
|
+
}
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return flags;
|
|
40
|
+
}
|
|
41
|
+
export async function driveMkdirCommand(account, args) {
|
|
42
|
+
const flags = parseFlags(args);
|
|
43
|
+
if (!flags.name) {
|
|
44
|
+
throw new AxiError("Missing folder name", "VALIDATION_ERROR", [
|
|
45
|
+
"Usage: gws-axi drive mkdir <name> [--parent <folder-id>]",
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
const api = await driveClient(account);
|
|
49
|
+
const requestBody = {
|
|
50
|
+
name: flags.name,
|
|
51
|
+
mimeType: FOLDER_MIME,
|
|
52
|
+
};
|
|
53
|
+
if (flags.parent)
|
|
54
|
+
requestBody.parents = [flags.parent];
|
|
55
|
+
let folder;
|
|
56
|
+
try {
|
|
57
|
+
const res = await api.files.create({
|
|
58
|
+
requestBody,
|
|
59
|
+
fields: MKDIR_FIELDS,
|
|
60
|
+
supportsAllDrives: true,
|
|
61
|
+
});
|
|
62
|
+
folder = res.data;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const translated = translateGoogleError(err, {
|
|
66
|
+
account,
|
|
67
|
+
operation: "drive.files.create",
|
|
68
|
+
});
|
|
69
|
+
if (translated.code === "NOT_FOUND") {
|
|
70
|
+
throw new AxiError(`Parent folder '${flags.parent}' not found (or ${account} can't write to it)`, "FILE_NOT_FOUND", [
|
|
71
|
+
"Verify the --parent ID is correct (from a Drive URL or `drive ls` / `drive search`)",
|
|
72
|
+
`Confirm ${account} has edit access`,
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
throw translated;
|
|
76
|
+
}
|
|
77
|
+
const id = folder.id ?? "";
|
|
78
|
+
const details = {
|
|
79
|
+
id,
|
|
80
|
+
name: folder.name ?? flags.name,
|
|
81
|
+
parents: folder.parents?.length ? folder.parents.join(", ") : "",
|
|
82
|
+
};
|
|
83
|
+
if (folder.webViewLink)
|
|
84
|
+
details.web_view_link = folder.webViewLink;
|
|
85
|
+
const blocks = [];
|
|
86
|
+
blocks.push(renderObject({ action: "created", account }));
|
|
87
|
+
blocks.push(renderObject({ folder: details }));
|
|
88
|
+
const suggestions = [
|
|
89
|
+
`Run \`gws-axi drive upload <file> --parent ${id}\` to put a file in this folder`,
|
|
90
|
+
`Run \`gws-axi drive ls ${id}\` to list its contents`,
|
|
91
|
+
`Run \`gws-axi drive get ${id}\` for full metadata`,
|
|
92
|
+
`Run \`gws-axi drive permissions ${id}\` to see / change who has access`,
|
|
93
|
+
`Re-running creates another folder (Drive allows duplicate names) — capture this id to reuse it`,
|
|
94
|
+
];
|
|
95
|
+
if (folder.webViewLink) {
|
|
96
|
+
suggestions.push(`Open in browser: ${folder.webViewLink}`);
|
|
97
|
+
}
|
|
98
|
+
blocks.push(renderHelp(suggestions));
|
|
99
|
+
return joinBlocks(...blocks);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=mkdir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mkdir.js","sourceRoot":"","sources":["../../../../src/commands/drive/mkdir.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { AxiError } from "axi-sdk-js";
|
|
3
|
+
import { parseFlags, driveMkdirCommand } from "./mkdir.js";
|
|
4
|
+
describe("drive mkdir parseFlags", () => {
|
|
5
|
+
it("parses a bare name with no parent", () => {
|
|
6
|
+
const f = parseFlags(["Reports"]);
|
|
7
|
+
expect(f.name).toBe("Reports");
|
|
8
|
+
expect(f.parent).toBeUndefined();
|
|
9
|
+
});
|
|
10
|
+
it("parses a quoted multi-word name and --parent", () => {
|
|
11
|
+
const f = parseFlags(["Q2 Reports", "--parent", "1AbC"]);
|
|
12
|
+
expect(f.name).toBe("Q2 Reports");
|
|
13
|
+
expect(f.parent).toBe("1AbC");
|
|
14
|
+
});
|
|
15
|
+
it("takes the first positional as the name, ignoring later ones", () => {
|
|
16
|
+
const f = parseFlags(["first", "second"]);
|
|
17
|
+
expect(f.name).toBe("first");
|
|
18
|
+
});
|
|
19
|
+
it("leaves name undefined when only flags are given", () => {
|
|
20
|
+
const f = parseFlags(["--parent", "1AbC"]);
|
|
21
|
+
expect(f.name).toBeUndefined();
|
|
22
|
+
expect(f.parent).toBe("1AbC");
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe("drive mkdir command validation", () => {
|
|
26
|
+
it("throws VALIDATION_ERROR when the name is missing", async () => {
|
|
27
|
+
await expect(driveMkdirCommand("a@b.com", ["--parent", "1AbC"])).rejects.toMatchObject({ code: "VALIDATION_ERROR" });
|
|
28
|
+
});
|
|
29
|
+
it("rejects with an AxiError (not a raw throw) on missing name", async () => {
|
|
30
|
+
try {
|
|
31
|
+
await driveMkdirCommand("a@b.com", []);
|
|
32
|
+
throw new Error("should have thrown");
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
expect(err).toBeInstanceOf(AxiError);
|
|
36
|
+
expect(err.code).toBe("VALIDATION_ERROR");
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=mkdir.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mkdir.test.js","sourceRoot":"","sources":["../../../../src/commands/drive/mkdir.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE3D,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/B,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;QACzD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;QAC/B,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CACpF,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAC7B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,IAAI,CAAC;YACH,MAAM,iBAAiB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,CAAE,GAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const UPLOAD_HELP = "usage: gws-axi drive upload <local-path> [flags]\nargs[1]:\n <local-path> REQUIRED \u2014 path to a readable local file to upload\nflags[5]:\n --parent <folder-id> Destination folder ID (default: My Drive root).\n Cannot be combined with --update.\n --name <name> Name to give the file in Drive (default: the local\n file's basename). With --update, renames the target.\n --mime <type> Override the source content type (default: detected\n from the file extension; unknown \u2192 application/octet-stream)\n --convert Convert to the matching native Google format on upload\n (.docx\u2192Doc, .xlsx/.csv\u2192Sheet, .pptx\u2192Slides). Cannot be\n combined with --update.\n --update <file-id> Replace an existing file's content (new revision)\n instead of creating a new file.\n --account <email> REQUIRED when 2+ accounts are authenticated\nexamples:\n gws-axi drive upload ./report.pdf\n gws-axi drive upload ./report.pdf --parent 1AbC... --name \"Q2 Report.pdf\"\n gws-axi drive upload ./notes.docx --convert\n gws-axi drive upload ./report.pdf --update 1XyZ...\nnotes:\n Without --update, every upload creates a NEW Drive file \u2014 re-running makes\n another copy (Drive allows duplicate names). Use --update <id> to replace an\n existing file's content in place.\noutput:\n An `action: created` (or `updated`) line plus a `file{...}` object with\n id, name, mime_type, size_bytes, parents, and web_view_link.\n";
|
|
2
|
+
export interface ParsedFlags {
|
|
3
|
+
localPath: string | undefined;
|
|
4
|
+
parent: string | undefined;
|
|
5
|
+
name: string | undefined;
|
|
6
|
+
mime: string | undefined;
|
|
7
|
+
convert: boolean;
|
|
8
|
+
update: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare function parseFlags(args: string[]): ParsedFlags;
|
|
11
|
+
/**
|
|
12
|
+
* Validate the local path is present and the flag combination is legal,
|
|
13
|
+
* before any FS/network work. Pure — throws `AxiError` on the same cases the
|
|
14
|
+
* spec enumerates, so it's unit-testable without touching disk or Google.
|
|
15
|
+
*/
|
|
16
|
+
export declare function validateFlags(flags: ParsedFlags): void;
|
|
17
|
+
export declare function driveUploadCommand(account: string, args: string[]): Promise<string>;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { createReadStream } from "node:fs";
|
|
2
|
+
import { stat } from "node:fs/promises";
|
|
3
|
+
import { basename, resolve } from "node:path";
|
|
4
|
+
import { AxiError } from "axi-sdk-js";
|
|
5
|
+
import { driveClient, translateGoogleError } from "../../google/client.js";
|
|
6
|
+
import { joinBlocks, renderHelp, renderObject } from "../../output/index.js";
|
|
7
|
+
import { detectMimeType, googleConversionTarget, } from "../../util/mime-types.js";
|
|
8
|
+
export const UPLOAD_HELP = `usage: gws-axi drive upload <local-path> [flags]
|
|
9
|
+
args[1]:
|
|
10
|
+
<local-path> REQUIRED — path to a readable local file to upload
|
|
11
|
+
flags[5]:
|
|
12
|
+
--parent <folder-id> Destination folder ID (default: My Drive root).
|
|
13
|
+
Cannot be combined with --update.
|
|
14
|
+
--name <name> Name to give the file in Drive (default: the local
|
|
15
|
+
file's basename). With --update, renames the target.
|
|
16
|
+
--mime <type> Override the source content type (default: detected
|
|
17
|
+
from the file extension; unknown → application/octet-stream)
|
|
18
|
+
--convert Convert to the matching native Google format on upload
|
|
19
|
+
(.docx→Doc, .xlsx/.csv→Sheet, .pptx→Slides). Cannot be
|
|
20
|
+
combined with --update.
|
|
21
|
+
--update <file-id> Replace an existing file's content (new revision)
|
|
22
|
+
instead of creating a new file.
|
|
23
|
+
--account <email> REQUIRED when 2+ accounts are authenticated
|
|
24
|
+
examples:
|
|
25
|
+
gws-axi drive upload ./report.pdf
|
|
26
|
+
gws-axi drive upload ./report.pdf --parent 1AbC... --name "Q2 Report.pdf"
|
|
27
|
+
gws-axi drive upload ./notes.docx --convert
|
|
28
|
+
gws-axi drive upload ./report.pdf --update 1XyZ...
|
|
29
|
+
notes:
|
|
30
|
+
Without --update, every upload creates a NEW Drive file — re-running makes
|
|
31
|
+
another copy (Drive allows duplicate names). Use --update <id> to replace an
|
|
32
|
+
existing file's content in place.
|
|
33
|
+
output:
|
|
34
|
+
An \`action: created\` (or \`updated\`) line plus a \`file{...}\` object with
|
|
35
|
+
id, name, mime_type, size_bytes, parents, and web_view_link.
|
|
36
|
+
`;
|
|
37
|
+
export function parseFlags(args) {
|
|
38
|
+
const flags = {
|
|
39
|
+
localPath: undefined,
|
|
40
|
+
parent: undefined,
|
|
41
|
+
name: undefined,
|
|
42
|
+
mime: undefined,
|
|
43
|
+
convert: false,
|
|
44
|
+
update: undefined,
|
|
45
|
+
};
|
|
46
|
+
for (let i = 0; i < args.length; i++) {
|
|
47
|
+
const arg = args[i];
|
|
48
|
+
const next = args[i + 1];
|
|
49
|
+
switch (arg) {
|
|
50
|
+
case "--parent":
|
|
51
|
+
flags.parent = next;
|
|
52
|
+
i++;
|
|
53
|
+
break;
|
|
54
|
+
case "--name":
|
|
55
|
+
flags.name = next;
|
|
56
|
+
i++;
|
|
57
|
+
break;
|
|
58
|
+
case "--mime":
|
|
59
|
+
flags.mime = next;
|
|
60
|
+
i++;
|
|
61
|
+
break;
|
|
62
|
+
case "--convert":
|
|
63
|
+
flags.convert = true;
|
|
64
|
+
break;
|
|
65
|
+
case "--update":
|
|
66
|
+
flags.update = next;
|
|
67
|
+
i++;
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
if (!arg.startsWith("--") && flags.localPath === undefined) {
|
|
71
|
+
flags.localPath = arg;
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return flags;
|
|
77
|
+
}
|
|
78
|
+
const UPLOAD_FIELDS = "id,name,mimeType,size,parents,webViewLink";
|
|
79
|
+
/**
|
|
80
|
+
* Validate the local path is present and the flag combination is legal,
|
|
81
|
+
* before any FS/network work. Pure — throws `AxiError` on the same cases the
|
|
82
|
+
* spec enumerates, so it's unit-testable without touching disk or Google.
|
|
83
|
+
*/
|
|
84
|
+
export function validateFlags(flags) {
|
|
85
|
+
if (!flags.localPath) {
|
|
86
|
+
throw new AxiError("Missing local file path", "VALIDATION_ERROR", [
|
|
87
|
+
"Usage: gws-axi drive upload <local-path> [flags]",
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
if (flags.update && flags.parent) {
|
|
91
|
+
throw new AxiError("--parent cannot be combined with --update", "VALIDATION_ERROR", [
|
|
92
|
+
"--update replaces a file's content in place; moving folders is not supported here",
|
|
93
|
+
"Drop --parent, or upload as a new file (omit --update) to place it in a folder",
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
if (flags.update && flags.convert) {
|
|
97
|
+
throw new AxiError("--convert cannot be combined with --update", "VALIDATION_ERROR", [
|
|
98
|
+
"Converting a file's type in place is not supported",
|
|
99
|
+
"Drop --convert to replace content as-is, or upload a new file (omit --update) with --convert",
|
|
100
|
+
]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export async function driveUploadCommand(account, args) {
|
|
104
|
+
const flags = parseFlags(args);
|
|
105
|
+
validateFlags(flags);
|
|
106
|
+
const absolutePath = resolve(process.cwd(), flags.localPath);
|
|
107
|
+
let fileStat;
|
|
108
|
+
try {
|
|
109
|
+
fileStat = await stat(absolutePath);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
throw new AxiError(`Local file not found: ${flags.localPath}`, "LOCAL_FILE_NOT_FOUND", ["Check the path; it must be a readable file on this machine"]);
|
|
113
|
+
}
|
|
114
|
+
if (fileStat.isDirectory()) {
|
|
115
|
+
throw new AxiError(`Local path is a directory, not a file: ${flags.localPath}`, "LOCAL_PATH_NOT_FILE", ["Upload a single file; recursive directory upload is not supported"]);
|
|
116
|
+
}
|
|
117
|
+
const name = flags.name ?? basename(absolutePath);
|
|
118
|
+
const sourceMime = flags.mime ?? detectMimeType(absolutePath);
|
|
119
|
+
let targetMime;
|
|
120
|
+
if (flags.convert) {
|
|
121
|
+
const target = googleConversionTarget(sourceMime);
|
|
122
|
+
if (!target) {
|
|
123
|
+
throw new AxiError(`Cannot convert ${sourceMime} to a native Google format`, "UNSUPPORTED_CONVERSION", [
|
|
124
|
+
"Supported: word-processing/text → Doc, spreadsheets/CSV → Sheet, presentations → Slides",
|
|
125
|
+
"Drop --convert to upload the file as-is",
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
128
|
+
targetMime = target;
|
|
129
|
+
}
|
|
130
|
+
const api = await driveClient(account);
|
|
131
|
+
const media = {
|
|
132
|
+
mimeType: sourceMime,
|
|
133
|
+
body: createReadStream(absolutePath),
|
|
134
|
+
};
|
|
135
|
+
let file;
|
|
136
|
+
const updating = Boolean(flags.update);
|
|
137
|
+
try {
|
|
138
|
+
if (flags.update) {
|
|
139
|
+
const res = await api.files.update({
|
|
140
|
+
fileId: flags.update,
|
|
141
|
+
requestBody: flags.name ? { name } : {},
|
|
142
|
+
media,
|
|
143
|
+
fields: UPLOAD_FIELDS,
|
|
144
|
+
supportsAllDrives: true,
|
|
145
|
+
});
|
|
146
|
+
file = res.data;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
const requestBody = { name };
|
|
150
|
+
if (flags.parent)
|
|
151
|
+
requestBody.parents = [flags.parent];
|
|
152
|
+
if (targetMime)
|
|
153
|
+
requestBody.mimeType = targetMime;
|
|
154
|
+
const res = await api.files.create({
|
|
155
|
+
requestBody,
|
|
156
|
+
media,
|
|
157
|
+
fields: UPLOAD_FIELDS,
|
|
158
|
+
supportsAllDrives: true,
|
|
159
|
+
});
|
|
160
|
+
file = res.data;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
const translated = translateGoogleError(err, {
|
|
165
|
+
account,
|
|
166
|
+
operation: updating ? "drive.files.update" : "drive.files.create",
|
|
167
|
+
});
|
|
168
|
+
if (translated.code === "NOT_FOUND") {
|
|
169
|
+
// For --update, the missing item is the target file; for create it's the
|
|
170
|
+
// --parent folder. Re-wrap with an access-check suggestion (cf. drive get).
|
|
171
|
+
const missing = updating
|
|
172
|
+
? `File '${flags.update}' not found (or ${account} can't write to it)`
|
|
173
|
+
: `Parent folder '${flags.parent}' not found (or ${account} can't write to it)`;
|
|
174
|
+
throw new AxiError(missing, "FILE_NOT_FOUND", [
|
|
175
|
+
"Verify the ID is correct (from a Drive URL or `drive search` / `drive ls`)",
|
|
176
|
+
`Confirm ${account} has edit access`,
|
|
177
|
+
]);
|
|
178
|
+
}
|
|
179
|
+
throw translated;
|
|
180
|
+
}
|
|
181
|
+
const details = {
|
|
182
|
+
id: file.id ?? "",
|
|
183
|
+
name: file.name ?? name,
|
|
184
|
+
mime_type: file.mimeType ?? "",
|
|
185
|
+
};
|
|
186
|
+
if (file.size)
|
|
187
|
+
details.size_bytes = parseInt(file.size, 10);
|
|
188
|
+
details.parents = file.parents?.length ? file.parents.join(", ") : "";
|
|
189
|
+
if (file.webViewLink)
|
|
190
|
+
details.web_view_link = file.webViewLink;
|
|
191
|
+
const blocks = [];
|
|
192
|
+
blocks.push(renderObject({ action: updating ? "updated" : "created", account }));
|
|
193
|
+
blocks.push(renderObject({ file: details }));
|
|
194
|
+
const suggestions = [];
|
|
195
|
+
const id = file.id ?? "";
|
|
196
|
+
const isNativeDoc = file.mimeType === "application/vnd.google-apps.document";
|
|
197
|
+
if (isNativeDoc) {
|
|
198
|
+
suggestions.push(`Run \`gws-axi docs read ${id}\` to read it as markdown`);
|
|
199
|
+
}
|
|
200
|
+
else if ((file.mimeType ?? "").startsWith("application/vnd.google-apps.")) {
|
|
201
|
+
suggestions.push(`Native Google file — run \`gws-axi docs download ${id} --as <mime>\` to export it`);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
suggestions.push(`Run \`gws-axi docs download ${id} --out <path>\` to fetch the bytes back`);
|
|
205
|
+
}
|
|
206
|
+
suggestions.push(`Run \`gws-axi drive get ${id}\` for full metadata`);
|
|
207
|
+
suggestions.push(`Run \`gws-axi drive permissions ${id}\` to see / change who has access`);
|
|
208
|
+
if (!updating) {
|
|
209
|
+
suggestions.push(`Re-running creates another copy — pass \`--update ${id}\` to replace this file's content instead`);
|
|
210
|
+
}
|
|
211
|
+
if (file.webViewLink) {
|
|
212
|
+
suggestions.push(`Open in browser: ${file.webViewLink}`);
|
|
213
|
+
}
|
|
214
|
+
blocks.push(renderHelp(suggestions));
|
|
215
|
+
return joinBlocks(...blocks);
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../../../src/commands/drive/upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAElC,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B1B,CAAC;AAWF,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,KAAK,GAAgB;QACzB,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK;QACd,MAAM,EAAE,SAAS;KAClB,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzB,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,UAAU;gBACb,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;gBACpB,CAAC,EAAE,CAAC;gBACJ,MAAM;YACR,KAAK,QAAQ;gBACX,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;gBAClB,CAAC,EAAE,CAAC;gBACJ,MAAM;YACR,KAAK,QAAQ;gBACX,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;gBAClB,CAAC,EAAE,CAAC;gBACJ,MAAM;YACR,KAAK,WAAW;gBACd,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;gBACrB,MAAM;YACR,KAAK,UAAU;gBACb,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;gBACpB,CAAC,EAAE,CAAC;gBACJ,MAAM;YACR;gBACE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;oBAC3D,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC;gBACxB,CAAC;gBACD,MAAM;QACV,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,aAAa,GAAG,2CAA2C,CAAC;AAElE;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAkB;IAC9C,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACrB,MAAM,IAAI,QAAQ,CAAC,yBAAyB,EAAE,kBAAkB,EAAE;YAChE,kDAAkD;SACnD,CAAC,CAAC;IACL,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,MAAM,IAAI,QAAQ,CAChB,2CAA2C,EAC3C,kBAAkB,EAClB;YACE,mFAAmF;YACnF,gFAAgF;SACjF,CACF,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,IAAI,QAAQ,CAChB,4CAA4C,EAC5C,kBAAkB,EAClB;YACE,oDAAoD;YACpD,8FAA8F;SAC/F,CACF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAe,EACf,IAAc;IAEd,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,aAAa,CAAC,KAAK,CAAC,CAAC;IAErB,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,SAAU,CAAC,CAAC;IAC9D,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,QAAQ,CAChB,yBAAyB,KAAK,CAAC,SAAS,EAAE,EAC1C,sBAAsB,EACtB,CAAC,4DAA4D,CAAC,CAC/D,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAC3B,MAAM,IAAI,QAAQ,CAChB,0CAA0C,KAAK,CAAC,SAAS,EAAE,EAC3D,qBAAqB,EACrB,CAAC,mEAAmE,CAAC,CACtE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,IAAI,cAAc,CAAC,YAAY,CAAC,CAAC;IAE9D,IAAI,UAA8B,CAAC;IACnC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,QAAQ,CAChB,kBAAkB,UAAU,4BAA4B,EACxD,wBAAwB,EACxB;gBACE,yFAAyF;gBACzF,yCAAyC;aAC1C,CACF,CAAC;QACJ,CAAC;QACD,UAAU,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG;QACZ,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,gBAAgB,CAAC,YAAY,CAAC;KACrC,CAAC;IAEF,IAAI,IAA0B,CAAC;IAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC;QACH,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;gBACjC,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;gBACvC,KAAK;gBACL,MAAM,EAAE,aAAa;gBACrB,iBAAiB,EAAE,IAAI;aACxB,CAAC,CAAC;YACH,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,MAAM,WAAW,GAAyB,EAAE,IAAI,EAAE,CAAC;YACnD,IAAI,KAAK,CAAC,MAAM;gBAAE,WAAW,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACvD,IAAI,UAAU;gBAAE,WAAW,CAAC,QAAQ,GAAG,UAAU,CAAC;YAClD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;gBACjC,WAAW;gBACX,KAAK;gBACL,MAAM,EAAE,aAAa;gBACrB,iBAAiB,EAAE,IAAI;aACxB,CAAC,CAAC;YACH,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,UAAU,GAAG,oBAAoB,CAAC,GAAG,EAAE;YAC3C,OAAO;YACP,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,oBAAoB;SAClE,CAAC,CAAC;QACH,IAAI,UAAU,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACpC,yEAAyE;YACzE,4EAA4E;YAC5E,MAAM,OAAO,GAAG,QAAQ;gBACtB,CAAC,CAAC,SAAS,KAAK,CAAC,MAAM,mBAAmB,OAAO,qBAAqB;gBACtE,CAAC,CAAC,kBAAkB,KAAK,CAAC,MAAM,mBAAmB,OAAO,qBAAqB,CAAC;YAClF,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE;gBAC5C,4EAA4E;gBAC5E,WAAW,OAAO,kBAAkB;aACrC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,UAAU,CAAC;IACnB,CAAC;IAED,MAAM,OAAO,GAA4B;QACvC,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;QACvB,SAAS,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;KAC/B,CAAC;IACF,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,IAAI,IAAI,CAAC,WAAW;QAAE,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC;IAE/D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,CAAC,IAAI,CACT,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,CACpE,CAAC;IACF,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAE7C,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;IACzB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,KAAK,sCAAsC,CAAC;IAC7E,IAAI,WAAW,EAAE,CAAC;QAChB,WAAW,CAAC,IAAI,CAAC,2BAA2B,EAAE,2BAA2B,CAAC,CAAC;IAC7E,CAAC;SAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,8BAA8B,CAAC,EAAE,CAAC;QAC5E,WAAW,CAAC,IAAI,CACd,oDAAoD,EAAE,6BAA6B,CACpF,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,WAAW,CAAC,IAAI,CACd,+BAA+B,EAAE,yCAAyC,CAC3E,CAAC;IACJ,CAAC;IACD,WAAW,CAAC,IAAI,CAAC,2BAA2B,EAAE,sBAAsB,CAAC,CAAC;IACtE,WAAW,CAAC,IAAI,CACd,mCAAmC,EAAE,mCAAmC,CACzE,CAAC;IACF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,WAAW,CAAC,IAAI,CACd,qDAAqD,EAAE,2CAA2C,CACnG,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,WAAW,CAAC,IAAI,CAAC,oBAAoB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;IACrC,OAAO,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { AxiError } from "axi-sdk-js";
|
|
3
|
+
import { parseFlags, validateFlags } from "./upload.js";
|
|
4
|
+
describe("drive upload parseFlags", () => {
|
|
5
|
+
it("parses a bare local path with defaults", () => {
|
|
6
|
+
const f = parseFlags(["./report.pdf"]);
|
|
7
|
+
expect(f.localPath).toBe("./report.pdf");
|
|
8
|
+
expect(f.parent).toBeUndefined();
|
|
9
|
+
expect(f.name).toBeUndefined();
|
|
10
|
+
expect(f.mime).toBeUndefined();
|
|
11
|
+
expect(f.convert).toBe(false);
|
|
12
|
+
expect(f.update).toBeUndefined();
|
|
13
|
+
});
|
|
14
|
+
it("parses all flags", () => {
|
|
15
|
+
const f = parseFlags([
|
|
16
|
+
"./report.pdf",
|
|
17
|
+
"--parent",
|
|
18
|
+
"1AbC",
|
|
19
|
+
"--name",
|
|
20
|
+
"Q2 Report.pdf",
|
|
21
|
+
"--mime",
|
|
22
|
+
"application/pdf",
|
|
23
|
+
"--convert",
|
|
24
|
+
]);
|
|
25
|
+
expect(f.localPath).toBe("./report.pdf");
|
|
26
|
+
expect(f.parent).toBe("1AbC");
|
|
27
|
+
expect(f.name).toBe("Q2 Report.pdf");
|
|
28
|
+
expect(f.mime).toBe("application/pdf");
|
|
29
|
+
expect(f.convert).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
it("parses --update with a file id", () => {
|
|
32
|
+
const f = parseFlags(["./report.pdf", "--update", "1XyZ"]);
|
|
33
|
+
expect(f.update).toBe("1XyZ");
|
|
34
|
+
});
|
|
35
|
+
it("takes the first positional as the local path, ignoring later ones", () => {
|
|
36
|
+
const f = parseFlags(["./a.pdf", "./b.pdf"]);
|
|
37
|
+
expect(f.localPath).toBe("./a.pdf");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("drive upload validateFlags", () => {
|
|
41
|
+
const base = {
|
|
42
|
+
localPath: "./report.pdf",
|
|
43
|
+
parent: undefined,
|
|
44
|
+
name: undefined,
|
|
45
|
+
mime: undefined,
|
|
46
|
+
convert: false,
|
|
47
|
+
update: undefined,
|
|
48
|
+
};
|
|
49
|
+
it("accepts a valid create invocation", () => {
|
|
50
|
+
expect(() => validateFlags({ ...base, parent: "1AbC" })).not.toThrow();
|
|
51
|
+
});
|
|
52
|
+
it("accepts a valid update invocation", () => {
|
|
53
|
+
expect(() => validateFlags({ ...base, update: "1XyZ" })).not.toThrow();
|
|
54
|
+
});
|
|
55
|
+
it("throws VALIDATION_ERROR when the local path is missing", () => {
|
|
56
|
+
try {
|
|
57
|
+
validateFlags({ ...base, localPath: undefined });
|
|
58
|
+
throw new Error("should have thrown");
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
expect(err).toBeInstanceOf(AxiError);
|
|
62
|
+
expect(err.code).toBe("VALIDATION_ERROR");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
it("rejects --parent combined with --update", () => {
|
|
66
|
+
try {
|
|
67
|
+
validateFlags({ ...base, parent: "1AbC", update: "1XyZ" });
|
|
68
|
+
throw new Error("should have thrown");
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
expect(err).toBeInstanceOf(AxiError);
|
|
72
|
+
expect(err.code).toBe("VALIDATION_ERROR");
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
it("rejects --convert combined with --update", () => {
|
|
76
|
+
try {
|
|
77
|
+
validateFlags({ ...base, convert: true, update: "1XyZ" });
|
|
78
|
+
throw new Error("should have thrown");
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
expect(err).toBeInstanceOf(AxiError);
|
|
82
|
+
expect(err.code).toBe("VALIDATION_ERROR");
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=upload.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.test.js","sourceRoot":"","sources":["../../../../src/commands/drive/upload.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,8 @@ import { drivePermissionsCommand, PERMISSIONS_HELP, } from "./drive/permissions.
|
|
|
7
7
|
import { driveActivityCommand, ACTIVITY_HELP } from "./drive/activity.js";
|
|
8
8
|
import { driveRevisionsCommand, REVISIONS_HELP, } from "./drive/revisions.js";
|
|
9
9
|
import { driveSearchCommand, SEARCH_HELP } from "./drive/search.js";
|
|
10
|
+
import { driveUploadCommand, UPLOAD_HELP } from "./drive/upload.js";
|
|
11
|
+
import { driveMkdirCommand, MKDIR_HELP } from "./drive/mkdir.js";
|
|
10
12
|
// Drive `download` shares the docs/download.ts implementation — same code
|
|
11
13
|
// path handles native Google file export + uploaded-file media fetch.
|
|
12
14
|
const DOWNLOAD_HELP = `usage: gws-axi drive download <file-id> [flags]
|
|
@@ -45,9 +47,6 @@ status: planned for v1 writes — not yet implemented
|
|
|
45
47
|
const DELETE_HELP = `usage: gws-axi drive delete <file-id> [flags]
|
|
46
48
|
status: planned for v1 writes — not yet implemented
|
|
47
49
|
`;
|
|
48
|
-
const MKDIR_HELP = `usage: gws-axi drive mkdir --name <name> --parent <folder-id> [flags]
|
|
49
|
-
status: planned for v1 writes — not yet implemented
|
|
50
|
-
`;
|
|
51
50
|
const SUBCOMMANDS = [
|
|
52
51
|
{ name: "search", mutation: false, help: SEARCH_HELP, handler: driveSearchCommand },
|
|
53
52
|
{ name: "get", mutation: false, help: GET_HELP, handler: driveGetCommand },
|
|
@@ -77,12 +76,23 @@ const SUBCOMMANDS = [
|
|
|
77
76
|
help: ACTIVITY_HELP,
|
|
78
77
|
handler: driveActivityCommand,
|
|
79
78
|
},
|
|
79
|
+
{
|
|
80
|
+
name: "upload",
|
|
81
|
+
mutation: true,
|
|
82
|
+
help: UPLOAD_HELP,
|
|
83
|
+
handler: driveUploadCommand,
|
|
84
|
+
},
|
|
80
85
|
{ name: "create", mutation: true, help: CREATE_HELP },
|
|
81
86
|
{ name: "copy", mutation: true, help: COPY_HELP },
|
|
82
87
|
{ name: "move", mutation: true, help: MOVE_HELP },
|
|
83
88
|
{ name: "rename", mutation: true, help: RENAME_HELP },
|
|
84
89
|
{ name: "delete", mutation: true, help: DELETE_HELP },
|
|
85
|
-
{
|
|
90
|
+
{
|
|
91
|
+
name: "mkdir",
|
|
92
|
+
mutation: true,
|
|
93
|
+
help: MKDIR_HELP,
|
|
94
|
+
handler: driveMkdirCommand,
|
|
95
|
+
},
|
|
86
96
|
];
|
|
87
97
|
const SUB_BY_NAME = Object.fromEntries(SUBCOMMANDS.map((s) => [s.name, s]));
|
|
88
98
|
function parseAccountFlag(args) {
|
|
@@ -109,20 +119,24 @@ writes[${writes.length}]:
|
|
|
109
119
|
notes:
|
|
110
120
|
Writes require --account <email> when 2+ accounts are authenticated.
|
|
111
121
|
Reads use the default account when --account is not provided.
|
|
112
|
-
|
|
113
|
-
NOT_IMPLEMENTED after account resolution runs.
|
|
122
|
+
upload and mkdir are live; the remaining write subcommands are scaffolded
|
|
123
|
+
for the next slice and throw NOT_IMPLEMENTED after account resolution runs.
|
|
114
124
|
subcommand help:
|
|
115
125
|
gws-axi drive ls --help for folder listing (incl. --recursive)
|
|
116
126
|
gws-axi drive get --help for full file metadata
|
|
117
127
|
gws-axi drive search --help for full-text search
|
|
118
128
|
gws-axi drive permissions --help for access / sharing
|
|
119
129
|
gws-axi drive download --help for fetching bytes (alias of docs download)
|
|
130
|
+
gws-axi drive upload --help for uploading a local file (incl. --convert)
|
|
131
|
+
gws-axi drive mkdir --help for creating a folder
|
|
120
132
|
examples:
|
|
121
133
|
gws-axi drive ls
|
|
122
134
|
gws-axi drive ls <folder-id> --recursive
|
|
123
135
|
gws-axi drive search --query "project plan"
|
|
124
136
|
gws-axi drive get <file-id>
|
|
125
137
|
gws-axi drive permissions <file-id>
|
|
138
|
+
gws-axi drive upload ./report.pdf --account you@example.com
|
|
139
|
+
gws-axi drive mkdir "Q2 Reports" --account you@example.com
|
|
126
140
|
`;
|
|
127
141
|
export async function driveCommand(args) {
|
|
128
142
|
if (args.length === 0 || (args.length === 1 && args[0] === "--help")) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drive.js","sourceRoot":"","sources":["../../../src/commands/drive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"drive.js","sourceRoot":"","sources":["../../../src/commands/drive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AASjE,0EAA0E;AAC1E,sEAAsE;AACtE,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;CAmBrB,CAAC;AAEF,2EAA2E;AAC3E,MAAM,WAAW,GAAG;;CAEnB,CAAC;AACF,MAAM,SAAS,GAAG;;CAEjB,CAAC;AACF,MAAM,SAAS,GAAG;;CAEjB,CAAC;AACF,MAAM,WAAW,GAAG;;CAEnB,CAAC;AACF,MAAM,WAAW,GAAG;;CAEnB,CAAC;AAEF,MAAM,WAAW,GAAsB;IACrC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,kBAAkB,EAAE;IACnF,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE;IAC1E,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE;IACvE;QACE,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,uBAAuB;KACjC;IACD;QACE,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,aAAa;QACnB,oEAAoE;QACpE,OAAO,EAAE,mBAAmB;KAC7B;IACD;QACE,IAAI,EAAE,WAAW;QACjB,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,qBAAqB;KAC/B;IACD;QACE,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,oBAAoB;KAC9B;IACD;QACE,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,kBAAkB;KAC5B;IACD,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE;IACrD,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;IACjD,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;IACjD,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE;IACrD,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE;IACrD;QACE,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,iBAAiB;KAC3B;CACF,CAAC;AAEF,MAAM,WAAW,GAAoC,MAAM,CAAC,WAAW,CACrE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CACpC,CAAC;AAEF,SAAS,gBAAgB,CAAC,IAAc;IAItC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,OAA2B,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,WAAW,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACvC,OAAO,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACtB,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACxE,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAExE,MAAM,CAAC,MAAM,UAAU,GAAG;QAClB,KAAK,CAAC,MAAM;IAChB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,MAAM;IAClB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;CAsBpB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAc;IAC/C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;QACrE,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,QAAQ,CAChB,6BAA6B,GAAG,EAAE,EAClC,kBAAkB,EAClB,CAAC,2DAA2D,CAAC,CAC9D,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,cAAc,CAAC,WAAW,EAAE;QAC7C,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,WAAW,EAAE,SAAS,GAAG,EAAE;KAC5B,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,QAAQ,CAChB,iBAAiB,GAAG,yBAAyB,EAC7C,iBAAiB,EACjB;YACE,8CAA8C,UAAU,CAAC,OAAO,EAAE;YAClE,uBAAuB,GAAG,mCAAmC;SAC9D,CACF,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DEFAULT_MIME_TYPE = "application/octet-stream";
|
|
2
|
+
/**
|
|
3
|
+
* Detect a MIME type from a file path's extension. Case-insensitive; returns
|
|
4
|
+
* `application/octet-stream` for unknown or absent extensions.
|
|
5
|
+
*/
|
|
6
|
+
export declare function detectMimeType(path: string): string;
|
|
7
|
+
export declare function googleConversionTarget(sourceMime: string): string | null;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { extname } from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Minimal extension → MIME table for `drive upload`. Node has no built-in
|
|
4
|
+
* MIME lookup, and pulling in a full database is overkill: this covers the
|
|
5
|
+
* office/document/text/image/archive types an agent actually uploads. Unknown
|
|
6
|
+
* extensions fall back to `application/octet-stream` (a safe generic binary
|
|
7
|
+
* type Drive accepts), so detection never throws — it only ever under-labels.
|
|
8
|
+
*/
|
|
9
|
+
const EXTENSION_MIME = {
|
|
10
|
+
// Office (OOXML)
|
|
11
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
12
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
13
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
14
|
+
// Office (legacy)
|
|
15
|
+
doc: "application/msword",
|
|
16
|
+
xls: "application/vnd.ms-excel",
|
|
17
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
18
|
+
// Text & delimited
|
|
19
|
+
txt: "text/plain",
|
|
20
|
+
md: "text/markdown",
|
|
21
|
+
markdown: "text/markdown",
|
|
22
|
+
csv: "text/csv",
|
|
23
|
+
tsv: "text/tab-separated-values",
|
|
24
|
+
rtf: "application/rtf",
|
|
25
|
+
html: "text/html",
|
|
26
|
+
htm: "text/html",
|
|
27
|
+
json: "application/json",
|
|
28
|
+
xml: "application/xml",
|
|
29
|
+
yaml: "application/yaml",
|
|
30
|
+
yml: "application/yaml",
|
|
31
|
+
// Documents
|
|
32
|
+
pdf: "application/pdf",
|
|
33
|
+
// Images
|
|
34
|
+
png: "image/png",
|
|
35
|
+
jpg: "image/jpeg",
|
|
36
|
+
jpeg: "image/jpeg",
|
|
37
|
+
gif: "image/gif",
|
|
38
|
+
webp: "image/webp",
|
|
39
|
+
svg: "image/svg+xml",
|
|
40
|
+
bmp: "image/bmp",
|
|
41
|
+
tif: "image/tiff",
|
|
42
|
+
tiff: "image/tiff",
|
|
43
|
+
heic: "image/heic",
|
|
44
|
+
// Audio / video
|
|
45
|
+
mp3: "audio/mpeg",
|
|
46
|
+
wav: "audio/wav",
|
|
47
|
+
mp4: "video/mp4",
|
|
48
|
+
mov: "video/quicktime",
|
|
49
|
+
// Archives
|
|
50
|
+
zip: "application/zip",
|
|
51
|
+
gz: "application/gzip",
|
|
52
|
+
tar: "application/x-tar",
|
|
53
|
+
};
|
|
54
|
+
export const DEFAULT_MIME_TYPE = "application/octet-stream";
|
|
55
|
+
/**
|
|
56
|
+
* Detect a MIME type from a file path's extension. Case-insensitive; returns
|
|
57
|
+
* `application/octet-stream` for unknown or absent extensions.
|
|
58
|
+
*/
|
|
59
|
+
export function detectMimeType(path) {
|
|
60
|
+
const ext = extname(path).replace(/^\./, "").toLowerCase();
|
|
61
|
+
if (!ext)
|
|
62
|
+
return DEFAULT_MIME_TYPE;
|
|
63
|
+
return EXTENSION_MIME[ext] ?? DEFAULT_MIME_TYPE;
|
|
64
|
+
}
|
|
65
|
+
const GOOGLE_DOC = "application/vnd.google-apps.document";
|
|
66
|
+
const GOOGLE_SHEET = "application/vnd.google-apps.spreadsheet";
|
|
67
|
+
const GOOGLE_SLIDES = "application/vnd.google-apps.presentation";
|
|
68
|
+
/**
|
|
69
|
+
* Map a source MIME type to the native Google Workspace target Drive can
|
|
70
|
+
* convert it into on upload (the `--convert` flag). Returns `null` when the
|
|
71
|
+
* source has no sensible native target — the caller surfaces
|
|
72
|
+
* `UNSUPPORTED_CONVERSION`.
|
|
73
|
+
*/
|
|
74
|
+
const CONVERSION_TARGETS = {
|
|
75
|
+
// → Google Doc
|
|
76
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": GOOGLE_DOC,
|
|
77
|
+
"application/msword": GOOGLE_DOC,
|
|
78
|
+
"application/rtf": GOOGLE_DOC,
|
|
79
|
+
"text/rtf": GOOGLE_DOC,
|
|
80
|
+
"text/plain": GOOGLE_DOC,
|
|
81
|
+
"text/markdown": GOOGLE_DOC,
|
|
82
|
+
"text/html": GOOGLE_DOC,
|
|
83
|
+
// → Google Sheet
|
|
84
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": GOOGLE_SHEET,
|
|
85
|
+
"application/vnd.ms-excel": GOOGLE_SHEET,
|
|
86
|
+
"text/csv": GOOGLE_SHEET,
|
|
87
|
+
"text/tab-separated-values": GOOGLE_SHEET,
|
|
88
|
+
// → Google Slides
|
|
89
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation": GOOGLE_SLIDES,
|
|
90
|
+
"application/vnd.ms-powerpoint": GOOGLE_SLIDES,
|
|
91
|
+
};
|
|
92
|
+
export function googleConversionTarget(sourceMime) {
|
|
93
|
+
return CONVERSION_TARGETS[sourceMime.toLowerCase()] ?? null;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=mime-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mime-types.js","sourceRoot":"","sources":["../../../src/util/mime-types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;GAMG;AACH,MAAM,cAAc,GAA2B;IAC7C,iBAAiB;IACjB,IAAI,EAAE,yEAAyE;IAC/E,IAAI,EAAE,mEAAmE;IACzE,IAAI,EAAE,2EAA2E;IACjF,kBAAkB;IAClB,GAAG,EAAE,oBAAoB;IACzB,GAAG,EAAE,0BAA0B;IAC/B,GAAG,EAAE,+BAA+B;IACpC,mBAAmB;IACnB,GAAG,EAAE,YAAY;IACjB,EAAE,EAAE,eAAe;IACnB,QAAQ,EAAE,eAAe;IACzB,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,2BAA2B;IAChC,GAAG,EAAE,iBAAiB;IACtB,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,kBAAkB;IACxB,GAAG,EAAE,iBAAiB;IACtB,IAAI,EAAE,kBAAkB;IACxB,GAAG,EAAE,kBAAkB;IACvB,YAAY;IACZ,GAAG,EAAE,iBAAiB;IACtB,SAAS;IACT,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,eAAe;IACpB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,gBAAgB;IAChB,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,iBAAiB;IACtB,WAAW;IACX,GAAG,EAAE,iBAAiB;IACtB,EAAE,EAAE,kBAAkB;IACtB,GAAG,EAAE,mBAAmB;CACzB,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,0BAA0B,CAAC;AAE5D;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC3D,IAAI,CAAC,GAAG;QAAE,OAAO,iBAAiB,CAAC;IACnC,OAAO,cAAc,CAAC,GAAG,CAAC,IAAI,iBAAiB,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,GAAG,sCAAsC,CAAC;AAC1D,MAAM,YAAY,GAAG,yCAAyC,CAAC;AAC/D,MAAM,aAAa,GAAG,0CAA0C,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,kBAAkB,GAA2B;IACjD,eAAe;IACf,yEAAyE,EACvE,UAAU;IACZ,oBAAoB,EAAE,UAAU;IAChC,iBAAiB,EAAE,UAAU;IAC7B,UAAU,EAAE,UAAU;IACtB,YAAY,EAAE,UAAU;IACxB,eAAe,EAAE,UAAU;IAC3B,WAAW,EAAE,UAAU;IACvB,iBAAiB;IACjB,mEAAmE,EACjE,YAAY;IACd,0BAA0B,EAAE,YAAY;IACxC,UAAU,EAAE,YAAY;IACxB,2BAA2B,EAAE,YAAY;IACzC,kBAAkB;IAClB,2EAA2E,EACzE,aAAa;IACf,+BAA+B,EAAE,aAAa;CAC/C,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,UAAkB;IACvD,OAAO,kBAAkB,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { DEFAULT_MIME_TYPE, detectMimeType, googleConversionTarget, } from "./mime-types.js";
|
|
3
|
+
describe("detectMimeType", () => {
|
|
4
|
+
it("maps common office and document extensions", () => {
|
|
5
|
+
expect(detectMimeType("report.docx")).toBe("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
|
6
|
+
expect(detectMimeType("data.xlsx")).toBe("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
7
|
+
expect(detectMimeType("deck.pptx")).toBe("application/vnd.openxmlformats-officedocument.presentationml.presentation");
|
|
8
|
+
expect(detectMimeType("notes.pdf")).toBe("application/pdf");
|
|
9
|
+
expect(detectMimeType("rows.csv")).toBe("text/csv");
|
|
10
|
+
});
|
|
11
|
+
it("is case-insensitive on the extension", () => {
|
|
12
|
+
expect(detectMimeType("PHOTO.JPG")).toBe("image/jpeg");
|
|
13
|
+
expect(detectMimeType("Report.DOCX")).toBe("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
|
14
|
+
});
|
|
15
|
+
it("resolves full and relative paths by their extension", () => {
|
|
16
|
+
expect(detectMimeType("/home/me/pics/cat.png")).toBe("image/png");
|
|
17
|
+
expect(detectMimeType("./sub/dir/file.md")).toBe("text/markdown");
|
|
18
|
+
});
|
|
19
|
+
it("falls back to octet-stream for unknown or absent extensions", () => {
|
|
20
|
+
expect(detectMimeType("mystery.xyz")).toBe(DEFAULT_MIME_TYPE);
|
|
21
|
+
expect(detectMimeType("Makefile")).toBe(DEFAULT_MIME_TYPE);
|
|
22
|
+
expect(detectMimeType("archive.")).toBe(DEFAULT_MIME_TYPE);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe("googleConversionTarget", () => {
|
|
26
|
+
it("maps word-processing and text sources to Google Doc", () => {
|
|
27
|
+
expect(googleConversionTarget("application/vnd.openxmlformats-officedocument.wordprocessingml.document")).toBe("application/vnd.google-apps.document");
|
|
28
|
+
expect(googleConversionTarget("text/plain")).toBe("application/vnd.google-apps.document");
|
|
29
|
+
expect(googleConversionTarget("text/markdown")).toBe("application/vnd.google-apps.document");
|
|
30
|
+
});
|
|
31
|
+
it("maps spreadsheet and delimited sources to Google Sheet", () => {
|
|
32
|
+
expect(googleConversionTarget("text/csv")).toBe("application/vnd.google-apps.spreadsheet");
|
|
33
|
+
expect(googleConversionTarget("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")).toBe("application/vnd.google-apps.spreadsheet");
|
|
34
|
+
});
|
|
35
|
+
it("maps presentation sources to Google Slides", () => {
|
|
36
|
+
expect(googleConversionTarget("application/vnd.ms-powerpoint")).toBe("application/vnd.google-apps.presentation");
|
|
37
|
+
});
|
|
38
|
+
it("is case-insensitive on the source mime", () => {
|
|
39
|
+
expect(googleConversionTarget("TEXT/CSV")).toBe("application/vnd.google-apps.spreadsheet");
|
|
40
|
+
});
|
|
41
|
+
it("returns null for unsupported source types", () => {
|
|
42
|
+
expect(googleConversionTarget("application/pdf")).toBeNull();
|
|
43
|
+
expect(googleConversionTarget("image/png")).toBeNull();
|
|
44
|
+
expect(googleConversionTarget("application/zip")).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=mime-types.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mime-types.test.js","sourceRoot":"","sources":["../../../src/util/mime-types.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gws-axi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "AXI-compliant Google Workspace CLI — token-efficient TOON output, agent-guided auth setup, unified interface for Gmail, Calendar, Docs, Drive, Slides",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|