@open-webapp/drive-sync 0.3.0 → 0.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/README.md +1 -1
- package/SPEC.md +3 -1
- package/dist/files.js +4 -2
- package/dist/testing/driveFake.d.ts +6 -0
- package/dist/testing/driveFake.js +8 -1
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ const folderId = await p.ensureFolderPath()
|
|
|
29
29
|
await p.files.write({ folderId, name: 'data.json', content: '{}', mimeType: 'application/json' })
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
See `SPEC.md` for the full design: the
|
|
32
|
+
See `SPEC.md` for the full design: the 36 resolved decisions, storage layout,
|
|
33
33
|
and refresh state machine. `SPEC.md` is descriptive, written from the shipped
|
|
34
34
|
code — if it ever disagrees with the source, the source wins.
|
|
35
35
|
|
package/SPEC.md
CHANGED
|
@@ -50,7 +50,7 @@ Files implementing the surface: `index.ts` (factory + `ProjectHandle`/`FilesHand
|
|
|
50
50
|
|
|
51
51
|
`getAccessToken()` is the one deliberate exception to `Connection` never exposing secret material (types.ts): it exists solely so an app can feed the token to Google Picker (`setOAuthToken()`), which runs outside this library's control and has no other way to read it. Reuses a cached token while it has more than 5 minutes left; otherwise acquires one (interactive by default, since callers use this to drive a UI the user is actively interacting with).
|
|
52
52
|
|
|
53
|
-
## 2. The
|
|
53
|
+
## 2. The 36 resolved design decisions
|
|
54
54
|
|
|
55
55
|
**Bugs fixed (both source apps carried these):**
|
|
56
56
|
|
|
@@ -94,6 +94,8 @@ Files implementing the surface: `index.ts` (factory + `ProjectHandle`/`FilesHand
|
|
|
94
94
|
34. **`interactive` option, default `false`** — every `BaseCallOptions`-shaped call in `files.ts`/`permissions.ts`/`http.ts` defaults `interactive` to falsy; a non-interactive call with no usable token throws `NeedsReauthError` rather than silently prompting.
|
|
95
95
|
35. **Google Picker integration** — `picker.ts`'s `pickFile` accepts an `apiKey` and an `appId` (the OAuth client's Cloud project number) per-call (not stored in `DriveSyncOptions`); `appId` is mandatory because drive-sync holds only a `drive.file`-scoped token and Picker rejects a scoped session it cannot attribute to an app — omitting it makes Picker drop the OAuth token, show its own sign-in prompt, and fail with "The API developer key is invalid"; `index.ts` and `connection.ts` resolve the token, but `picker.ts` only ever sees a plain string token to avoid secret exposure. Script loading is cached at module level to avoid repeated GIS-loader calls. On user cancel, `PickerCancelledError` is thrown; on success, `FileRef` is returned. Drive scope prerequisites and token refresh are handled transparently (`picker.ts` takes the token and makes the Picker call; no token-boundary complexity leaks to callers).
|
|
96
96
|
|
|
97
|
+
36. **`list()` returns `modifiedTime`** — `files.ts`'s `list()` requests `modifiedTime` alongside `id,name,mimeType,version` (same field `fetchRemoteVersion` already fetches per-file for `status()`); `FileRef.modifiedTime` (`types.ts`) is optional since older/unfetched responses may omit it.
|
|
98
|
+
|
|
97
99
|
## 3. Storage layout
|
|
98
100
|
|
|
99
101
|
Each project gets its own IndexedDB database: **`owa-drive-{appId}-{projectId}`**, version 1, containing one object store, `auth` (`storage.ts`). The store holds exactly two keys:
|
package/dist/files.js
CHANGED
|
@@ -292,8 +292,10 @@ function buildQuery(opts) {
|
|
|
292
292
|
export async function list(opts) {
|
|
293
293
|
const q = buildQuery(opts);
|
|
294
294
|
// `version` comes back so the name-resolution path in write() can run its
|
|
295
|
-
// staleness check without a follow-up metadata fetch.
|
|
296
|
-
|
|
295
|
+
// staleness check without a follow-up metadata fetch. `modifiedTime` is
|
|
296
|
+
// also requested so callers can get a last-modified timestamp per file
|
|
297
|
+
// without an extra round trip.
|
|
298
|
+
const url = `${DRIVE_BASE}/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent('files(id,name,mimeType,version,modifiedTime)')}`;
|
|
297
299
|
const res = await driveFetch({
|
|
298
300
|
appId: opts.appId,
|
|
299
301
|
projectId: opts.projectId,
|
|
@@ -25,6 +25,12 @@ export interface DriveFakeFile {
|
|
|
25
25
|
* Optional so tests may seed files without it; treated as 1 when absent.
|
|
26
26
|
*/
|
|
27
27
|
version?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Drive's last-modified timestamp; optional so tests may seed files
|
|
30
|
+
* without it (omitted from the fake's response in that case, matching
|
|
31
|
+
* real Drive's `fields`-gated behavior).
|
|
32
|
+
*/
|
|
33
|
+
modifiedTime?: string;
|
|
28
34
|
}
|
|
29
35
|
export interface DriveFakePermission {
|
|
30
36
|
id: string;
|
|
@@ -142,7 +142,14 @@ export function createDriveFake() {
|
|
|
142
142
|
return override;
|
|
143
143
|
}
|
|
144
144
|
function fileToMetadata(f) {
|
|
145
|
-
return {
|
|
145
|
+
return {
|
|
146
|
+
id: f.id,
|
|
147
|
+
name: f.name,
|
|
148
|
+
mimeType: f.mimeType,
|
|
149
|
+
parents: f.parents,
|
|
150
|
+
version: String(f.version ?? 1),
|
|
151
|
+
modifiedTime: f.modifiedTime,
|
|
152
|
+
};
|
|
146
153
|
}
|
|
147
154
|
async function handleFilesList(url) {
|
|
148
155
|
const q = url.searchParams.get('q') ?? '';
|
package/dist/types.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export interface FileRef {
|
|
|
29
29
|
name?: string;
|
|
30
30
|
/** Drive's monotonic change counter, when the call requested it. */
|
|
31
31
|
version?: string;
|
|
32
|
+
/** Drive's last-modified timestamp (RFC3339), when the call requested it. */
|
|
33
|
+
modifiedTime?: string;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
36
|
* Sync state of one file relative to what this client last restored.
|