@open-webapp/drive-sync 0.5.3 → 0.5.4

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/errors.d.ts CHANGED
@@ -46,6 +46,15 @@ export declare class NotFoundError extends DriveSyncError {
46
46
  fileId: string;
47
47
  constructor(fileId: string, opts?: DriveSyncErrorOptions);
48
48
  }
49
+ /**
50
+ * Thrown when Drive refuses to serve a file's raw bytes via `alt=media`
51
+ * because it isn't binary content (e.g. a native Google Docs/Sheets/Slides
52
+ * file, which only supports Export, not Download).
53
+ */
54
+ export declare class NotDownloadableError extends DriveSyncError {
55
+ fileId: string;
56
+ constructor(fileId: string, opts?: DriveSyncErrorOptions);
57
+ }
49
58
  export interface RateLimitedErrorOptions extends DriveSyncErrorOptions {
50
59
  retryAfter?: number;
51
60
  }
package/dist/errors.js CHANGED
@@ -59,6 +59,19 @@ export class NotFoundError extends DriveSyncError {
59
59
  this.fileId = fileId;
60
60
  }
61
61
  }
62
+ /**
63
+ * Thrown when Drive refuses to serve a file's raw bytes via `alt=media`
64
+ * because it isn't binary content (e.g. a native Google Docs/Sheets/Slides
65
+ * file, which only supports Export, not Download).
66
+ */
67
+ export class NotDownloadableError extends DriveSyncError {
68
+ fileId;
69
+ constructor(fileId, opts) {
70
+ super(`File not downloadable as raw content: ${fileId}`, { status: 403, ...opts });
71
+ this.name = 'NotDownloadableError';
72
+ this.fileId = fileId;
73
+ }
74
+ }
62
75
  /** Thrown on a 429 response. */
63
76
  export class RateLimitedError extends DriveSyncError {
64
77
  retryAfter;
package/dist/files.d.ts CHANGED
@@ -18,7 +18,9 @@ export interface ReadOptions extends BaseCallOptions {
18
18
  * since Drive 404s both for a genuinely wrong id and for a file the
19
19
  * connected account cannot see — this ambiguity is documented in the public
20
20
  * API and callers are expected to treat `null` as "not available" rather
21
- * than distinguishing the two cases.
21
+ * than distinguishing the two cases. Also returns `null` for a native Google
22
+ * Workspace file (Docs/Sheets/Slides/...), since those only support Export,
23
+ * not the raw `alt=media` download this function issues.
22
24
  */
23
25
  export declare function read(opts: ReadOptions): Promise<string | Blob | null>;
24
26
  export interface RemoveOptions extends BaseCallOptions {
package/dist/files.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { driveFetch } from './http.js';
2
2
  import { escapeQ } from './query.js';
3
- import { NotFoundError, RemoteChangedError } from './errors.js';
3
+ import { NotFoundError, NotDownloadableError, RemoteChangedError } from './errors.js';
4
4
  import { getFileState, setFileState, clearFileState } from './storage.js';
5
5
  const DRIVE_BASE = 'https://www.googleapis.com/drive/v3';
6
6
  const UPLOAD_BASE = 'https://www.googleapis.com/upload/drive/v3';
@@ -53,7 +53,9 @@ async function recordBaseline(opts, fileId, version) {
53
53
  * since Drive 404s both for a genuinely wrong id and for a file the
54
54
  * connected account cannot see — this ambiguity is documented in the public
55
55
  * API and callers are expected to treat `null` as "not available" rather
56
- * than distinguishing the two cases.
56
+ * than distinguishing the two cases. Also returns `null` for a native Google
57
+ * Workspace file (Docs/Sheets/Slides/...), since those only support Export,
58
+ * not the raw `alt=media` download this function issues.
57
59
  */
58
60
  export async function read(opts) {
59
61
  try {
@@ -88,7 +90,7 @@ export async function read(opts) {
88
90
  return content;
89
91
  }
90
92
  catch (err) {
91
- if (err instanceof NotFoundError) {
93
+ if (err instanceof NotFoundError || err instanceof NotDownloadableError) {
92
94
  return null;
93
95
  }
94
96
  throw err;
package/dist/http.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { acquireToken } from './token.js';
2
2
  import { getConnection, refreshSilently } from './connection.js';
3
3
  import { clearToken, getToken } from './storage.js';
4
- import { DriveSyncError, NeedsReauthError, ScopeInsufficientError, NotFoundError, RateLimitedError, TransientError, WrongAccountError, } from './errors.js';
4
+ import { DriveSyncError, NeedsReauthError, ScopeInsufficientError, NotFoundError, NotDownloadableError, RateLimitedError, TransientError, WrongAccountError, } from './errors.js';
5
5
  const MAX_ATTEMPTS = 3;
6
6
  const BASE_DELAY_MS = 500;
7
7
  /** Mirrors connection.ts's own buffer: a cached token this close to expiry is treated as unusable. */
@@ -182,6 +182,12 @@ async function performFetch(opts, accessToken, isRetryAfter401) {
182
182
  reason: lastBodyText,
183
183
  });
184
184
  }
185
+ if (lastBodyText.includes('fileNotDownloadable')) {
186
+ // No fileId is reliably available at this layer (see the 404 case
187
+ // below) — files.ts re-catches this and returns null instead of
188
+ // rethrowing with the concrete fileId, so the empty default is fine.
189
+ throw new NotDownloadableError('', { status: 403, reason: lastBodyText });
190
+ }
185
191
  throw new DriveSyncError(`Drive request forbidden (403): ${lastBodyText}`, {
186
192
  status: 403,
187
193
  reason: lastBodyText,
package/dist/index.js CHANGED
@@ -227,7 +227,11 @@ export function createDriveSync(options) {
227
227
  });
228
228
  const results = [];
229
229
  for (const p of picked) {
230
- const content = await filesImpl.read({ ...base, fileId: p.fileId, interactive: true });
230
+ // Not interactive: the token above was already acquired
231
+ // interactively moments ago for the Picker itself and is now
232
+ // cached, so each file read reuses it (or silently refreshes)
233
+ // instead of forcing its own consent prompt per file.
234
+ const content = await filesImpl.read({ ...base, fileId: p.fileId, interactive: false });
231
235
  results.push({ fileId: p.fileId, name: p.name, mimeType: p.mimeType, content });
232
236
  }
233
237
  return results;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-webapp/drive-sync",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",