microsoft-onedrive-mock 1.0.1 → 1.0.3
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/index.js +2 -0
- package/dist/routes/v1.js +262 -6
- package/dist/store.d.ts +13 -0
- package/dist/store.js +41 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -85,6 +85,8 @@ const createApp = (config = {}) => {
|
|
|
85
85
|
// Auth Middleware
|
|
86
86
|
const validTokens = ['valid-token', 'another-valid-token'];
|
|
87
87
|
app.use((req, res, next) => {
|
|
88
|
+
if (req.path.startsWith('/v1.0/upload-sessions'))
|
|
89
|
+
return next();
|
|
88
90
|
const authHeaderVal = req.headers.authorization;
|
|
89
91
|
const authHeader = Array.isArray(authHeaderVal) ? authHeaderVal[0] : authHeaderVal;
|
|
90
92
|
if (!authHeader) {
|
package/dist/routes/v1.js
CHANGED
|
@@ -47,9 +47,84 @@ const createV1Router = () => {
|
|
|
47
47
|
// GET /me/drive/items/{id}/children
|
|
48
48
|
app.get('/v1.0/me/drive/items/:itemId/children', (req, res) => {
|
|
49
49
|
const itemId = req.params.itemId;
|
|
50
|
-
|
|
50
|
+
let children = store_1.driveStore.listItems(itemId);
|
|
51
|
+
// Basic OData $filter REJECTION
|
|
52
|
+
if (req.query.$filter && typeof req.query.$filter === 'string') {
|
|
53
|
+
res.status(400).json({
|
|
54
|
+
error: {
|
|
55
|
+
code: 'invalidRequest',
|
|
56
|
+
message: 'Invalid request'
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Basic OData $orderby support
|
|
62
|
+
if (req.query.$orderby && typeof req.query.$orderby === 'string') {
|
|
63
|
+
const descending = req.query.$orderby.includes('desc');
|
|
64
|
+
children.sort((a, b) => {
|
|
65
|
+
const timeA = a.lastModifiedDateTime || "";
|
|
66
|
+
const timeB = b.lastModifiedDateTime || "";
|
|
67
|
+
if (timeA === timeB) {
|
|
68
|
+
return a.name > b.name ? 1 : -1;
|
|
69
|
+
}
|
|
70
|
+
if (descending)
|
|
71
|
+
return timeA < timeB ? 1 : -1;
|
|
72
|
+
return timeA > timeB ? 1 : -1;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// Basic OData $top support and $skip REJECTION
|
|
76
|
+
let skip = 0;
|
|
77
|
+
if (req.query.$skip && typeof req.query.$skip === 'string') {
|
|
78
|
+
res.status(400).json({
|
|
79
|
+
error: {
|
|
80
|
+
code: 'invalidRequest',
|
|
81
|
+
message: '$skip is not supported on this API. Only URLs returned by the API can be used to page.'
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// Basic OData $top support and $skipToken pagination
|
|
87
|
+
if (req.query.$skipToken && typeof req.query.$skipToken === 'string') {
|
|
88
|
+
const parsedToken = parseInt(req.query.$skipToken, 10);
|
|
89
|
+
if (!isNaN(parsedToken))
|
|
90
|
+
skip = parsedToken;
|
|
91
|
+
}
|
|
92
|
+
let hasMore = false;
|
|
93
|
+
let nextSkipToken = 0;
|
|
94
|
+
if (req.query.$top && typeof req.query.$top === 'string') {
|
|
95
|
+
const top = parseInt(req.query.$top, 10);
|
|
96
|
+
if (!isNaN(top)) {
|
|
97
|
+
if (skip + top < children.length) {
|
|
98
|
+
hasMore = true;
|
|
99
|
+
nextSkipToken = skip + top;
|
|
100
|
+
}
|
|
101
|
+
children = children.slice(skip, skip + top);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (skip > 0) {
|
|
105
|
+
children = children.slice(skip);
|
|
106
|
+
}
|
|
51
107
|
const mappedChildren = children.map(c => applySelect(c, req.query.$select));
|
|
52
|
-
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
109
|
+
const response = { value: mappedChildren };
|
|
110
|
+
if (hasMore) {
|
|
111
|
+
const host = req.headers.host || 'localhost';
|
|
112
|
+
const protocol = req.protocol || 'http';
|
|
113
|
+
const baseBaseUrl = `${protocol}://${host}`;
|
|
114
|
+
const url = new URL(req.originalUrl || req.url, baseBaseUrl);
|
|
115
|
+
url.searchParams.set('$skipToken', nextSkipToken.toString());
|
|
116
|
+
response['@odata.nextLink'] = url.toString();
|
|
117
|
+
}
|
|
118
|
+
if (req.query.$count === 'true') {
|
|
119
|
+
res.status(400).json({
|
|
120
|
+
error: {
|
|
121
|
+
code: 'invalidRequest',
|
|
122
|
+
message: '$count is not supported on this API. Only URLs returned by the API can be used to page.'
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
res.json(response);
|
|
53
128
|
});
|
|
54
129
|
// GET /me/drive/root/search(q='query')
|
|
55
130
|
app.get('/v1.0/me/drive/root/search\\(q=\':query\'\\)', (req, res) => {
|
|
@@ -96,12 +171,33 @@ const createV1Router = () => {
|
|
|
96
171
|
}
|
|
97
172
|
const ifMatch = req.header('If-Match');
|
|
98
173
|
if (ifMatch && ifMatch !== item.eTag) {
|
|
99
|
-
res.status(
|
|
174
|
+
res.status(409).json({ error: { code: "preconditionFailed", message: "ETag mismatch" } });
|
|
100
175
|
return;
|
|
101
176
|
}
|
|
102
177
|
store_1.driveStore.deleteItem(fileId);
|
|
103
178
|
res.status(204).send();
|
|
104
179
|
});
|
|
180
|
+
// PATCH /me/drive/items/{id}
|
|
181
|
+
app.patch('/v1.0/me/drive/items/:itemId', (req, res) => {
|
|
182
|
+
const fileId = req.params.itemId;
|
|
183
|
+
if (fileId === 'root') {
|
|
184
|
+
res.status(400).json({ error: { message: "Cannot modify root" } });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const item = store_1.driveStore.getItem(fileId);
|
|
188
|
+
if (!item) {
|
|
189
|
+
res.status(404).json({ error: { code: "itemNotFound", message: "Item not found" } });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const ifMatch = req.header('If-Match');
|
|
193
|
+
if (ifMatch && ifMatch !== item.eTag) {
|
|
194
|
+
res.status(409).json({ error: { code: "preconditionFailed", message: "ETag mismatch" } });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const updates = req.body;
|
|
198
|
+
const updatedItem = store_1.driveStore.updateItem(fileId, updates);
|
|
199
|
+
res.status(200).json(applySelect(updatedItem, req.query.$select));
|
|
200
|
+
});
|
|
105
201
|
// GET /me/drive/items/{id}/content
|
|
106
202
|
app.get('/v1.0/me/drive/items/:itemId/content', (req, res) => {
|
|
107
203
|
var _a;
|
|
@@ -128,6 +224,36 @@ const createV1Router = () => {
|
|
|
128
224
|
res.send(file.content);
|
|
129
225
|
}
|
|
130
226
|
});
|
|
227
|
+
// Path-based Addressing
|
|
228
|
+
app.get('/v1.0/me/drive/items/:parentId\\:/:filename', (req, res) => {
|
|
229
|
+
const params = req.params;
|
|
230
|
+
const parentId = params.parentId;
|
|
231
|
+
let filename = params.filename;
|
|
232
|
+
if (filename.endsWith(':'))
|
|
233
|
+
filename = filename.slice(0, -1);
|
|
234
|
+
filename = decodeURIComponent(filename);
|
|
235
|
+
const parentObj = store_1.driveStore.getItem(parentId) || (parentId === 'root' ? store_1.driveStore.getItem('root') : null);
|
|
236
|
+
if (!parentObj) {
|
|
237
|
+
return res.status(404).json({ error: { code: "itemNotFound", message: "Parent not found" } });
|
|
238
|
+
}
|
|
239
|
+
const child = store_1.driveStore.getItemByName(parentId, filename);
|
|
240
|
+
if (!child) {
|
|
241
|
+
return res.status(404).json({ error: { code: "itemNotFound", message: "Item not found" } });
|
|
242
|
+
}
|
|
243
|
+
res.status(200).json(applySelect(child, req.query.$select));
|
|
244
|
+
});
|
|
245
|
+
app.get('/v1.0/me/drive/root\\:/:filename', (req, res) => {
|
|
246
|
+
const params = req.params;
|
|
247
|
+
let filename = params.filename;
|
|
248
|
+
if (filename.endsWith(':'))
|
|
249
|
+
filename = filename.slice(0, -1);
|
|
250
|
+
filename = decodeURIComponent(filename);
|
|
251
|
+
const child = store_1.driveStore.getItemByName('root', filename);
|
|
252
|
+
if (!child) {
|
|
253
|
+
return res.status(404).json({ error: { code: "itemNotFound", message: "Item not found" } });
|
|
254
|
+
}
|
|
255
|
+
res.status(200).json(applySelect(child, req.query.$select));
|
|
256
|
+
});
|
|
131
257
|
// PUT /me/drive/items/{parent-id}:/{filename}:/content
|
|
132
258
|
app.put('/v1.0/me/drive/items/:parentId\\:/:filename\\:/content', (req, res) => {
|
|
133
259
|
const parentId = req.params.parentId;
|
|
@@ -146,7 +272,8 @@ const createV1Router = () => {
|
|
|
146
272
|
return;
|
|
147
273
|
}
|
|
148
274
|
// Update
|
|
149
|
-
|
|
275
|
+
const size = content ? (Buffer.isBuffer(content) || typeof content === 'string' ? content.length : JSON.stringify(content).length) : 0;
|
|
276
|
+
item = store_1.driveStore.updateItem(item.id, { content, file: { mimeType }, size });
|
|
150
277
|
}
|
|
151
278
|
else {
|
|
152
279
|
// Create
|
|
@@ -154,7 +281,8 @@ const createV1Router = () => {
|
|
|
154
281
|
name: filename,
|
|
155
282
|
parentReference: { id: parentId },
|
|
156
283
|
content,
|
|
157
|
-
file: { mimeType }
|
|
284
|
+
file: { mimeType },
|
|
285
|
+
size: content ? (Buffer.isBuffer(content) || typeof content === 'string' ? content.length : JSON.stringify(content).length) : 0
|
|
158
286
|
});
|
|
159
287
|
}
|
|
160
288
|
res.status(isNew ? 201 : 200).json(applySelect(item, req.query.$select));
|
|
@@ -176,7 +304,8 @@ const createV1Router = () => {
|
|
|
176
304
|
const content = req.rawBody !== undefined ? req.rawBody : req.body;
|
|
177
305
|
const headerMime = req.headers['content-type'];
|
|
178
306
|
const mimeType = (Array.isArray(headerMime) ? headerMime[0] : headerMime) || ((_a = item.file) === null || _a === void 0 ? void 0 : _a.mimeType) || 'application/octet-stream';
|
|
179
|
-
|
|
307
|
+
const size = content ? (Buffer.isBuffer(content) || typeof content === 'string' ? content.length : JSON.stringify(content).length) : 0;
|
|
308
|
+
item = store_1.driveStore.updateItem(item.id, { content, file: { mimeType }, size });
|
|
180
309
|
res.status(200).json(applySelect(item, req.query.$select));
|
|
181
310
|
});
|
|
182
311
|
// Delta Query
|
|
@@ -196,6 +325,133 @@ const createV1Router = () => {
|
|
|
196
325
|
value: result.items
|
|
197
326
|
});
|
|
198
327
|
});
|
|
328
|
+
// ==========================================
|
|
329
|
+
// MISSING ENDPOINTS IMPLEMENTATION
|
|
330
|
+
// ==========================================
|
|
331
|
+
// --- Drives & Shared Content ---
|
|
332
|
+
const defaultDrive = {
|
|
333
|
+
id: "b!default-mock-drive-id",
|
|
334
|
+
driveType: "personal",
|
|
335
|
+
name: "OneDrive",
|
|
336
|
+
owner: { user: { id: "user1", displayName: "Mock User" } }
|
|
337
|
+
};
|
|
338
|
+
app.get('/v1.0/me/drives', (req, res) => {
|
|
339
|
+
res.json({ value: [defaultDrive] });
|
|
340
|
+
});
|
|
341
|
+
app.get('/v1.0/drives/:driveId', (req, res) => {
|
|
342
|
+
res.json(defaultDrive);
|
|
343
|
+
});
|
|
344
|
+
app.get('/v1.0/me/drive/sharedWithMe', (req, res) => {
|
|
345
|
+
res.json({ value: [] });
|
|
346
|
+
});
|
|
347
|
+
app.get('/v1.0/me/drive/recent', (req, res) => {
|
|
348
|
+
res.json({ value: [] });
|
|
349
|
+
});
|
|
350
|
+
app.get('/v1.0/me/drive/following', (req, res) => {
|
|
351
|
+
res.json({ value: [] });
|
|
352
|
+
});
|
|
353
|
+
// --- Special Folders ---
|
|
354
|
+
app.get('/v1.0/me/drive/special/:folderName', (req, res) => {
|
|
355
|
+
const root = store_1.driveStore.getItem('root');
|
|
356
|
+
if (!root)
|
|
357
|
+
return res.status(404).json({ error: { message: "Not found" } });
|
|
358
|
+
res.json(root);
|
|
359
|
+
});
|
|
360
|
+
// --- Advanced Item Operations ---
|
|
361
|
+
app.post('/v1.0/me/drive/items/:itemId/copy', (req, res) => {
|
|
362
|
+
const itemId = req.params.itemId;
|
|
363
|
+
const item = store_1.driveStore.getItem(itemId);
|
|
364
|
+
if (!item)
|
|
365
|
+
return res.status(404).json({ error: { message: "Not found" } });
|
|
366
|
+
const host = req.headers.host || 'localhost';
|
|
367
|
+
const protocol = req.protocol || 'http';
|
|
368
|
+
const baseUrl = `${protocol}://${host}`;
|
|
369
|
+
res.setHeader('Location', `${baseUrl}/v1.0/monitor/mock-copy-job-12345`);
|
|
370
|
+
res.status(202).json({});
|
|
371
|
+
});
|
|
372
|
+
app.post('/v1.0/me/drive/items/:itemId/createLink', (req, res) => {
|
|
373
|
+
const item = store_1.driveStore.getItem(req.params.itemId);
|
|
374
|
+
if (!item)
|
|
375
|
+
return res.status(404).json({ error: { message: "Not found" } });
|
|
376
|
+
res.json({
|
|
377
|
+
id: "mock-link-id",
|
|
378
|
+
roles: ["write"],
|
|
379
|
+
link: { webUrl: "https://mock-onedrive-link/123" }
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
app.get('/v1.0/me/drive/items/:itemId/permissions', (req, res) => {
|
|
383
|
+
res.json({ value: [{ id: "perm1", roles: ["write"] }] });
|
|
384
|
+
});
|
|
385
|
+
app.post('/v1.0/me/drive/items/:itemId/invite', (req, res) => {
|
|
386
|
+
res.json({ value: [{ id: "perm1", roles: ["write"] }] });
|
|
387
|
+
});
|
|
388
|
+
app.delete('/v1.0/me/drive/items/:itemId/permissions/:permId', (req, res) => {
|
|
389
|
+
res.status(204).send();
|
|
390
|
+
});
|
|
391
|
+
app.get('/v1.0/me/drive/items/:itemId/versions', (req, res) => {
|
|
392
|
+
res.json({ value: [] });
|
|
393
|
+
});
|
|
394
|
+
app.post('/v1.0/me/drive/items/:itemId/versions/:versionId/restoreVersion', (req, res) => {
|
|
395
|
+
res.status(204).send();
|
|
396
|
+
});
|
|
397
|
+
app.post('/v1.0/me/drive/items/:itemId/checkout', (req, res) => {
|
|
398
|
+
res.status(204).send();
|
|
399
|
+
});
|
|
400
|
+
app.post('/v1.0/me/drive/items/:itemId/checkin', (req, res) => {
|
|
401
|
+
res.status(204).send();
|
|
402
|
+
});
|
|
403
|
+
app.get('/v1.0/me/drive/items/:itemId/thumbnails', (req, res) => {
|
|
404
|
+
res.json({
|
|
405
|
+
value: [
|
|
406
|
+
{ id: "0", large: { url: "https://mock-thumbnail-url/large" } }
|
|
407
|
+
]
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
app.get('/v1.0/me/drive/items/:itemId/activities', (req, res) => {
|
|
411
|
+
res.json({ value: [] });
|
|
412
|
+
});
|
|
413
|
+
// --- Upload Sessions ---
|
|
414
|
+
const handleCreateUploadSession = (parentId, filename, req, res) => {
|
|
415
|
+
const parentObj = store_1.driveStore.getItem(parentId) || (parentId === 'root' ? store_1.driveStore.getItem('root') : null);
|
|
416
|
+
if (!parentObj) {
|
|
417
|
+
return res.status(404).json({ error: { code: "itemNotFound", message: "Parent not found" } });
|
|
418
|
+
}
|
|
419
|
+
const session = store_1.driveStore.createUploadSession(parentId, filename);
|
|
420
|
+
const host = req.headers.host || 'localhost';
|
|
421
|
+
const protocol = req.protocol || 'http';
|
|
422
|
+
const baseUrl = `${protocol}://${host}`;
|
|
423
|
+
res.status(200).json({
|
|
424
|
+
uploadUrl: `${baseUrl}/v1.0${session.uploadUrl}`,
|
|
425
|
+
expirationDateTime: session.expirationDateTime
|
|
426
|
+
});
|
|
427
|
+
};
|
|
428
|
+
app.post('/v1.0/me/drive/items/:parentId\\:/:filename\\:/createUploadSession', (req, res) => {
|
|
429
|
+
const params = req.params;
|
|
430
|
+
handleCreateUploadSession(params.parentId, decodeURIComponent(params.filename), req, res);
|
|
431
|
+
});
|
|
432
|
+
app.post('/v1.0/me/drive/root\\:/:filename\\:/createUploadSession', (req, res) => {
|
|
433
|
+
const params = req.params;
|
|
434
|
+
handleCreateUploadSession('root', decodeURIComponent(params.filename), req, res);
|
|
435
|
+
});
|
|
436
|
+
// --- Subscriptions ---
|
|
437
|
+
app.post('/v1.0/subscriptions', (req, res) => {
|
|
438
|
+
res.status(201).json({
|
|
439
|
+
id: "mock-subscription-123",
|
|
440
|
+
expirationDateTime: new Date(Date.now() + 2 * 24 * 3600 * 1000).toISOString(),
|
|
441
|
+
clientState: req.body.clientState || "mock-secret"
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
app.get('/v1.0/subscriptions', (req, res) => {
|
|
445
|
+
res.json({ value: [] });
|
|
446
|
+
});
|
|
447
|
+
app.put('/v1.0/upload-sessions/:sessionId', express_1.default.raw({ type: '*/*', limit: '50mb' }), (req, res) => {
|
|
448
|
+
const sessionId = req.params.sessionId;
|
|
449
|
+
const session = store_1.driveStore.getUploadSession(sessionId);
|
|
450
|
+
if (!session)
|
|
451
|
+
return res.status(404).json({ error: { message: "Session not found" } });
|
|
452
|
+
const item = store_1.driveStore.completeUploadSession(sessionId);
|
|
453
|
+
res.status(200).json(item);
|
|
454
|
+
});
|
|
199
455
|
return app;
|
|
200
456
|
};
|
|
201
457
|
exports.createV1Router = createV1Router;
|
package/dist/store.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { DriveItem } from './types';
|
|
|
2
2
|
export declare class DriveStore {
|
|
3
3
|
private items;
|
|
4
4
|
private deltaHistory;
|
|
5
|
+
private uploadSessions;
|
|
5
6
|
constructor();
|
|
6
7
|
private calculateStats;
|
|
7
8
|
createItem(item: Partial<DriveItem> & {
|
|
@@ -9,10 +10,22 @@ export declare class DriveStore {
|
|
|
9
10
|
}, isFolder?: boolean): DriveItem;
|
|
10
11
|
updateItem(id: string, updates: Partial<DriveItem>): DriveItem | null;
|
|
11
12
|
getItem(id: string): DriveItem | null;
|
|
13
|
+
getItemByName(parentId: string, name: string): DriveItem | null;
|
|
12
14
|
deleteItem(id: string): boolean;
|
|
13
15
|
listItems(parentId?: string): DriveItem[];
|
|
14
16
|
getAllItems(): DriveItem[];
|
|
15
17
|
clear(): void;
|
|
18
|
+
createUploadSession(parentId: string, filename: string): {
|
|
19
|
+
uploadUrl: string;
|
|
20
|
+
expirationDateTime: string;
|
|
21
|
+
};
|
|
22
|
+
completeUploadSession(sessionId: string): DriveItem | null;
|
|
23
|
+
getUploadSession(sessionId: string): {
|
|
24
|
+
parentId: string;
|
|
25
|
+
filename: string;
|
|
26
|
+
expirationDateTime: string;
|
|
27
|
+
} | null;
|
|
28
|
+
deleteUploadSession(sessionId: string): void;
|
|
16
29
|
private addDeltaHistory;
|
|
17
30
|
getDeltaToken(): string;
|
|
18
31
|
getDelta(token?: string): {
|
package/dist/store.js
CHANGED
|
@@ -39,6 +39,7 @@ class DriveStore {
|
|
|
39
39
|
constructor() {
|
|
40
40
|
this.items = new Map();
|
|
41
41
|
this.deltaHistory = [];
|
|
42
|
+
this.uploadSessions = new Map();
|
|
42
43
|
}
|
|
43
44
|
calculateStats(content) {
|
|
44
45
|
let buffer;
|
|
@@ -107,6 +108,10 @@ class DriveStore {
|
|
|
107
108
|
getItem(id) {
|
|
108
109
|
return this.items.get(id) || null;
|
|
109
110
|
}
|
|
111
|
+
getItemByName(parentId, name) {
|
|
112
|
+
const children = this.listItems(parentId);
|
|
113
|
+
return children.find(c => c.name === name && !c.deleted) || null;
|
|
114
|
+
}
|
|
110
115
|
deleteItem(id) {
|
|
111
116
|
const item = this.items.get(id);
|
|
112
117
|
if (!item)
|
|
@@ -134,9 +139,39 @@ class DriveStore {
|
|
|
134
139
|
clear() {
|
|
135
140
|
this.items.clear();
|
|
136
141
|
this.deltaHistory = [];
|
|
142
|
+
this.uploadSessions.clear();
|
|
137
143
|
// Always recreate a standard root folder
|
|
138
144
|
this.createItem({ id: 'root', name: 'root' }, true);
|
|
139
145
|
}
|
|
146
|
+
// Upload Sessions
|
|
147
|
+
createUploadSession(parentId, filename) {
|
|
148
|
+
const sessionId = Math.random().toString(36).substring(7);
|
|
149
|
+
const expirationDateTime = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(); // 1 day
|
|
150
|
+
this.uploadSessions.set(sessionId, { parentId, filename, expirationDateTime });
|
|
151
|
+
// Return a relative URL path to be prefixed by the router
|
|
152
|
+
return {
|
|
153
|
+
uploadUrl: `/upload-sessions/${sessionId}`,
|
|
154
|
+
expirationDateTime
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
completeUploadSession(sessionId) {
|
|
158
|
+
const session = this.uploadSessions.get(sessionId);
|
|
159
|
+
if (!session)
|
|
160
|
+
return null;
|
|
161
|
+
this.uploadSessions.delete(sessionId);
|
|
162
|
+
const item = this.createItem({
|
|
163
|
+
name: session.filename,
|
|
164
|
+
file: { mimeType: 'application/octet-stream' },
|
|
165
|
+
parentReference: { id: session.parentId }
|
|
166
|
+
});
|
|
167
|
+
return item;
|
|
168
|
+
}
|
|
169
|
+
getUploadSession(sessionId) {
|
|
170
|
+
return this.uploadSessions.get(sessionId) || null;
|
|
171
|
+
}
|
|
172
|
+
deleteUploadSession(sessionId) {
|
|
173
|
+
this.uploadSessions.delete(sessionId);
|
|
174
|
+
}
|
|
140
175
|
// Delta History (simulated changes API)
|
|
141
176
|
addDeltaHistory(item) {
|
|
142
177
|
this.deltaHistory.push(JSON.parse(JSON.stringify(item)));
|
|
@@ -145,6 +180,12 @@ class DriveStore {
|
|
|
145
180
|
return String(this.deltaHistory.length);
|
|
146
181
|
}
|
|
147
182
|
getDelta(token) {
|
|
183
|
+
if (token === 'latest') {
|
|
184
|
+
return {
|
|
185
|
+
items: [],
|
|
186
|
+
deltaLink: String(this.deltaHistory.length)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
148
189
|
const tokenIndex = token ? parseInt(token, 10) : 0;
|
|
149
190
|
const start = isNaN(tokenIndex) ? 0 : Math.max(0, tokenIndex);
|
|
150
191
|
const items = this.deltaHistory.slice(start);
|