openwork-server 0.18.61 → 0.18.62
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/{opencode-plugin-deps-1.18.30.tgz → opencode-plugin-deps-1.18.33.tgz} +0 -0
- package/dist/opencode-plugins/drive-file-tools.js +10 -8
- package/dist/opencode-plugins/openwork-extensions-preview.js +9 -7
- package/dist/openwork-server.mjs +317 -40
- package/package.json +1 -1
- package/web/assets/{abnfDiagram-VCTEODGH-DGCabXot.js → abnfDiagram-VCTEODGH-DJzrT8Ql.js} +1 -1
- package/web/assets/{app-Cy3sY2K8.js → app-_2KkkZIM.js} +10 -10
- package/web/assets/{arc-OJTfUP9L.js → arc-KehB1xN5.js} +1 -1
- package/web/assets/{architectureDiagram-5GKGNRK7-Ch0Zt81S.js → architectureDiagram-5GKGNRK7-C_GL2639.js} +1 -1
- package/web/assets/{artifact-code-view-CSo8dBet.js → artifact-code-view-CYn_58gV.js} +1 -1
- package/web/assets/{artifact-spreadsheet-editor-DG2AL4aO.js → artifact-spreadsheet-editor-f6V-tYvi.js} +1 -1
- package/web/assets/{artifact-text-editor-BKs1cI6V.js → artifact-text-editor-CiSlW3kl.js} +1 -1
- package/web/assets/{blockDiagram-OSKFZWR5-Dur4PitI.js → blockDiagram-OSKFZWR5-DErH-7gY.js} +1 -1
- package/web/assets/{c4Diagram-7LVT6UL2-DN-qrh5o.js → c4Diagram-7LVT6UL2-aML4z_n9.js} +1 -1
- package/web/assets/channel-7oM0ncHI.js +1 -0
- package/web/assets/{chunk-2Q5K7J3B-BSmk0dam.js → chunk-2Q5K7J3B-Dw_IH9rW.js} +1 -1
- package/web/assets/{chunk-5VM5RSS4-BwAmjLhK.js → chunk-5VM5RSS4-aeJEQ945.js} +1 -1
- package/web/assets/{chunk-F27PBJKO-DLKbY_DS.js → chunk-F27PBJKO-hZwti-Oc.js} +1 -1
- package/web/assets/{chunk-HLEWEB6X-s4I3BuHN.js → chunk-HLEWEB6X-JFNzm3Ge.js} +1 -1
- package/web/assets/{chunk-JWPE2WC7-LslAnaQK.js → chunk-JWPE2WC7-B34hvYk7.js} +1 -1
- package/web/assets/{chunk-POPQ4Y6H-e0_lKBGk.js → chunk-POPQ4Y6H-CDqgEp-q.js} +1 -1
- package/web/assets/{chunk-SVP7TREG-CBKOSsQl.js → chunk-SVP7TREG-B65ta9aQ.js} +1 -1
- package/web/assets/{chunk-XXDRQBXY-Bwqkh7ZD.js → chunk-XXDRQBXY-DjTi6c9m.js} +1 -1
- package/web/assets/{chunk-ZLD2IHE6-anLhhsDd.js → chunk-ZLD2IHE6-CbviXFvb.js} +1 -1
- package/web/assets/classDiagram-CYGNFDIV-BkidFauP.js +1 -0
- package/web/assets/classDiagram-v2-TLXNO2FR-BkidFauP.js +1 -0
- package/web/assets/{cose-bilkent-JH36ORCC-CCj043X5.js → cose-bilkent-JH36ORCC-Cl9SO5zd.js} +1 -1
- package/web/assets/{cynefin-OW5HDTMX-BGWD-i0N.js → cynefin-OW5HDTMX-CAcz2tHt.js} +1 -1
- package/web/assets/{cynefinDiagram-5FMLGOSQ-ZWq_C5SK.js → cynefinDiagram-5FMLGOSQ-BJHft4FO.js} +1 -1
- package/web/assets/{dagre-OS7QT2EB-In3Mah_T.js → dagre-OS7QT2EB-DbdnY1uS.js} +1 -1
- package/web/assets/{diagram-S7CK7UJ4-DaTd6oXD.js → diagram-S7CK7UJ4-C07WD5Lc.js} +1 -1
- package/web/assets/{diagram-UQ7AKVKN-D3jwCd_v.js → diagram-UQ7AKVKN-D8VCjq9x.js} +1 -1
- package/web/assets/{diagram-VSXAHHWV-CsK-_hfn.js → diagram-VSXAHHWV-D1XSfMnK.js} +1 -1
- package/web/assets/{diagram-VX7I27RA-BBLQ2mL7.js → diagram-VX7I27RA-3GZe-yrf.js} +1 -1
- package/web/assets/{diagram-Z3DM3KII-CUM2PN0X.js → diagram-Z3DM3KII-CI43WcIB.js} +1 -1
- package/web/assets/{ebnfDiagram-PWID7BFC-BjJTJ9Vr.js → ebnfDiagram-PWID7BFC-CTzouade.js} +1 -1
- package/web/assets/{erDiagram-2YWLMYGG-BhjMQMDs.js → erDiagram-2YWLMYGG-CNcqsnqx.js} +1 -1
- package/web/assets/{flowDiagram-T62WH6J4-KrGbrW-t.js → flowDiagram-T62WH6J4-pomAqjgF.js} +1 -1
- package/web/assets/{ganttDiagram-EL5Y4UJY-Co_OE6ls.js → ganttDiagram-EL5Y4UJY-C1dNaxxj.js} +1 -1
- package/web/assets/{gitGraphDiagram-WWUBYQGX-BxM4C4Ti.js → gitGraphDiagram-WWUBYQGX-Ni8GECg1.js} +1 -1
- package/web/assets/{infoDiagram-FKFFQAWI-C8YaW3a6.js → infoDiagram-FKFFQAWI-C0kvE7Zu.js} +1 -1
- package/web/assets/{ishikawaDiagram-5VMMS53U-MPTb2C9Y.js → ishikawaDiagram-5VMMS53U-CxmP_irp.js} +1 -1
- package/web/assets/{journeyDiagram-EYS64GPL-Dzq-vllP.js → journeyDiagram-EYS64GPL-60GkPgH5.js} +1 -1
- package/web/assets/{kanban-definition-UXKFOSKX-DWhE5bnH.js → kanban-definition-UXKFOSKX-ByxcB0T_.js} +1 -1
- package/web/assets/{layout-CMyIV62W.js → layout-BD9ef90s.js} +1 -1
- package/web/assets/{linear-CX-tWibZ.js → linear-Dp9l0lBr.js} +1 -1
- package/web/assets/{mermaid.core-DcgS6fFC.js → mermaid.core-FKm3Akes.js} +6 -6
- package/web/assets/{mindmap-definition-THT77NOG-CJzNRYpk.js → mindmap-definition-THT77NOG-i7WJlWHV.js} +1 -1
- package/web/assets/{pegDiagram-XKGWAZYB-BSIi724T.js → pegDiagram-XKGWAZYB-DfI-LsJq.js} +1 -1
- package/web/assets/{pieDiagram-E7YTZNPT-CoArMhZD.js → pieDiagram-E7YTZNPT-kcgWYBSb.js} +1 -1
- package/web/assets/{quadrantDiagram-AXDQQJYC-B9HoxOyK.js → quadrantDiagram-AXDQQJYC-DVyziZnc.js} +1 -1
- package/web/assets/{railroadDiagram-O6MQD6OU-C-aYV4dU.js → railroadDiagram-O6MQD6OU-CWgHq9nv.js} +1 -1
- package/web/assets/{requirementDiagram-IS5BZ75X-DHPnVlti.js → requirementDiagram-IS5BZ75X-B7fgi4lz.js} +1 -1
- package/web/assets/{sankeyDiagram-P5KCCOFB-DlxAwgv1.js → sankeyDiagram-P5KCCOFB-D1-pD_qh.js} +1 -1
- package/web/assets/{sequenceDiagram-WJ2MYXX4-DzVPZb2m.js → sequenceDiagram-WJ2MYXX4-B6oeRmVj.js} +1 -1
- package/web/assets/{sizeCapture-INFHLROL-BkwjaMAx.js → sizeCapture-INFHLROL-BTpKGFt5.js} +1 -1
- package/web/assets/{stateDiagram-XQSTLZYL-DIeNtdWj.js → stateDiagram-XQSTLZYL-zXJRxE6h.js} +1 -1
- package/web/assets/stateDiagram-v2-IH3M54BS-CmwZ6tXj.js +1 -0
- package/web/assets/{swimlanes-V6O3JKXN-CPUSs3Tj.js → swimlanes-V6O3JKXN-Dc7MXPb3.js} +1 -1
- package/web/assets/swimlanesDiagram-JKAHXJPX-BXoJEx2b.js +8 -0
- package/web/assets/{timeline-definition-24CTP7MA-CjBwDFJH.js → timeline-definition-24CTP7MA-DYhgbnjW.js} +1 -1
- package/web/assets/{vennDiagram-4TSXK5OY-DOsoEsMT.js → vennDiagram-4TSXK5OY-DRnme7za.js} +1 -1
- package/web/assets/{wardleyDiagram-VM6X3IG4-_fhLZdvF.js → wardleyDiagram-VM6X3IG4-wAoo4GsZ.js} +1 -1
- package/web/assets/{workspace-file-tree-CTzNl5A5.js → workspace-file-tree-DmAwvqtx.js} +1 -1
- package/web/assets/{xychartDiagram-S5SC5T6Z-D4Kz81TF.js → xychartDiagram-S5SC5T6Z-_Z_TOWBn.js} +1 -1
- package/web/index.html +1 -1
- package/web/assets/channel-68fpiRG4.js +0 -1
- package/web/assets/classDiagram-CYGNFDIV-Z4CG2h2d.js +0 -1
- package/web/assets/classDiagram-v2-TLXNO2FR-Z4CG2h2d.js +0 -1
- package/web/assets/stateDiagram-v2-IH3M54BS-CZR_2wND.js +0 -1
- package/web/assets/swimlanesDiagram-JKAHXJPX-C1Sms2Ey.js +0 -8
package/dist/openwork-server.mjs
CHANGED
|
@@ -310371,6 +310371,14 @@ import { createHash as createHash16, randomBytes as randomBytes6 } from "node:cr
|
|
|
310371
310371
|
import { constants as constants3, realpathSync } from "node:fs";
|
|
310372
310372
|
import { lstat as lstat3, mkdir as mkdir13, open as open4, readFile as readFile24, realpath as realpath5, rename as rename7, rm as rm12, stat as stat6, writeFile as writeFile17 } from "node:fs/promises";
|
|
310373
310373
|
import { basename as basename10, dirname as dirname15, extname as extname2, isAbsolute as isAbsolute3, join as join25, relative as relative5, resolve as resolve16 } from "node:path";
|
|
310374
|
+
|
|
310375
|
+
// ../../packages/types/src/microsoft-drive-transfer.ts
|
|
310376
|
+
var MICROSOFT_DRIVE_TRANSFER_MAX_BYTES = 250 * 1024 * 1024;
|
|
310377
|
+
var MICROSOFT_DRIVE_PULL_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
310378
|
+
var MICROSOFT_DRIVE_UPLOAD_CHUNK_BYTES = 32 * 320 * 1024;
|
|
310379
|
+
var MICROSOFT_DRIVE_UPLOAD_MAX_BYTES = 250 * 1000 ** 3;
|
|
310380
|
+
|
|
310381
|
+
// src/extensions/drive-files.ts
|
|
310374
310382
|
init_errors5();
|
|
310375
310383
|
init_runtime_db();
|
|
310376
310384
|
|
|
@@ -310461,7 +310469,11 @@ var LINKS_FILE = "drive-links.json";
|
|
|
310461
310469
|
var DEN_TIMEOUT_MS = 2 * 60 * 1000;
|
|
310462
310470
|
var MAX_STATUS_FILES = 50;
|
|
310463
310471
|
var CONNECTION_ID = /^(google-workspace|emc_[A-Za-z0-9]+)$/;
|
|
310472
|
+
var MICROSOFT_CONNECTION_ID = /^(microsoft-365|emc_[A-Za-z0-9]+)$/;
|
|
310464
310473
|
var DRIVE_ID = /^[A-Za-z0-9_-]{1,512}$/;
|
|
310474
|
+
var MICROSOFT_ID = /^[^\s/\\?#]{1,512}$/;
|
|
310475
|
+
var MICROSOFT_LINK_HOST = /(^|\.)(sharepoint\.(com|us|cn|de)|sharepoint-mil\.us|onedrive\.(com|live\.com)|1drv\.ms)$/;
|
|
310476
|
+
var SERVICE_NAME = { "google-workspace": "Drive", "microsoft-365": "OneDrive or SharePoint" };
|
|
310465
310477
|
var CONVERTIBLE_FORMATS = {
|
|
310466
310478
|
"application/vnd.google-apps.spreadsheet": ["xlsx", "csv"],
|
|
310467
310479
|
"application/vnd.google-apps.document": ["docx", "md", "txt"],
|
|
@@ -310487,14 +310499,47 @@ function readArgString(args2, key2) {
|
|
|
310487
310499
|
const value3 = args2[key2];
|
|
310488
310500
|
return typeof value3 === "string" ? value3.trim() : "";
|
|
310489
310501
|
}
|
|
310490
|
-
function optionalConnectionId(args2) {
|
|
310502
|
+
function optionalConnectionId(args2, provider = "google-workspace") {
|
|
310491
310503
|
if (args2.connectionId === undefined)
|
|
310492
310504
|
return;
|
|
310493
|
-
|
|
310494
|
-
|
|
310505
|
+
const pattern = provider === "microsoft-365" ? MICROSOFT_CONNECTION_ID : CONNECTION_ID;
|
|
310506
|
+
if (typeof args2.connectionId !== "string" || !pattern.test(args2.connectionId)) {
|
|
310507
|
+
throw new ApiError(400, "invalid_payload", provider === "microsoft-365" ? "connectionId must identify a Microsoft 365 connection." : "connectionId must identify a native Google Workspace connection.");
|
|
310495
310508
|
}
|
|
310496
310509
|
return args2.connectionId;
|
|
310497
310510
|
}
|
|
310511
|
+
function isMicrosoftLink(value3) {
|
|
310512
|
+
try {
|
|
310513
|
+
const url2 = new URL(value3);
|
|
310514
|
+
return url2.protocol === "https:" && MICROSOFT_LINK_HOST.test(url2.hostname);
|
|
310515
|
+
} catch {
|
|
310516
|
+
return false;
|
|
310517
|
+
}
|
|
310518
|
+
}
|
|
310519
|
+
function providerFor(args2) {
|
|
310520
|
+
if (args2.provider !== undefined) {
|
|
310521
|
+
if (args2.provider !== "google-workspace" && args2.provider !== "microsoft-365")
|
|
310522
|
+
throw new ApiError(400, "invalid_payload", "provider must be google-workspace or microsoft-365.");
|
|
310523
|
+
return args2.provider;
|
|
310524
|
+
}
|
|
310525
|
+
if (args2.driveId !== undefined || args2.connectionId === "microsoft-365")
|
|
310526
|
+
return "microsoft-365";
|
|
310527
|
+
return isMicrosoftLink(readArgString(args2, "fileId")) ? "microsoft-365" : "google-workspace";
|
|
310528
|
+
}
|
|
310529
|
+
function microsoftTarget(args2) {
|
|
310530
|
+
const fileId = readArgString(args2, "fileId");
|
|
310531
|
+
const driveId = args2.driveId === undefined ? undefined : readArgString(args2, "driveId");
|
|
310532
|
+
if (driveId !== undefined && !MICROSOFT_ID.test(driveId))
|
|
310533
|
+
throw new ApiError(400, "invalid_payload", "driveId must be a Microsoft drive id.");
|
|
310534
|
+
if (isMicrosoftLink(fileId)) {
|
|
310535
|
+
if (driveId !== undefined)
|
|
310536
|
+
throw new ApiError(400, "invalid_payload", "Pass a OneDrive or SharePoint link, or an item id with its driveId, not both.");
|
|
310537
|
+
return { url: fileId };
|
|
310538
|
+
}
|
|
310539
|
+
if (!MICROSOFT_ID.test(fileId))
|
|
310540
|
+
throw new ApiError(400, "invalid_payload", "fileId must be a OneDrive or SharePoint item id or file link.");
|
|
310541
|
+
return { itemId: fileId, ...driveId ? { driveId } : {} };
|
|
310542
|
+
}
|
|
310498
310543
|
function parseDriveFileId(value3) {
|
|
310499
310544
|
const trimmed = value3.trim();
|
|
310500
310545
|
if (DRIVE_ID.test(trimmed))
|
|
@@ -310738,9 +310783,11 @@ async function denRequest(config2, dependencies, suffix, init = {}) {
|
|
|
310738
310783
|
headers: {
|
|
310739
310784
|
authorization: endpoint.authorization,
|
|
310740
310785
|
...init.body !== undefined ? { "content-type": "application/json" } : {},
|
|
310786
|
+
...init.bytes ? { "content-type": "application/octet-stream" } : {},
|
|
310741
310787
|
...init.headers
|
|
310742
310788
|
},
|
|
310743
310789
|
...init.body !== undefined ? { body: JSON.stringify(init.body) } : {},
|
|
310790
|
+
...init.bytes ? { body: init.bytes } : {},
|
|
310744
310791
|
signal: dependencies.signal ? AbortSignal.any([dependencies.signal, AbortSignal.timeout(DEN_TIMEOUT_MS)]) : AbortSignal.timeout(DEN_TIMEOUT_MS)
|
|
310745
310792
|
});
|
|
310746
310793
|
} catch (error48) {
|
|
@@ -310774,6 +310821,7 @@ function parseDownloadInfo(payload) {
|
|
|
310774
310821
|
return {
|
|
310775
310822
|
file: {
|
|
310776
310823
|
id: file2.id,
|
|
310824
|
+
driveId: "",
|
|
310777
310825
|
name: file2.name,
|
|
310778
310826
|
mimeType: file2.mimeType,
|
|
310779
310827
|
native: file2.native === true,
|
|
@@ -310793,12 +310841,55 @@ function parseDownloadInfo(payload) {
|
|
|
310793
310841
|
}
|
|
310794
310842
|
};
|
|
310795
310843
|
}
|
|
310796
|
-
|
|
310797
|
-
|
|
310844
|
+
function parseMicrosoftDownloadInfo(payload) {
|
|
310845
|
+
const file2 = payload.file;
|
|
310846
|
+
const download = payload.download;
|
|
310847
|
+
if (!isRecord28(file2) || !isRecord28(download) || typeof file2.id !== "string" || !MICROSOFT_ID.test(file2.id) || typeof file2.name !== "string" || typeof file2.mimeType !== "string" || typeof download.mimeType !== "string" || file2.driveId !== "" && (typeof file2.driveId !== "string" || !MICROSOFT_ID.test(file2.driveId))) {
|
|
310848
|
+
throw new ApiError(502, "cloud_drive_failed", "OpenWork Cloud returned an invalid OneDrive or SharePoint file description.");
|
|
310849
|
+
}
|
|
310850
|
+
const size6 = typeof download.size === "number" && Number.isSafeInteger(download.size) ? download.size : null;
|
|
310851
|
+
return {
|
|
310852
|
+
file: {
|
|
310853
|
+
id: file2.id,
|
|
310854
|
+
driveId: file2.driveId,
|
|
310855
|
+
name: file2.name,
|
|
310856
|
+
mimeType: file2.mimeType,
|
|
310857
|
+
native: false,
|
|
310858
|
+
revision: stringOrNull(file2.revision),
|
|
310859
|
+
md5Checksum: null,
|
|
310860
|
+
size: typeof file2.size === "number" ? file2.size : null,
|
|
310861
|
+
webViewLink: stringOrNull(file2.webUrl),
|
|
310862
|
+
parents: typeof file2.parentId === "string" && file2.parentId ? [file2.parentId] : []
|
|
310863
|
+
},
|
|
310864
|
+
download: {
|
|
310865
|
+
format: download.format === "pdf" ? "pdf" : null,
|
|
310866
|
+
mimeType: download.mimeType,
|
|
310867
|
+
extension: stringOrNull(download.extension),
|
|
310868
|
+
size: size6,
|
|
310869
|
+
exported: download.exported === true,
|
|
310870
|
+
maxBytes: typeof download.maxBytes === "number" ? Math.min(download.maxBytes, MICROSOFT_DRIVE_TRANSFER_MAX_BYTES) : MICROSOFT_DRIVE_TRANSFER_MAX_BYTES
|
|
310871
|
+
}
|
|
310872
|
+
};
|
|
310873
|
+
}
|
|
310874
|
+
async function describe4(config2, dependencies, target, format4, connectionId) {
|
|
310875
|
+
if ("fileId" in target) {
|
|
310876
|
+
return parseDownloadInfo(await denJson(config2, dependencies, `/v1/direct-downloads/google-workspace/drive-files/${target.fileId}`, { query: { format: format4, connectionId } }));
|
|
310877
|
+
}
|
|
310878
|
+
const query = "url" in target ? { url: target.url } : { itemId: target.itemId, driveId: target.driveId };
|
|
310879
|
+
return parseMicrosoftDownloadInfo(await denJson(config2, dependencies, "/v1/direct-downloads/microsoft-365/drive-files", { query: { ...query, format: format4, connectionId } }));
|
|
310880
|
+
}
|
|
310881
|
+
function describedTarget(provider, info) {
|
|
310882
|
+
return provider === "microsoft-365" ? { itemId: info.file.id, ...info.file.driveId ? { driveId: info.file.driveId } : {} } : { fileId: info.file.id };
|
|
310798
310883
|
}
|
|
310799
|
-
|
|
310800
|
-
|
|
310801
|
-
|
|
310884
|
+
function linkTarget(link2) {
|
|
310885
|
+
return link2.provider === "microsoft-365" ? { itemId: link2.fileId, ...link2.driveId ? { driveId: link2.driveId } : {} } : { fileId: link2.fileId };
|
|
310886
|
+
}
|
|
310887
|
+
async function download(config2, dependencies, provider, info, connectionId, handle) {
|
|
310888
|
+
const format4 = info.download.exported ? info.download.format ?? undefined : undefined;
|
|
310889
|
+
const microsoft = provider === "microsoft-365";
|
|
310890
|
+
const suffix = microsoft ? "/v1/direct-downloads/microsoft-365/drive-files/content" : `/v1/direct-downloads/google-workspace/drive-files/${info.file.id}/content`;
|
|
310891
|
+
const query = microsoft ? { itemId: info.file.id, driveId: info.file.driveId || undefined, format: format4, connectionId } : { format: format4, connectionId };
|
|
310892
|
+
const chunkBytes = microsoft ? MICROSOFT_DRIVE_PULL_CHUNK_BYTES : GOOGLE_DRIVE_PULL_CHUNK_BYTES;
|
|
310802
310893
|
const sha256 = createHash16("sha256");
|
|
310803
310894
|
const md5 = createHash16("md5");
|
|
310804
310895
|
let written = 0;
|
|
@@ -310812,14 +310903,14 @@ async function download(config2, dependencies, info, connectionId, handle) {
|
|
|
310812
310903
|
};
|
|
310813
310904
|
const size6 = info.download.size;
|
|
310814
310905
|
if (!info.download.exported && size6 !== null) {
|
|
310815
|
-
for (let start = 0;start < size6; start +=
|
|
310816
|
-
const end = Math.min(size6, start +
|
|
310906
|
+
for (let start = 0;start < size6; start += chunkBytes) {
|
|
310907
|
+
const end = Math.min(size6, start + chunkBytes) - 1;
|
|
310817
310908
|
const response = await denRequest(config2, dependencies, suffix, { query, headers: { range: `bytes=${start}-${end}` } });
|
|
310818
310909
|
if (!response.ok)
|
|
310819
310910
|
await denFailure(response);
|
|
310820
310911
|
if (response.status !== 206 && !(response.status === 200 && start === 0 && end === size6 - 1)) {
|
|
310821
310912
|
await response.body?.cancel();
|
|
310822
|
-
throw new ApiError(502, "drive_download_incomplete", "
|
|
310913
|
+
throw new ApiError(502, "drive_download_incomplete", "The requested part of the file did not arrive. Try the pull again.");
|
|
310823
310914
|
}
|
|
310824
310915
|
const bytes = new Uint8Array(await response.arrayBuffer().catch(() => {
|
|
310825
310916
|
throw new ApiError(502, "drive_download_incomplete", "The download stopped early. Try the pull again.");
|
|
@@ -310833,7 +310924,7 @@ async function download(config2, dependencies, info, connectionId, handle) {
|
|
|
310833
310924
|
if (!response.ok)
|
|
310834
310925
|
await denFailure(response);
|
|
310835
310926
|
if (!response.body)
|
|
310836
|
-
throw new ApiError(502, "drive_download_incomplete", "
|
|
310927
|
+
throw new ApiError(502, "drive_download_incomplete", "No file content arrived.");
|
|
310837
310928
|
try {
|
|
310838
310929
|
for await (const chunk of response.body)
|
|
310839
310930
|
await write(chunk);
|
|
@@ -310849,21 +310940,28 @@ function verified(info, saved) {
|
|
|
310849
310940
|
return (info.download.size === null || saved.size === info.download.size) && (info.download.exported || !info.file.md5Checksum || saved.md5 === info.file.md5Checksum);
|
|
310850
310941
|
}
|
|
310851
310942
|
async function pullDriveFile(config2, args2, context4, dependencies) {
|
|
310852
|
-
const
|
|
310943
|
+
const provider = providerFor(args2);
|
|
310944
|
+
let fileTarget = provider === "microsoft-365" ? microsoftTarget(args2) : { fileId: parseDriveFileId(readArgString(args2, "fileId")) };
|
|
310853
310945
|
const format4 = readArgString(args2, "format") || undefined;
|
|
310946
|
+
if (provider === "microsoft-365" && format4 && format4 !== "pdf")
|
|
310947
|
+
throw new ApiError(400, "invalid_payload", "OneDrive and SharePoint files can only be converted to pdf; omit format to pull the file as it is.");
|
|
310854
310948
|
if (format4 && !/^[a-z]{2,5}$/.test(format4))
|
|
310855
310949
|
throw new ApiError(400, "invalid_payload", "format must be an export format such as xlsx, csv, docx, md, txt, pptx or pdf.");
|
|
310856
|
-
const connectionId = optionalConnectionId(args2);
|
|
310950
|
+
const connectionId = optionalConnectionId(args2, provider);
|
|
310857
310951
|
const overwrite = args2.overwrite === true;
|
|
310858
310952
|
const requested = readArgString(args2, "path") || null;
|
|
310859
|
-
|
|
310860
|
-
|
|
310953
|
+
const service3 = SERVICE_NAME[provider];
|
|
310954
|
+
let info = await describe4(config2, dependencies, fileTarget, format4, connectionId);
|
|
310955
|
+
fileTarget = describedTarget(provider, info);
|
|
310956
|
+
const converted = provider === "microsoft-365" && info.download.exported;
|
|
310957
|
+
const sourceName = converted ? info.file.name.slice(0, info.file.name.length - extname2(info.file.name).length) || info.file.name : info.file.name;
|
|
310958
|
+
const name = safeFileName(sourceName, info.download.exported ? info.download.extension : null);
|
|
310861
310959
|
const links = await readLinks(config2);
|
|
310862
310960
|
let target = await resolvePullTarget(config2, context4, requested, name);
|
|
310863
310961
|
if (!requested) {
|
|
310864
310962
|
const extension = extname2(name);
|
|
310865
310963
|
const stem = name.slice(0, name.length - extension.length);
|
|
310866
|
-
for (let copy2 = 2;await exists2(target) && links.links[target]
|
|
310964
|
+
for (let copy2 = 2;await exists2(target) && !sameDriveFile(links.links[target], provider, info); copy2 += 1) {
|
|
310867
310965
|
if (copy2 > 50)
|
|
310868
310966
|
throw new ApiError(409, "path_exists", "Choose a path for this file; the default names are taken.");
|
|
310869
310967
|
target = await resolvePullTarget(config2, context4, null, `${stem} (${copy2})${extension}`);
|
|
@@ -310872,24 +310970,24 @@ async function pullDriveFile(config2, args2, context4, dependencies) {
|
|
|
310872
310970
|
const before = await lstat3(target).catch(() => null);
|
|
310873
310971
|
if (before) {
|
|
310874
310972
|
const link3 = links.links[target];
|
|
310875
|
-
if (link3
|
|
310973
|
+
if (sameDriveFile(link3, provider, info)) {
|
|
310876
310974
|
const local = await hashFile(target);
|
|
310877
310975
|
if (local.sha256 === link3.sha256 && link3.revision !== null && link3.revision === info.file.revision && link3.format === info.download.format) {
|
|
310878
310976
|
return pullResult(config2, context4, target, info, local.size, true);
|
|
310879
310977
|
}
|
|
310880
310978
|
if (!overwrite && local.sha256 !== link3.sha256) {
|
|
310881
|
-
throw new ApiError(409, "local_changes",
|
|
310979
|
+
throw new ApiError(409, "local_changes", `The local copy has edits that are not in ${service3}. Push them first, or pull with overwrite: true to discard them.`, { path: displayPath(config2, context4, target) });
|
|
310882
310980
|
}
|
|
310883
310981
|
} else if (!overwrite) {
|
|
310884
310982
|
throw new ApiError(409, "path_exists", "A different file already exists at that path. Choose another path, or pass overwrite: true to replace it.");
|
|
310885
310983
|
}
|
|
310886
310984
|
}
|
|
310887
310985
|
let saved = null;
|
|
310888
|
-
await confirmDriveTransfer(config2, { action: before && overwrite ? "overwrite" : "pull", path: target, fileId: info.file.id, name: info.file.name, webViewLink: info.file.webViewLink }, dependencies.signal);
|
|
310986
|
+
await confirmDriveTransfer(config2, { provider, action: before && overwrite ? "overwrite" : "pull", path: target, fileId: info.file.id, name: info.file.name, webViewLink: info.file.webViewLink }, dependencies.signal);
|
|
310889
310987
|
for (let attempt = 1;attempt <= 2 && !saved; attempt += 1) {
|
|
310890
310988
|
const temporary = await privateDriveFile(config2);
|
|
310891
310989
|
try {
|
|
310892
|
-
const result3 = await download(config2, dependencies, info, connectionId, temporary);
|
|
310990
|
+
const result3 = await download(config2, dependencies, provider, info, connectionId, temporary);
|
|
310893
310991
|
if (verified(info, result3)) {
|
|
310894
310992
|
if (!sameState(before, await lstat3(target).catch(() => null))) {
|
|
310895
310993
|
throw new ApiError(409, "local_changes", "The file at that path changed while pulling, so it was not replaced. Pull again once it is saved or pushed.", { path: displayPath(config2, context4, target) });
|
|
@@ -310919,10 +311017,10 @@ async function pullDriveFile(config2, args2, context4, dependencies) {
|
|
|
310919
311017
|
}
|
|
310920
311018
|
}
|
|
310921
311019
|
} catch (error48) {
|
|
310922
|
-
const transient = error48 instanceof ApiError && ["drive_download_incomplete", "google_api_error", "cloud_drive_failed"].includes(error48.code);
|
|
311020
|
+
const transient = error48 instanceof ApiError && ["drive_download_incomplete", "google_api_error", "microsoft_graph_error", "cloud_drive_failed"].includes(error48.code);
|
|
310923
311021
|
if (!transient || attempt === 2)
|
|
310924
311022
|
throw error48;
|
|
310925
|
-
const fresh = await describe4(config2, dependencies,
|
|
311023
|
+
const fresh = await describe4(config2, dependencies, fileTarget, format4, connectionId);
|
|
310926
311024
|
if (fresh.file.revision === info.file.revision)
|
|
310927
311025
|
throw error48;
|
|
310928
311026
|
info = fresh;
|
|
@@ -310931,11 +311029,12 @@ async function pullDriveFile(config2, args2, context4, dependencies) {
|
|
|
310931
311029
|
await temporary.close();
|
|
310932
311030
|
}
|
|
310933
311031
|
if (!saved && attempt === 1)
|
|
310934
|
-
info = await describe4(config2, dependencies,
|
|
311032
|
+
info = await describe4(config2, dependencies, fileTarget, format4, connectionId);
|
|
310935
311033
|
}
|
|
310936
311034
|
if (!saved)
|
|
310937
|
-
throw new ApiError(409, "drive_changed_during_download",
|
|
311035
|
+
throw new ApiError(409, "drive_changed_during_download", `The file kept changing in ${service3} while downloading. Try again later.`);
|
|
310938
311036
|
const link2 = {
|
|
311037
|
+
...provider === "microsoft-365" ? { provider, driveId: info.file.driveId } : {},
|
|
310939
311038
|
fileId: info.file.id,
|
|
310940
311039
|
connectionId: connectionId ?? null,
|
|
310941
311040
|
name: info.file.name,
|
|
@@ -310964,9 +311063,21 @@ function pullResult(config2, context4, target, info, size6, upToDate) {
|
|
|
310964
311063
|
mimeType: info.download.mimeType,
|
|
310965
311064
|
...info.download.exported ? { exportedAs: info.download.format } : {},
|
|
310966
311065
|
...upToDate ? { upToDate: true } : {},
|
|
310967
|
-
file: {
|
|
311066
|
+
file: {
|
|
311067
|
+
id: info.file.id,
|
|
311068
|
+
...info.file.driveId ? { driveId: info.file.driveId } : {},
|
|
311069
|
+
name: info.file.name,
|
|
311070
|
+
mimeType: info.file.mimeType,
|
|
311071
|
+
webViewLink: info.file.webViewLink,
|
|
311072
|
+
revision: info.file.revision
|
|
311073
|
+
}
|
|
310968
311074
|
};
|
|
310969
311075
|
}
|
|
311076
|
+
function sameDriveFile(link2, provider, info) {
|
|
311077
|
+
if (!link2 || (link2.provider ?? "google-workspace") !== provider || link2.fileId !== info.file.id)
|
|
311078
|
+
return false;
|
|
311079
|
+
return provider !== "microsoft-365" || (link2.driveId ?? "") === info.file.driveId;
|
|
311080
|
+
}
|
|
310970
311081
|
async function linkedEntries(config2, context4, requested) {
|
|
310971
311082
|
const links = await readLinks(config2);
|
|
310972
311083
|
const roots = [...allowedRoots(config2), ...await realRoots(config2)];
|
|
@@ -310986,6 +311097,9 @@ async function linkedEntries(config2, context4, requested) {
|
|
|
310986
311097
|
}
|
|
310987
311098
|
return entries3;
|
|
310988
311099
|
}
|
|
311100
|
+
function linkFormat(link2) {
|
|
311101
|
+
return link2.provider === "microsoft-365" || link2.native ? link2.format ?? undefined : undefined;
|
|
311102
|
+
}
|
|
310989
311103
|
async function driveFileStatus(config2, args2, context4, dependencies) {
|
|
310990
311104
|
const entries3 = await linkedEntries(config2, context4, readArgString(args2, "path"));
|
|
310991
311105
|
const files = [];
|
|
@@ -310997,7 +311111,7 @@ async function driveFileStatus(config2, args2, context4, dependencies) {
|
|
|
310997
311111
|
let currentRevision = null;
|
|
310998
311112
|
let note;
|
|
310999
311113
|
try {
|
|
311000
|
-
const info = await describe4(config2, dependencies, link2
|
|
311114
|
+
const info = await describe4(config2, dependencies, linkTarget(link2), linkFormat(link2), link2.connectionId ?? undefined);
|
|
311001
311115
|
currentRevision = info.file.revision;
|
|
311002
311116
|
drive = currentRevision === link2.revision ? "unchanged" : "changed";
|
|
311003
311117
|
} catch (error48) {
|
|
@@ -311008,7 +311122,9 @@ async function driveFileStatus(config2, args2, context4, dependencies) {
|
|
|
311008
311122
|
}
|
|
311009
311123
|
files.push({
|
|
311010
311124
|
path: displayPath(config2, context4, path3),
|
|
311125
|
+
provider: link2.provider ?? "google-workspace",
|
|
311011
311126
|
fileId: link2.fileId,
|
|
311127
|
+
...link2.driveId ? { driveId: link2.driveId } : {},
|
|
311012
311128
|
name: link2.name,
|
|
311013
311129
|
webViewLink: link2.webViewLink,
|
|
311014
311130
|
local,
|
|
@@ -311059,6 +311175,8 @@ async function pushOpenFile(config2, args2, context4, dependencies, path3, handl
|
|
|
311059
311175
|
const link2 = (await readLinks(config2)).links[path3];
|
|
311060
311176
|
if (!link2)
|
|
311061
311177
|
throw new ApiError(409, "not_linked", "That file was not pulled from Drive. Upload it as a new file with drive_upload_file instead.");
|
|
311178
|
+
if (link2.provider === "microsoft-365")
|
|
311179
|
+
return pushMicrosoftFile(config2, args2, context4, dependencies, path3, handle, link2);
|
|
311062
311180
|
if (!DRIVE_ID.test(link2.fileId) || link2.connectionId !== null && !CONNECTION_ID.test(link2.connectionId)) {
|
|
311063
311181
|
throw new ApiError(409, "invalid_link", "The saved Drive link is invalid. Pull the file again before saving.");
|
|
311064
311182
|
}
|
|
@@ -311078,14 +311196,14 @@ async function pushOpenFile(config2, args2, context4, dependencies, path3, handl
|
|
|
311078
311196
|
}
|
|
311079
311197
|
const snapshot = await snapshotForPush(config2, handle, local, dependencies.signal);
|
|
311080
311198
|
try {
|
|
311081
|
-
const remote = await describe4(config2, dependencies, link2
|
|
311199
|
+
const remote = await describe4(config2, dependencies, linkTarget(link2), linkFormat(link2), link2.connectionId ?? undefined);
|
|
311082
311200
|
if (remote.file.id !== link2.fileId)
|
|
311083
311201
|
throw new ApiError(409, "drive_conflict", "The Drive target changed. Pull it again before saving.");
|
|
311084
311202
|
if (mode === "replace" && remote.file.native)
|
|
311085
311203
|
throw new ApiError(400, "native_file_replace_unsupported", "Save this Google file as a copy instead.");
|
|
311086
311204
|
const target = { ...link2, name: remote.file.name, driveMimeType: remote.file.mimeType, native: remote.file.native, parents: remote.file.parents };
|
|
311087
311205
|
const convert = mode === "copy" && target.native && (CONVERTIBLE_FORMATS[target.driveMimeType] ?? []).includes(link2.format ?? "");
|
|
311088
|
-
await confirmDriveTransfer(config2, { action: "push", path: path3, fileId: remote.file.id, name: remote.file.name, webViewLink: remote.file.webViewLink, mode: mode === "copy" ? "copy" : "replace" }, dependencies.signal);
|
|
311206
|
+
await confirmDriveTransfer(config2, { provider: "google-workspace", action: "push", path: path3, fileId: remote.file.id, name: remote.file.name, webViewLink: remote.file.webViewLink, mode: mode === "copy" ? "copy" : "replace" }, dependencies.signal);
|
|
311089
311207
|
await assertStableFolder(config2, dirname15(path3));
|
|
311090
311208
|
await assertSameFile(path3, await handle.stat());
|
|
311091
311209
|
if ((await hashHandle(handle)).sha256 !== local.sha256) {
|
|
@@ -311141,6 +311259,163 @@ async function pushOpenFile(config2, args2, context4, dependencies, path3, handl
|
|
|
311141
311259
|
await snapshot.close();
|
|
311142
311260
|
}
|
|
311143
311261
|
}
|
|
311262
|
+
async function relayProgress(response) {
|
|
311263
|
+
const payload = await response.json().catch(() => null);
|
|
311264
|
+
if (!response.ok) {
|
|
311265
|
+
const code = isRecord28(payload) && typeof payload.error === "string" ? payload.error : "";
|
|
311266
|
+
if (response.status >= 500 || code === "upload_out_of_order")
|
|
311267
|
+
return "uncertain";
|
|
311268
|
+
const message = isRecord28(payload) && typeof payload.message === "string" ? payload.message : `OpenWork Cloud returned HTTP ${response.status}.`;
|
|
311269
|
+
const details = isRecord28(payload) ? Object.fromEntries(Object.entries(payload).filter(([key2]) => key2 === "currentRevision" || key2 === "modifiedTime")) : {};
|
|
311270
|
+
throw new ApiError(response.status, code || "cloud_drive_failed", message, Object.keys(details).length ? details : undefined);
|
|
311271
|
+
}
|
|
311272
|
+
if (isRecord28(payload) && payload.status === "partial" && typeof payload.nextOffset === "number" && Number.isSafeInteger(payload.nextOffset)) {
|
|
311273
|
+
return { status: "partial", nextOffset: payload.nextOffset };
|
|
311274
|
+
}
|
|
311275
|
+
if (isRecord28(payload) && payload.status === "complete" && isRecord28(payload.file) && typeof payload.file.id === "string" && MICROSOFT_ID.test(payload.file.id)) {
|
|
311276
|
+
return { status: "complete", file: payload.file };
|
|
311277
|
+
}
|
|
311278
|
+
return "uncertain";
|
|
311279
|
+
}
|
|
311280
|
+
async function uploadMicrosoftRelayFile(config2, dependencies, input) {
|
|
311281
|
+
const suffix = "/v1/direct-uploads/microsoft-365/drive-upload-sessions/content";
|
|
311282
|
+
const query = { token: input.token };
|
|
311283
|
+
const unconfirmed = () => new ApiError(502, "drive_upload_unconfirmed", "Microsoft did not confirm the upload. Check the file before retrying; no new upload was started.");
|
|
311284
|
+
let offset2 = 0;
|
|
311285
|
+
let recoveries = 0;
|
|
311286
|
+
while (true) {
|
|
311287
|
+
dependencies.signal?.throwIfAborted();
|
|
311288
|
+
const length = Math.min(input.chunkBytes, input.size - offset2);
|
|
311289
|
+
const bytes = new Uint8Array(length);
|
|
311290
|
+
for (let read2 = 0;read2 < length; ) {
|
|
311291
|
+
const part = await input.file.read(bytes, read2, length - read2, offset2 + read2);
|
|
311292
|
+
if (!part.bytesRead)
|
|
311293
|
+
throw new ApiError(409, "file_changed", "The file was truncated during upload.");
|
|
311294
|
+
read2 += part.bytesRead;
|
|
311295
|
+
}
|
|
311296
|
+
let result3;
|
|
311297
|
+
try {
|
|
311298
|
+
result3 = await relayProgress(await denRequest(config2, dependencies, suffix, {
|
|
311299
|
+
method: "PUT",
|
|
311300
|
+
query,
|
|
311301
|
+
headers: { "content-range": `bytes ${offset2}-${offset2 + length - 1}/${input.size}` },
|
|
311302
|
+
bytes
|
|
311303
|
+
}));
|
|
311304
|
+
} catch (error48) {
|
|
311305
|
+
if (!(error48 instanceof ApiError) || error48.code !== "cloud_unreachable")
|
|
311306
|
+
throw error48;
|
|
311307
|
+
result3 = "uncertain";
|
|
311308
|
+
}
|
|
311309
|
+
if (result3 === "uncertain") {
|
|
311310
|
+
if (++recoveries > 2)
|
|
311311
|
+
throw unconfirmed();
|
|
311312
|
+
try {
|
|
311313
|
+
result3 = await relayProgress(await denRequest(config2, dependencies, suffix, { query }));
|
|
311314
|
+
} catch (error48) {
|
|
311315
|
+
if (error48 instanceof ApiError && error48.code === "cloud_unreachable")
|
|
311316
|
+
throw unconfirmed();
|
|
311317
|
+
throw error48;
|
|
311318
|
+
}
|
|
311319
|
+
if (result3 === "uncertain")
|
|
311320
|
+
throw unconfirmed();
|
|
311321
|
+
}
|
|
311322
|
+
if (result3.status === "complete")
|
|
311323
|
+
return result3.file;
|
|
311324
|
+
if (result3.nextOffset < 0 || result3.nextOffset >= input.size)
|
|
311325
|
+
throw unconfirmed();
|
|
311326
|
+
if (result3.nextOffset <= offset2 && ++recoveries > 2)
|
|
311327
|
+
throw new ApiError(502, "drive_upload_unconfirmed", "Microsoft's upload made no progress. Completion is not confirmed; check the file before retrying.");
|
|
311328
|
+
offset2 = result3.nextOffset;
|
|
311329
|
+
}
|
|
311330
|
+
}
|
|
311331
|
+
async function pushMicrosoftFile(config2, args2, context4, dependencies, path3, handle, link2) {
|
|
311332
|
+
if (!MICROSOFT_ID.test(link2.fileId) || link2.driveId && !MICROSOFT_ID.test(link2.driveId) || link2.connectionId !== null && !MICROSOFT_CONNECTION_ID.test(link2.connectionId)) {
|
|
311333
|
+
throw new ApiError(409, "invalid_link", "The saved OneDrive or SharePoint link is invalid. Pull the file again before saving.");
|
|
311334
|
+
}
|
|
311335
|
+
const modeArg = readArgString(args2, "mode");
|
|
311336
|
+
if (modeArg && modeArg !== "replace" && modeArg !== "copy")
|
|
311337
|
+
throw new ApiError(400, "invalid_payload", "mode must be replace or copy.");
|
|
311338
|
+
const converted = link2.format !== null;
|
|
311339
|
+
const mode = modeArg || (converted ? "copy" : "replace");
|
|
311340
|
+
if (mode === "replace" && converted) {
|
|
311341
|
+
throw new ApiError(400, "converted_file_replace_unsupported", "A PDF made from this file cannot replace the original. Push with mode copy to save the PDF next to it.");
|
|
311342
|
+
}
|
|
311343
|
+
if (mode === "replace" && !link2.revision) {
|
|
311344
|
+
throw new ApiError(409, "revision_unknown", "Microsoft reported no revision when this file was pulled, so newer changes could not be detected. Pull it again, or save the edits as a copy.");
|
|
311345
|
+
}
|
|
311346
|
+
const local = await hashHandle(handle);
|
|
311347
|
+
if (local.size > MICROSOFT_DRIVE_TRANSFER_MAX_BYTES) {
|
|
311348
|
+
throw new ApiError(413, "file_too_large", `Saving to OneDrive or SharePoint supports files up to ${MICROSOFT_DRIVE_TRANSFER_MAX_BYTES} bytes.`);
|
|
311349
|
+
}
|
|
311350
|
+
if (mode === "replace" && local.sha256 === link2.sha256) {
|
|
311351
|
+
return { ok: true, unchanged: true, path: displayPath(config2, context4, path3), file: { id: link2.fileId, driveId: link2.driveId ?? "", name: link2.name, webViewLink: link2.webViewLink, revision: link2.revision } };
|
|
311352
|
+
}
|
|
311353
|
+
const snapshot = await snapshotForPush(config2, handle, local, dependencies.signal);
|
|
311354
|
+
try {
|
|
311355
|
+
const remote = await describe4(config2, dependencies, linkTarget(link2), undefined, link2.connectionId ?? undefined);
|
|
311356
|
+
if (remote.file.id !== link2.fileId)
|
|
311357
|
+
throw new ApiError(409, "drive_conflict", "The OneDrive or SharePoint target changed. Pull it again before saving.");
|
|
311358
|
+
await confirmDriveTransfer(config2, { provider: "microsoft-365", action: "push", path: path3, fileId: remote.file.id, name: remote.file.name, webViewLink: remote.file.webViewLink, mode: mode === "copy" ? "copy" : "replace" }, dependencies.signal);
|
|
311359
|
+
await assertStableFolder(config2, dirname15(path3));
|
|
311360
|
+
await assertSameFile(path3, await handle.stat());
|
|
311361
|
+
if ((await hashHandle(handle)).sha256 !== local.sha256) {
|
|
311362
|
+
throw new ApiError(409, "local_changes", "The local file changed while confirmation was open. Nothing was uploaded; review the edits and save again.");
|
|
311363
|
+
}
|
|
311364
|
+
const extension = converted ? ".pdf" : extname2(remote.file.name);
|
|
311365
|
+
const stem = remote.file.name.slice(0, remote.file.name.length - extname2(remote.file.name).length);
|
|
311366
|
+
const requestedName = readArgString(args2, "name").replace(/[/\\\x00-\x1f\x7f]/g, "_").slice(0, 255);
|
|
311367
|
+
const name = requestedName || `${stem} (edited)${extension}`;
|
|
311368
|
+
const driveId = remote.file.driveId || link2.driveId;
|
|
311369
|
+
const session2 = await denJson(config2, dependencies, "/v1/direct-uploads/microsoft-365/drive-upload-sessions", {
|
|
311370
|
+
method: "POST",
|
|
311371
|
+
body: {
|
|
311372
|
+
size: local.size,
|
|
311373
|
+
...link2.connectionId ? { connectionId: link2.connectionId } : {},
|
|
311374
|
+
...driveId ? { driveId } : {},
|
|
311375
|
+
...mode === "replace" ? { itemId: link2.fileId, baseRevision: link2.revision } : { name, conflictBehavior: "rename", ...remote.file.parents[0] ? { folderId: remote.file.parents[0] } : {} }
|
|
311376
|
+
}
|
|
311377
|
+
});
|
|
311378
|
+
const chunkBytes = session2.chunkSize;
|
|
311379
|
+
if (typeof session2.uploadToken !== "string" || session2.size !== local.size || typeof chunkBytes !== "number" || !Number.isSafeInteger(chunkBytes) || chunkBytes < 1 || chunkBytes > MICROSOFT_DRIVE_UPLOAD_CHUNK_BYTES || chunkBytes % (320 * 1024) !== 0) {
|
|
311380
|
+
throw new ApiError(502, "invalid_upload_session", "OpenWork Cloud returned an invalid upload session.");
|
|
311381
|
+
}
|
|
311382
|
+
const file2 = await uploadMicrosoftRelayFile(config2, dependencies, { token: session2.uploadToken, file: snapshot, size: local.size, chunkBytes });
|
|
311383
|
+
const revision = stringOrNull(file2.eTag);
|
|
311384
|
+
const savedName = typeof file2.name === "string" && file2.name ? file2.name : name;
|
|
311385
|
+
const savedDriveId = typeof file2.driveId === "string" && MICROSOFT_ID.test(file2.driveId) ? file2.driveId : driveId ?? "";
|
|
311386
|
+
const webViewLink = typeof file2.webUrl === "string" && file2.webUrl ? file2.webUrl : mode === "replace" ? link2.webViewLink : null;
|
|
311387
|
+
const driveMimeType = typeof file2.mimeType === "string" && file2.mimeType ? file2.mimeType : link2.driveMimeType;
|
|
311388
|
+
await withLinks(config2, (current2) => {
|
|
311389
|
+
current2.links[path3] = {
|
|
311390
|
+
...link2,
|
|
311391
|
+
provider: "microsoft-365",
|
|
311392
|
+
fileId: file2.id,
|
|
311393
|
+
driveId: savedDriveId,
|
|
311394
|
+
name: savedName,
|
|
311395
|
+
driveMimeType,
|
|
311396
|
+
native: false,
|
|
311397
|
+
format: null,
|
|
311398
|
+
revision,
|
|
311399
|
+
md5Checksum: null,
|
|
311400
|
+
sha256: local.sha256,
|
|
311401
|
+
size: local.size,
|
|
311402
|
+
webViewLink,
|
|
311403
|
+
pushedAt: new Date().toISOString()
|
|
311404
|
+
};
|
|
311405
|
+
});
|
|
311406
|
+
const replaces = isRecord28(session2.replaces) ? session2.replaces : null;
|
|
311407
|
+
return {
|
|
311408
|
+
ok: true,
|
|
311409
|
+
mode,
|
|
311410
|
+
path: displayPath(config2, context4, path3),
|
|
311411
|
+
size: local.size,
|
|
311412
|
+
file: { id: file2.id, driveId: savedDriveId, name: savedName, mimeType: driveMimeType, webViewLink, revision },
|
|
311413
|
+
...mode === "replace" ? { previousRevision: stringOrNull(replaces?.previousRevision) } : { copiedFrom: link2.fileId }
|
|
311414
|
+
};
|
|
311415
|
+
} finally {
|
|
311416
|
+
await snapshot.close();
|
|
311417
|
+
}
|
|
311418
|
+
}
|
|
311144
311419
|
async function callDriveFileAction(config2, action, args2, context4, dependencies = {}) {
|
|
311145
311420
|
if (action === "drive_pull_file")
|
|
311146
311421
|
return pullDriveFile(config2, args2, context4, dependencies);
|
|
@@ -318752,12 +319027,14 @@ async function uiBridgeRequest(path3, options = {}) {
|
|
|
318752
319027
|
// src/opencode-plugins/drive-file-tools.ts
|
|
318753
319028
|
init_zod();
|
|
318754
319029
|
var DRIVE_FILE_ACTIONS = ["drive_pull_file", "drive_file_status", "drive_push_file"];
|
|
318755
|
-
var connectionId = exports_external.string().regex(/^(google-workspace|emc_[A-Za-z0-9]+)$/).optional().describe("Selected Google Workspace connection; omit for the default. Unavailable selections never fall back to another account.");
|
|
319030
|
+
var connectionId = exports_external.string().regex(/^(google-workspace|microsoft-365|emc_[A-Za-z0-9]+)$/).optional().describe("Selected Google Workspace or Microsoft 365 connection; omit for the default. Unavailable selections never fall back to another account.");
|
|
318756
319031
|
var workspacePath = exports_external.string().min(1).max(4096);
|
|
318757
319032
|
var drivePullFileArgs = exports_external.object({
|
|
318758
|
-
fileId: exports_external.string().min(1).max(2048).describe("Drive file ID or link."),
|
|
319033
|
+
fileId: exports_external.string().min(1).max(2048).describe("Google Drive file ID or link, or a OneDrive, SharePoint or Teams file link or item id."),
|
|
319034
|
+
driveId: exports_external.string().min(1).max(512).optional().describe("Microsoft 365 only: the driveId that came with the item id from a search or folder listing."),
|
|
319035
|
+
provider: exports_external.enum(["google-workspace", "microsoft-365"]).optional().describe("Only needed for a Microsoft item id without driveId; links and driveId identify Microsoft 365 files."),
|
|
318759
319036
|
path: workspacePath.optional().describe("Workspace path to save to. Defaults to drive/<file name>."),
|
|
318760
|
-
format: exports_external.string().regex(/^[a-z]{2,5}$/).optional().describe("Docs, Sheets, Slides and Drawings
|
|
319037
|
+
format: exports_external.string().regex(/^[a-z]{2,5}$/).optional().describe("Docs, Sheets, Slides and Drawings: xlsx, csv (first tab only), docx, md, txt, pptx, pdf, png or svg. OneDrive and SharePoint: pdf converts an Office file."),
|
|
318761
319038
|
connectionId,
|
|
318762
319039
|
overwrite: exports_external.boolean().optional().describe("Replace a local copy even if it has edits not in Drive. Asks the person first.")
|
|
318763
319040
|
}).strict();
|
|
@@ -318766,7 +319043,7 @@ var driveFileStatusArgs = exports_external.object({
|
|
|
318766
319043
|
}).strict();
|
|
318767
319044
|
var drivePushFileArgs = exports_external.object({
|
|
318768
319045
|
path: workspacePath.describe("Workspace path of a pulled file."),
|
|
318769
|
-
mode: exports_external.enum(["replace", "copy"]).optional().describe("replace (default for stored files) updates the same
|
|
319046
|
+
mode: exports_external.enum(["replace", "copy"]).optional().describe("replace (default for stored files) updates the same file; copy saves a new file next to it."),
|
|
318770
319047
|
name: exports_external.string().min(1).max(255).optional().describe("Name for a copy.")
|
|
318771
319048
|
}).strict();
|
|
318772
319049
|
function isRecord41(value3) {
|
|
@@ -318781,7 +319058,7 @@ async function askPermission(context4, permission, patterns, metadata) {
|
|
|
318781
319058
|
function createDriveFileTools(call) {
|
|
318782
319059
|
return {
|
|
318783
319060
|
drive_pull_file: {
|
|
318784
|
-
description: "Save a Google Drive file into the workspace and return its path and revision, never its content. Use it to analyze or edit Office, PDF, CSV or any large file with shell tools. Docs, Sheets and Slides arrive as docx, xlsx and pptx unless format says otherwise.",
|
|
319061
|
+
description: "Save a Google Drive, OneDrive or SharePoint file into the workspace and return its path and revision, never its content. Use it to analyze or edit Office, PDF, CSV or any large file with shell tools. Docs, Sheets and Slides arrive as docx, xlsx and pptx unless format says otherwise.",
|
|
318785
319062
|
args: drivePullFileArgs.shape,
|
|
318786
319063
|
async execute(rawArgs, context4) {
|
|
318787
319064
|
const args2 = drivePullFileArgs.parse(rawArgs ?? {});
|
|
@@ -318791,14 +319068,14 @@ function createDriveFileTools(call) {
|
|
|
318791
319068
|
}
|
|
318792
319069
|
},
|
|
318793
319070
|
drive_file_status: {
|
|
318794
|
-
description: "For files pulled with drive_pull_file, report whether the local copy has edits not saved
|
|
319071
|
+
description: "For files pulled with drive_pull_file, report whether the local copy has edits not saved back and whether the file changed in Drive, OneDrive or SharePoint since the pull.",
|
|
318795
319072
|
args: driveFileStatusArgs.shape,
|
|
318796
319073
|
async execute(rawArgs, context4) {
|
|
318797
319074
|
return JSON.stringify(await call("drive_file_status", driveFileStatusArgs.parse(rawArgs ?? {}), context4), null, 2);
|
|
318798
319075
|
}
|
|
318799
319076
|
},
|
|
318800
319077
|
drive_push_file: {
|
|
318801
|
-
description: "Save a pulled file back to
|
|
319078
|
+
description: "Save a pulled file back to where it came from when the person asks. Asks the person first. Stored files, including Office files in OneDrive and SharePoint, are replaced in place as a new version; Google Docs, Sheets and Slides and PDF conversions are saved as a new file next to the original. Returns drive_conflict, and changes nothing, when someone changed the file since the pull: pull it again and reapply the edits, or save a copy.",
|
|
318802
319079
|
args: drivePushFileArgs.shape,
|
|
318803
319080
|
async execute(rawArgs, context4) {
|
|
318804
319081
|
const args2 = drivePushFileArgs.parse(rawArgs ?? {});
|
|
@@ -323877,7 +324154,7 @@ import { mkdir as mkdir19, rename as rename13, rm as rm18, writeFile as writeFil
|
|
|
323877
324154
|
import { join as join36 } from "node:path";
|
|
323878
324155
|
// ../../constants.json
|
|
323879
324156
|
var constants_default = {
|
|
323880
|
-
opencodeVersion: "v1.18.
|
|
324157
|
+
opencodeVersion: "v1.18.33",
|
|
323881
324158
|
opencodeV2Version: "2.0.26"
|
|
323882
324159
|
};
|
|
323883
324160
|
|
|
@@ -325254,7 +325531,7 @@ function createEngineV2Preview(options) {
|
|
|
325254
325531
|
// package.json
|
|
325255
325532
|
var package_default = {
|
|
325256
325533
|
name: "openwork-server",
|
|
325257
|
-
version: "0.18.
|
|
325534
|
+
version: "0.18.62",
|
|
325258
325535
|
description: "Filesystem-backed API for OpenWork remote clients",
|
|
325259
325536
|
type: "module",
|
|
325260
325537
|
bin: {
|
|
@@ -332809,7 +333086,7 @@ function readInstalledOpencodeVersion() {
|
|
|
332809
333086
|
// package.json
|
|
332810
333087
|
var package_default2 = {
|
|
332811
333088
|
name: "openwork-server",
|
|
332812
|
-
version: "0.18.
|
|
333089
|
+
version: "0.18.62",
|
|
332813
333090
|
description: "Filesystem-backed API for OpenWork remote clients",
|
|
332814
333091
|
type: "module",
|
|
332815
333092
|
bin: {
|
|
@@ -332900,7 +333177,7 @@ var package_default2 = {
|
|
|
332900
333177
|
};
|
|
332901
333178
|
// ../../constants.json
|
|
332902
333179
|
var constants_default2 = {
|
|
332903
|
-
opencodeVersion: "v1.18.
|
|
333180
|
+
opencodeVersion: "v1.18.33",
|
|
332904
333181
|
opencodeV2Version: "2.0.26"
|
|
332905
333182
|
};
|
|
332906
333183
|
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as p,r as u,d as a}from"./chunk-SVP7TREG-
|
|
1
|
+
import{g as p,r as u,d as a}from"./chunk-SVP7TREG-B65ta9aQ.js";import{p as f}from"./chunk-JWPE2WC7-B34hvYk7.js";import{_ as n,l as o}from"./mermaid.core-FKm3Akes.js";import{M as c,b as d}from"./cynefin-OW5HDTMX-CAcz2tHt.js";import"./app-_2KkkZIM.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
|