UNPKG

rxdb

Version:

A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/

273 lines (268 loc) 8.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createEmptyFile = createEmptyFile; exports.createFolder = createFolder; exports.deleteFile = deleteFile; exports.deleteIfEtagMatches = deleteIfEtagMatches; exports.ensureFolderExists = ensureFolderExists; exports.fillFileIfEtagMatches = fillFileIfEtagMatches; exports.findFolder = findFolder; exports.getDriveBaseUrl = getDriveBaseUrl; exports.listFilesInFolder = listFilesInFolder; exports.readJsonFileContent = readJsonFileContent; var _rxError = require("../../rx-error.js"); var _index = require("../utils/index.js"); /** * Returns the base URL for Graph API calls up to the drive root. * Examples: * - "https://graph.microsoft.com/v1.0/me/drive" (personal / default) * - "https://graph.microsoft.com/v1.0/drives/12345" */ function getDriveBaseUrl(oneDriveState) { var endpoint = oneDriveState.apiEndpoint || 'https://graph.microsoft.com/v1.0'; var driveId = oneDriveState.driveId || 'me/drive'; return endpoint + "/" + driveId; } async function createFolder(oneDriveState, parentId = 'root', folderName) { var baseUrl = getDriveBaseUrl(oneDriveState); var url = baseUrl + "/items/" + parentId + "/children"; var body = { name: folderName, folder: {}, '@microsoft.graph.conflictBehavior': 'fail' }; var response = await fetch(url, { method: 'POST', headers: { Authorization: 'Bearer ' + oneDriveState.authToken, 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); if (!response.ok) { if (response.status === 409) { // someone else created the same folder, return that one instead. var found = await findFolder(oneDriveState, parentId, folderName); return (0, _index.ensureNotFalsy)(found); } throw await (0, _rxError.newRxFetchError)(response, { folderName, parentId }); } await response.json(); var foundFolder = await findFolder(oneDriveState, parentId, folderName); return (0, _index.ensureNotFalsy)(foundFolder); } async function findFolder(oneDriveState, parentId = 'root', folderName) { var items = await listFilesInFolder(oneDriveState, parentId); var matchingItems = items.filter(i => i.name === folderName); if (matchingItems.length === 0) { return undefined; } // Sort by created time so older folders are picked first var item = matchingItems.sort((a, b) => { var timeA = a.createdDateTime ? new Date(a.createdDateTime).getTime() : 0; var timeB = b.createdDateTime ? new Date(b.createdDateTime).getTime() : 0; return timeA - timeB; })[0]; if (!item.folder) { throw (0, _rxError.newRxError)('ODR3', { folderName, args: { item } }); } return item.id; } async function ensureFolderExists(oneDriveState, folderPath) { var parts = folderPath.split('/').filter(p => p.length > 0); var parentId = 'root'; for (var part of parts) { var newParentId = await findFolder(oneDriveState, parentId, part); if (newParentId) { parentId = newParentId; } else { parentId = await createFolder(oneDriveState, parentId, part); } } return parentId; } async function createEmptyFile(oneDriveState, parentId, fileName) { var baseUrl = getDriveBaseUrl(oneDriveState); var url = baseUrl + "/items/" + parentId + "/children"; var body = { name: fileName, file: {}, '@microsoft.graph.conflictBehavior': 'fail' }; var response = await fetch(url, { method: 'POST', headers: { Authorization: 'Bearer ' + oneDriveState.authToken, 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); if (!response.ok && response.status !== 409) { throw await (0, _rxError.newRxFetchError)(response, { folderName: fileName }); } // To make idempotent, we always search for the file after creation // and take the oldest one in case there are duplicates. var items = await listFilesInFolder(oneDriveState, parentId); var matchingFiles = items.filter(i => i.name === fileName); var file = (0, _index.ensureNotFalsy)(matchingFiles.sort((a, b) => (a.createdDateTime ? new Date(a.createdDateTime).getTime() : 0) - (b.createdDateTime ? new Date(b.createdDateTime).getTime() : 0))[0]); return { status: response.status, etag: (0, _index.ensureNotFalsy)(file.eTag), createdTime: file.lastModifiedDateTime, fileId: (0, _index.ensureNotFalsy)(file.id), size: file.size ? file.size : 0 }; } async function fillFileIfEtagMatches(oneDriveState, fileId, etag, jsonContent) { var baseUrl = getDriveBaseUrl(oneDriveState); var url = baseUrl + "/items/" + encodeURIComponent(fileId) + "/content"; var writeContent = typeof jsonContent !== 'undefined' ? JSON.stringify(jsonContent) : ''; var res = await fetch(url, { method: "PUT", headers: { Authorization: "Bearer " + oneDriveState.authToken, "Content-Type": "application/json; charset=utf-8", "If-Match": etag }, body: writeContent }); if (res.status === 412) { return readJsonFileContent(oneDriveState, fileId).then(r => { return { content: r.content, etag: r.etag, status: res.status }; }); } if (res.status !== 200 && res.status !== 201) { throw await (0, _rxError.newRxFetchError)(res); } var data = await res.json(); return { content: jsonContent, etag: (0, _index.ensureNotFalsy)(data.eTag), status: res.status }; } async function deleteIfEtagMatches(oneDriveState, fileId, etag) { var baseUrl = getDriveBaseUrl(oneDriveState); var url = baseUrl + "/items/" + encodeURIComponent(fileId); var res = await fetch(url, { method: "DELETE", headers: { Authorization: "Bearer " + oneDriveState.authToken, // Not all item deletions in Microsoft Graph honor If-Match, but we send it. // As per KI, we might have to relax it for folders, but this is used for files. "If-Match": etag } }); if (!res.ok) { throw await (0, _rxError.newRxFetchError)(res, { args: { etag, fileId } }); } } async function deleteFile(oneDriveState, fileId) { var baseUrl = getDriveBaseUrl(oneDriveState); var url = baseUrl + "/items/" + encodeURIComponent(fileId); var res = await fetch(url, { method: "DELETE", headers: { Authorization: "Bearer " + oneDriveState.authToken } }); if (!res.ok) { throw await (0, _rxError.newRxFetchError)(res, { args: { fileId } }); } } async function readJsonFileContent(oneDriveState, fileId) { var baseUrl = getDriveBaseUrl(oneDriveState); // Fetch metadata FIRST to reliably get the ETag, preventing race conditions // where old content is fetched via /content and arbitrarily paired with a newer ETag fallback. var metaResponse = await fetch(baseUrl + "/items/" + encodeURIComponent(fileId) + "?$select=id,eTag,@microsoft.graph.downloadUrl", { headers: { Authorization: "Bearer " + oneDriveState.authToken } }); if (!metaResponse.ok) { if (metaResponse.status === 404) { return { etag: '', content: undefined }; } throw await (0, _rxError.newRxFetchError)(metaResponse, { args: { fileId } }); } var meta = await metaResponse.json(); var etag = (0, _index.ensureNotFalsy)(meta.eTag, 'eTag missing from metadata'); var contentText = ''; // Some mock servers or endpoints may omit the downloadUrl. Fallback to /content if necessary. var downloadUrl = meta['@microsoft.graph.downloadUrl'] || baseUrl + "/items/" + encodeURIComponent(fileId) + "/content"; var contentRes = await fetch(downloadUrl, { method: "GET", headers: { Authorization: "Bearer " + oneDriveState.authToken } }); if (contentRes.status === 200 || contentRes.status === 201) { contentText = await contentRes.text(); } else if (contentRes.status !== 404) { throw await (0, _rxError.newRxFetchError)(contentRes, { args: { fileId, downloadUrl } }); } var content = contentText.length > 0 ? JSON.parse(contentText) : undefined; return { etag, content: content }; } async function listFilesInFolder(oneDriveState, folderId) { var baseUrl = getDriveBaseUrl(oneDriveState); var url = baseUrl + "/items/" + folderId + "/children?$select=id,name,eTag,createdDateTime,lastModifiedDateTime,size,file,folder"; var items = []; while (url) { var res = await fetch(url, { headers: { Authorization: "Bearer " + oneDriveState.authToken } }); if (!res.ok) { var text = await res.text().catch(() => ""); throw new Error("files.list failed: " + res.status + " " + text); } var data = await res.json(); var batch = data.value || []; items.push(...batch); url = data['@odata.nextLink']; } return items; } //# sourceMappingURL=microsoft-onedrive-helper.js.map