@xuda.io/drive_module 1.1.1498 → 1.1.1499

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/index.mjs CHANGED
@@ -4,6 +4,7 @@ import { rimraf } from 'rimraf';
4
4
  import fse from 'fs-extra';
5
5
  import unzipper from 'unzipper';
6
6
  import fs from 'fs';
7
+ import os from 'os';
7
8
  import tesseract from 'node-tesseract-ocr';
8
9
  import countryLanguage from 'country-language';
9
10
  import url from 'url';
@@ -3763,6 +3764,106 @@ export const read_user_drive_folder = async (req) => {
3763
3764
  }
3764
3765
  };
3765
3766
 
3767
+ // fetch_drive_file_to_tmp: copy ONE drive file's bytes onto this box as a temp
3768
+ // file so a server-side document generator can open it, edit it and save the
3769
+ // result back as a new drive file. This is what lets the office plugins (pptx,
3770
+ // docx, xlsx) modify a deck/document the user already has instead of only
3771
+ // creating new ones: user + workspace files live in object storage, so there is
3772
+ // otherwise no path on disk to hand to a parser.
3773
+ //
3774
+ // The file is resolved by drive doc id (drv_...) or by its drive path
3775
+ // (/Folder/name.ext). The caller owns the temp file and must unlink it.
3776
+ //
3777
+ // req: { uid, app_id?, drive_type: 'user'|'workspace'|'studio', file }
3778
+ // -> { tmp_path, originalname, file_path, doc_id, size, mime, drive_type }
3779
+ export const fetch_drive_file_to_tmp = async (req) => {
3780
+ try {
3781
+ const { uid, app_id, drive_type = 'user' } = req || {};
3782
+ const file_ref = String(req?.file || req?.file_id || req?.file_path || '').trim();
3783
+
3784
+ if (!uid) return { code: -1, data: 'uid required' };
3785
+ if (!file_ref) return { code: -1, data: 'file required' };
3786
+ validate_drive_type(drive_type);
3787
+
3788
+ const write_tmp = async (buffer, name) => {
3789
+ const tmp_path = path.join(os.tmpdir(), `xuda_drive_${await _common.xuda_get_uuid('tmp')}${path.extname(name) || ''}`);
3790
+ await fs.promises.writeFile(tmp_path, buffer);
3791
+ return tmp_path;
3792
+ };
3793
+
3794
+ // studio drive is plain files on this box, addressed by their relative path.
3795
+ if (drive_type === 'studio') {
3796
+ const ref = await _common.get_project_app_id(app_id, true);
3797
+ const rel = file_ref.replace(/^\/+/, '');
3798
+ const full = path.join(_conf.studio_drive_path, ref, rel);
3799
+ // Contain the read inside the app's own studio folder.
3800
+ const root = path.join(_conf.studio_drive_path, ref);
3801
+ if (!path.resolve(full).startsWith(path.resolve(root) + path.sep)) {
3802
+ return { code: -1, data: 'file_path unauthorized' };
3803
+ }
3804
+ if (!(await fs_module.file_exists(full))) return { code: -1, data: `file not found: ${file_ref}` };
3805
+ const buffer = await fs.promises.readFile(full);
3806
+ const originalname = path.basename(full);
3807
+ return {
3808
+ code: 1,
3809
+ data: {
3810
+ tmp_path: await write_tmp(buffer, originalname),
3811
+ originalname,
3812
+ file_path: path.posix.join('/', path.dirname(rel) === '.' ? '' : path.dirname(rel)),
3813
+ doc_id: rel,
3814
+ size: buffer.length,
3815
+ mime: _drive_content_type_for(originalname),
3816
+ drive_type,
3817
+ },
3818
+ };
3819
+ }
3820
+
3821
+ const project_id = drive_type === 'user' ? await get_account_default_project_id(uid) : await _common.get_project_app_id(app_id);
3822
+
3823
+ // Either the doc id itself, or a /folder/name.ext path within the drive.
3824
+ const by_id = /^drv_/.test(file_ref);
3825
+ const selector = { docType: `${drive_type}_drive`, type: 'file', stat: 3 };
3826
+ if (by_id) {
3827
+ selector._id = file_ref;
3828
+ } else {
3829
+ const with_slash = file_ref.startsWith('/') ? file_ref : `/${file_ref}`;
3830
+ const dir = path.posix.dirname(with_slash);
3831
+ selector.file_path = dir === '.' ? '/' : dir;
3832
+ selector.originalname = path.posix.basename(with_slash);
3833
+ }
3834
+
3835
+ const find_ret = await db_module.find_app_couch_query(project_id, { selector, limit: 1 });
3836
+ const doc = find_ret?.docs?.[0];
3837
+ if (!doc) return { code: -1, data: `file not found: ${file_ref}` };
3838
+
3839
+ const region = _pick_file_region(doc);
3840
+ const b = (region && doc.bucket?.[region]) || {};
3841
+ const Bucket = b.Bucket || b.bucket || (region && _conf.storage_bucket?.[region]?.name);
3842
+ const Key = b.Key || b.key;
3843
+ const s3 = region ? _drive_s3_for(region) : null;
3844
+ if (!s3 || !Bucket || !Key) return { code: -1, data: 'file bytes unavailable' };
3845
+
3846
+ const obj = await s3.send(new GetObjectCommand({ Bucket, Key }));
3847
+ const buffer = await _stream_to_buffer(obj.Body);
3848
+ const originalname = doc.originalname || path.basename(Key);
3849
+
3850
+ return {
3851
+ code: 1,
3852
+ data: {
3853
+ tmp_path: await write_tmp(buffer, originalname),
3854
+ originalname,
3855
+ file_path: doc.file_path || '/',
3856
+ doc_id: doc._id,
3857
+ size: buffer.length,
3858
+ mime: doc.mime || _drive_content_type_for(originalname),
3859
+ drive_type,
3860
+ },
3861
+ };
3862
+ } catch (err) {
3863
+ return { code: -400, data: err.message };
3864
+ }
3865
+ };
3866
+
3766
3867
  // put_site_files — snapshot a set of static-site files into ONE region's
3767
3868
  // Spaces bucket under sites/{site_id}/{version}/{path}, public-read. Each
3768
3869
  // deploy writes a fresh immutable version directory, so older versions stay
package/index_ms.mjs CHANGED
@@ -197,6 +197,10 @@ export const read_user_drive_folder = async function (...args) {
197
197
  return await broker.send_to_queue("read_user_drive_folder", ...args);
198
198
  };
199
199
 
200
+ export const fetch_drive_file_to_tmp = async function (...args) {
201
+ return await broker.send_to_queue("fetch_drive_file_to_tmp", ...args);
202
+ };
203
+
200
204
  export const put_site_files = async function (...args) {
201
205
  return await broker.send_to_queue("put_site_files", ...args);
202
206
  };
package/index_msa.mjs CHANGED
@@ -197,6 +197,10 @@ export const read_user_drive_folder = function (...args) {
197
197
  broker.send_to_queue_async("read_user_drive_folder", ...args);
198
198
  };
199
199
 
200
+ export const fetch_drive_file_to_tmp = function (...args) {
201
+ broker.send_to_queue_async("fetch_drive_file_to_tmp", ...args);
202
+ };
203
+
200
204
  export const put_site_files = function (...args) {
201
205
  broker.send_to_queue_async("put_site_files", ...args);
202
206
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xuda.io/drive_module",
3
- "version": "1.1.1498",
3
+ "version": "1.1.1499",
4
4
  "description": "Xuda Drive Server Module",
5
5
  "main": "index.mjs",
6
6
  "dependencies": {