@jd-data-limited/easy-fm 1.3.0 → 2.0.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 CHANGED
@@ -68,7 +68,7 @@ let range_request = layout.records.range()
68
68
  range_request.setOffset(50) // Starting from the 50th record...
69
69
  range_request.setLimit(100) // Fetch 100 records
70
70
 
71
- let records = await range_request.run()
71
+ let records = await range_request.fetch()
72
72
  console.log(records)
73
73
  ```
74
74
 
package/dist/index.js CHANGED
@@ -15,6 +15,13 @@ import fetch, { File, FormData } from 'node-fetch';
15
15
  import { EventEmitter } from "events";
16
16
  // @ts-ignore
17
17
  import * as moment from "moment";
18
+ import * as http from "http";
19
+ import * as https from "https";
20
+ export var DOWNLOAD_MODES;
21
+ (function (DOWNLOAD_MODES) {
22
+ DOWNLOAD_MODES[DOWNLOAD_MODES["Stream"] = 0] = "Stream";
23
+ DOWNLOAD_MODES[DOWNLOAD_MODES["Buffer"] = 1] = "Buffer";
24
+ })(DOWNLOAD_MODES || (DOWNLOAD_MODES = {}));
18
25
  // @ts-ignore
19
26
  const errs = [
20
27
  {
@@ -1081,6 +1088,7 @@ export default class FMHost {
1081
1088
  export class Database extends EventEmitter {
1082
1089
  constructor(host, conn) {
1083
1090
  super();
1091
+ this.cookies = {};
1084
1092
  this.host = host;
1085
1093
  this.name = conn.database;
1086
1094
  this.connection_details = conn;
@@ -1171,6 +1179,12 @@ export class Database extends EventEmitter {
1171
1179
  options.headers["authorization"] = "Bearer " + this._token;
1172
1180
  options.rejectUnauthorized = this.host.verify;
1173
1181
  let _fetch = yield fetch(url, options);
1182
+ if (_fetch.headers.get('set-cookie')) {
1183
+ for (let cookie of _fetch.headers.get('set-cookie')) {
1184
+ let cookie_split = cookie.split("=");
1185
+ this.cookies[cookie_split[0]] = cookie_split[1];
1186
+ }
1187
+ }
1174
1188
  let data = yield _fetch.json();
1175
1189
  // console.log(data.messages[0])
1176
1190
  if (data.messages[0].code == 952 && autoRelogin) {
@@ -1182,7 +1196,7 @@ export class Database extends EventEmitter {
1182
1196
  });
1183
1197
  }
1184
1198
  getLayout(name) {
1185
- return new layout(this, name);
1199
+ return new Layout(this, name);
1186
1200
  }
1187
1201
  setGlobals(globalFields) {
1188
1202
  // console.log({globalFields})
@@ -1210,10 +1224,44 @@ export class Database extends EventEmitter {
1210
1224
  _tokenExpired() {
1211
1225
  this.emit("token_expired");
1212
1226
  }
1227
+ streamContainer(field, url) {
1228
+ return new Promise((resolve, reject) => {
1229
+ if (field.metadata.result !== "container") {
1230
+ reject("Cannot stream the field " + field.id + " as it is not a container");
1231
+ return;
1232
+ }
1233
+ if (!url || typeof url !== "string") {
1234
+ reject("Container is empty, or has invalid value");
1235
+ return;
1236
+ }
1237
+ let headers = {};
1238
+ if (Object.keys(this.cookies).length !== 0) {
1239
+ headers["Cookie"] = Object.keys(this.cookies)
1240
+ .map(key => {
1241
+ return key + "=" + this.cookies[key];
1242
+ })
1243
+ .join("; ");
1244
+ }
1245
+ // Automatically switch between the http and https modules, based on which is needed
1246
+ (url.startsWith("https") ? https : http).get(url, {
1247
+ headers
1248
+ }, (res) => {
1249
+ // Check for the 'set-cookie' header. If it exists, remember it and strip it for better security.
1250
+ if (res.headers['set-cookie']) {
1251
+ for (let cookie of res.headers['set-cookie']) {
1252
+ let cookie_split = cookie.split("=");
1253
+ this.cookies[cookie_split[0]] = cookie_split[1];
1254
+ }
1255
+ res.headers['set-cookie'] = null;
1256
+ }
1257
+ resolve(res);
1258
+ });
1259
+ });
1260
+ }
1213
1261
  }
1214
- class layout {
1262
+ export class Layout {
1215
1263
  constructor(database, name) {
1216
- this.records = new layoutRecordManager(this);
1264
+ this.records = new LayourRecordManager(this);
1217
1265
  this.database = database;
1218
1266
  this.name = name;
1219
1267
  }
@@ -1275,7 +1323,7 @@ class layout {
1275
1323
  });
1276
1324
  }
1277
1325
  }
1278
- class layoutRecordManager {
1326
+ class LayourRecordManager {
1279
1327
  constructor(layout) {
1280
1328
  this.layout = layout;
1281
1329
  }
@@ -1309,14 +1357,14 @@ class layoutRecordManager {
1309
1357
  });
1310
1358
  });
1311
1359
  }
1312
- range() {
1313
- return new recordGetRange(this.layout);
1360
+ range(start = 0, limit = 100) {
1361
+ return new RecordGetRange(this.layout, start, limit);
1314
1362
  }
1315
1363
  find() {
1316
- return new find(this.layout);
1364
+ return new Find(this.layout);
1317
1365
  }
1318
1366
  }
1319
- class RecordBase extends EventEmitter {
1367
+ export class RecordBase extends EventEmitter {
1320
1368
  constructor(layout, recordId, modId = recordId) {
1321
1369
  super();
1322
1370
  this.portals = [];
@@ -1332,7 +1380,7 @@ class RecordBase extends EventEmitter {
1332
1380
  }
1333
1381
  processPortalData(portalData) {
1334
1382
  for (let item of Object.keys(portalData)) {
1335
- let _portal = new portal(this, item);
1383
+ let _portal = new Portal(this, item);
1336
1384
  _portal.records = portalData[item].map(item => {
1337
1385
  let fieldData = item;
1338
1386
  delete fieldData.recordId;
@@ -1344,7 +1392,7 @@ class RecordBase extends EventEmitter {
1344
1392
  }
1345
1393
  processFieldData(fieldData) {
1346
1394
  return Object.keys(fieldData).map(item => {
1347
- let _field = new field(this, item, fieldData[item]);
1395
+ let _field = new Field(this, item, fieldData[item]);
1348
1396
  if (!!fieldData[item]) {
1349
1397
  if (_field.metadata.result === "timeStamp") {
1350
1398
  // @ts-ignore
@@ -1561,7 +1609,7 @@ class RecordBase extends EventEmitter {
1561
1609
  return obj;
1562
1610
  }
1563
1611
  }
1564
- class LayoutRecord extends RecordBase {
1612
+ export class LayoutRecord extends RecordBase {
1565
1613
  constructor(layout, recordId, modId = recordId, fieldData = {}, portalData = null) {
1566
1614
  super(layout, recordId, modId);
1567
1615
  this.fields = this.processFieldData(fieldData);
@@ -1571,7 +1619,7 @@ class LayoutRecord extends RecordBase {
1571
1619
  }
1572
1620
  }
1573
1621
  }
1574
- class field {
1622
+ export class Field {
1575
1623
  constructor(record, id, contents) {
1576
1624
  this.record = record;
1577
1625
  this.id = id;
@@ -1648,6 +1696,7 @@ class field {
1648
1696
  }
1649
1697
  }
1650
1698
  get value() {
1699
+ // if (this.metadata.result === "container") throw "Use await field.stream() to get the contents of a container field, instead of field.value"
1651
1700
  return this._value;
1652
1701
  }
1653
1702
  upload(buffer, filename, mime) {
@@ -1675,20 +1724,42 @@ class field {
1675
1724
  });
1676
1725
  }));
1677
1726
  }
1678
- download() {
1727
+ download(mode = DOWNLOAD_MODES.Stream) {
1679
1728
  return new Promise((resolve, reject) => {
1680
- fetch(this.value.toString())
1681
- .then(res => resolve(res));
1729
+ this.record.layout.database.streamContainer(this, this._value)
1730
+ .then(stream => {
1731
+ if (mode === DOWNLOAD_MODES.Stream) {
1732
+ resolve(stream);
1733
+ return;
1734
+ }
1735
+ let body = [];
1736
+ stream.on("data", chunk => {
1737
+ body.push(chunk);
1738
+ });
1739
+ stream.on("error", (e) => {
1740
+ reject(e);
1741
+ });
1742
+ stream.on("end", () => {
1743
+ resolve({
1744
+ buffer: Buffer.concat(body),
1745
+ mime: stream.headers["content-type"],
1746
+ request: stream
1747
+ });
1748
+ });
1749
+ })
1750
+ .catch(e => {
1751
+ reject(e);
1752
+ });
1682
1753
  });
1683
1754
  }
1684
1755
  }
1685
- class portal {
1756
+ export class Portal {
1686
1757
  constructor(record, name) {
1687
1758
  this.record = record;
1688
1759
  this.name = name;
1689
1760
  }
1690
1761
  }
1691
- class PortalRecord extends RecordBase {
1762
+ export class PortalRecord extends RecordBase {
1692
1763
  constructor(record, portal, recordId, modId = recordId, fieldData = {}) {
1693
1764
  super(record.layout, recordId, modId);
1694
1765
  this.portal = portal;
@@ -1712,7 +1783,7 @@ class PortalRecord extends RecordBase {
1712
1783
  return res;
1713
1784
  }
1714
1785
  }
1715
- class recordGetOperation {
1786
+ export class RecordGetOperation {
1716
1787
  constructor(layout) {
1717
1788
  this.limit = 100;
1718
1789
  this.limitPortals = [];
@@ -1752,11 +1823,13 @@ class recordGetOperation {
1752
1823
  return this;
1753
1824
  }
1754
1825
  }
1755
- class recordGetRange extends recordGetOperation {
1756
- constructor(layout) {
1826
+ export class RecordGetRange extends RecordGetOperation {
1827
+ constructor(layout, start = 0, limit = 100) {
1757
1828
  super(layout);
1829
+ this.setOffset(start);
1830
+ this.setLimit(limit);
1758
1831
  }
1759
- generateQueryParams() {
1832
+ generateQueryParams(extraBody = {}) {
1760
1833
  let params = [];
1761
1834
  if (this.limit !== 100)
1762
1835
  params.push("_limit=" + this.limit);
@@ -1773,15 +1846,38 @@ class recordGetRange extends recordGetOperation {
1773
1846
  params.push("_limit." + item.portal.name.replace(/[^0-9A-z]/g, "") + "=" + item.limit);
1774
1847
  }
1775
1848
  }
1849
+ if (extraBody.scripts) {
1850
+ if (extraBody.scripts.prerequest) {
1851
+ params.push("script.prerequest=" + extraBody.scripts.prerequest.name);
1852
+ if (extraBody.scripts.prerequest.param)
1853
+ params.push("script.prerequest.param=" + extraBody.scripts.prerequest.param);
1854
+ }
1855
+ if (extraBody.scripts.presort) {
1856
+ params.push("script.presort=" + extraBody.scripts.presort.name);
1857
+ if (extraBody.scripts.presort.param)
1858
+ params.push("script.presort.param=" + extraBody.scripts.presort.param);
1859
+ }
1860
+ if (extraBody.scripts.after) {
1861
+ params.push("script=" + extraBody.scripts.after.name);
1862
+ if (extraBody.scripts.after.param)
1863
+ params.push("script.param=" + extraBody.scripts.after.param);
1864
+ }
1865
+ }
1776
1866
  if (params.length === 0)
1777
1867
  return "";
1778
1868
  return "?" + params.join("&");
1779
1869
  }
1780
- run() {
1870
+ /**
1871
+ * @deprecated in favour of .fetch()
1872
+ */
1873
+ run(extraBody = {}) {
1874
+ return this.fetch(extraBody);
1875
+ }
1876
+ fetch(extraBody = {}) {
1781
1877
  return new Promise((resolve, reject) => {
1782
1878
  // console.log(this.#toObject())
1783
1879
  this.layout.getLayoutMeta().then(() => {
1784
- return this.layout.database.apiRequest(`${this.layout.endpoint}/records${this.generateQueryParams()}`, {
1880
+ return this.layout.database.apiRequest(`${this.layout.endpoint}/records${this.generateQueryParams(extraBody)}`, {
1785
1881
  method: "GET"
1786
1882
  });
1787
1883
  })
@@ -1806,7 +1902,7 @@ class recordGetRange extends recordGetOperation {
1806
1902
  });
1807
1903
  }
1808
1904
  }
1809
- class find extends recordGetOperation {
1905
+ export class Find extends RecordGetOperation {
1810
1906
  constructor(layout) {
1811
1907
  super(layout);
1812
1908
  this.queries = [];
@@ -1840,10 +1936,13 @@ class find extends recordGetOperation {
1840
1936
  this.queries.push(item);
1841
1937
  return this;
1842
1938
  }
1843
- find() {
1844
- return this.run();
1845
- }
1939
+ /**
1940
+ * @deprecated in favour of .fetch()
1941
+ */
1846
1942
  run() {
1943
+ return this.fetch();
1944
+ }
1945
+ fetch() {
1847
1946
  return new Promise((resolve, reject) => {
1848
1947
  // console.log(this.#toObject())
1849
1948
  this.layout.getLayoutMeta()
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@jd-data-limited/easy-fm",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "dependencies": {
5
5
  "@types/btoa": "^1.2.3",
6
6
  "@types/events": "^3.0.0",
7
7
  "moment": "^2.29.4",
8
- "node-fetch": "^3.3.0",
8
+ "node-fetch": "3.2.8",
9
9
  "typescript": "^4.9.4"
10
10
  },
11
11
  "type": "module",