@gpdoc/cli 1.4.0 → 1.5.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/lib/remote.js +37 -5
- package/package.json +1 -1
package/lib/remote.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
const {
|
|
4
|
+
convertDocument,
|
|
5
|
+
detectFormat,
|
|
6
|
+
readDocument,
|
|
7
|
+
} = await import('@gpdoc/filekit').catch(() => import('../../gpdoc-filekit/src/index.js'));
|
|
3
8
|
|
|
4
9
|
export class RemoteError extends Error {
|
|
5
10
|
constructor(code, message) {
|
|
@@ -49,6 +54,19 @@ function titleFrom(filePath, fallback = 'GPDoc Export') {
|
|
|
49
54
|
return path.basename(filePath).replace(/\.gpdoc\.md$/i, '').replace(/\.[^.]+$/, '') || fallback;
|
|
50
55
|
}
|
|
51
56
|
|
|
57
|
+
async function readExportDocument(filePath) {
|
|
58
|
+
const format = detectFormat(filePath);
|
|
59
|
+
if (['docx', 'pptx'].includes(format)) return null;
|
|
60
|
+
return readDocument(await readFile(filePath, 'utf8'), filePath);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function microsoftFilename(filename, title) {
|
|
64
|
+
const preferred = String(filename || `${title || 'GPDoc Export'}.docx`).trim() || 'GPDoc Export.docx';
|
|
65
|
+
return /\.docx$/i.test(preferred)
|
|
66
|
+
? preferred
|
|
67
|
+
: `${preferred.replace(/\.[^.]+$/, '')}.docx`;
|
|
68
|
+
}
|
|
69
|
+
|
|
52
70
|
async function githubToken({ auth, env, fetchImpl }) {
|
|
53
71
|
const token = await auth.getAccessToken();
|
|
54
72
|
const payload = await jsonRequest(fetchImpl, `${apiBase(env)}/.netlify/functions/get-user-profile`, { headers: bearer(token) }, 'GITHUB_IDENTITY_REQUIRED');
|
|
@@ -70,7 +88,7 @@ function githubHeaders(token) {
|
|
|
70
88
|
return { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json', 'Content-Type': 'application/json', 'X-GitHub-Api-Version': '2022-11-28' };
|
|
71
89
|
}
|
|
72
90
|
|
|
73
|
-
// @spec CLI-019, CLI-020, CLI-021, CLI-022, CLI-023, CLI-024, CLI-025
|
|
91
|
+
// @spec CLI-019, CLI-020, CLI-021, CLI-022, CLI-023, CLI-024, CLI-025, CLI-037
|
|
74
92
|
export function createRemoteClient({ auth, env = process.env, fetchImpl = globalThis.fetch } = {}) {
|
|
75
93
|
if (!auth) throw new Error('Remote client requires an auth manager.');
|
|
76
94
|
async function provider(functionName, body, method = 'POST', onProgress) {
|
|
@@ -90,10 +108,12 @@ export function createRemoteClient({ auth, env = process.env, fetchImpl = global
|
|
|
90
108
|
async googleSave({ filePath, title, mode = 'new', driveId, itemId, expectedRevision, filetype = 'document', onProgress }) {
|
|
91
109
|
await auth.getAccessToken();
|
|
92
110
|
onProgress?.({ provider: 'google', stage: 'preparing', current: 1, total: 3, filePath });
|
|
93
|
-
const
|
|
111
|
+
const document = await readExportDocument(filePath);
|
|
112
|
+
if (!document) throw new RemoteError('GOOGLE_FILE_TYPE_UNSUPPORTED', 'Google Drive upload requires a text-based GPDoc document. Convert Office files before uploading.');
|
|
113
|
+
const markdown = convertDocument(document, 'markdown');
|
|
94
114
|
onProgress?.({ provider: 'google', stage: 'uploading', current: 2, total: 3, filePath, bytes: Buffer.byteLength(markdown) });
|
|
95
115
|
const payload = await provider('google-drive-source-save', {
|
|
96
|
-
title: title || titleFrom(filePath), markdown, mode, driveId, itemId, expectedRevision, filetype,
|
|
116
|
+
title: title || document.title || titleFrom(filePath), markdown, mode, driveId, itemId, expectedRevision, filetype,
|
|
97
117
|
}, 'POST', () => {});
|
|
98
118
|
onProgress?.({ provider: 'google', stage: 'complete', current: 3, total: 3, filePath });
|
|
99
119
|
return { provider: 'google', mode, item: payload.item, warning: payload.warning || null };
|
|
@@ -102,11 +122,23 @@ export function createRemoteClient({ auth, env = process.env, fetchImpl = global
|
|
|
102
122
|
async microsoftSave({ filePath, mode = 'new', driveId, itemId, filename, onProgress }) {
|
|
103
123
|
await auth.getAccessToken();
|
|
104
124
|
onProgress?.({ provider: 'microsoft', stage: 'preparing', current: 1, total: 3, filePath });
|
|
105
|
-
const
|
|
125
|
+
const document = await readExportDocument(filePath);
|
|
126
|
+
if (document && document.filetype !== 'document') {
|
|
127
|
+
throw new RemoteError('MICROSOFT_FILE_TYPE_UNSUPPORTED', 'Microsoft 365 CLI export supports GPDoc documents.');
|
|
128
|
+
}
|
|
129
|
+
const bytes = document
|
|
130
|
+
? Buffer.from(convertDocument(document, 'docx'))
|
|
131
|
+
: await readFile(filePath);
|
|
132
|
+
const remoteFilename = document
|
|
133
|
+
? microsoftFilename(filename, document.title || titleFrom(filePath))
|
|
134
|
+
: filename || path.basename(filePath);
|
|
135
|
+
const remoteMimeType = document
|
|
136
|
+
? 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
137
|
+
: mimeType(filePath);
|
|
106
138
|
if (bytes.byteLength > 4 * 1024 * 1024) throw new RemoteError('MICROSOFT_FILE_TOO_LARGE', 'Microsoft files must be 4 MiB or smaller.');
|
|
107
139
|
onProgress?.({ provider: 'microsoft', stage: 'uploading', current: 2, total: 3, filePath, bytes: bytes.byteLength });
|
|
108
140
|
const payload = await provider('microsoft-drive-export', {
|
|
109
|
-
mode, driveId, itemId, filename:
|
|
141
|
+
mode, driveId, itemId, filename: remoteFilename, mimeType: remoteMimeType, bytes: bytes.toString('base64'),
|
|
110
142
|
}, 'POST', () => {});
|
|
111
143
|
onProgress?.({ provider: 'microsoft', stage: 'complete', current: 3, total: 3, filePath });
|
|
112
144
|
return { provider: 'microsoft', mode, item: payload.item || payload };
|