@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.
Files changed (2) hide show
  1. package/lib/remote.js +37 -5
  2. 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 markdown = await readFile(filePath, 'utf8');
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 bytes = await readFile(filePath);
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: filename || path.basename(filePath), mimeType: mimeType(filePath), bytes: bytes.toString('base64'),
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gpdoc/cli",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "description": "GPDoc command-line file conversion and validation tools",
6
6
  "repository": "https://github.com/repetere/gpdoc.git",