@jd-data-limited/easy-fm 3.2.2 → 3.2.4

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/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@jd-data-limited/easy-fm",
3
- "version": "3.2.2",
3
+ "version": "3.2.4",
4
4
  "dependencies": {
5
5
  "@types/btoa": "^1.2.3",
6
6
  "@types/events": "^3.0.0",
7
+ "follow-redirects": "^1.15.3",
7
8
  "moment": "^2.29.4",
8
9
  "node-fetch": "3.2.8",
9
10
  "typescript": "^5.2.2",
@@ -3,6 +3,7 @@ import { EventEmitter } from "events";
3
3
  import { Request } from "node-fetch";
4
4
  import { LayoutInterface } from "../layouts/layoutInterface.js";
5
5
  import { Layout } from "../layouts/layout.js";
6
+ import { http } from "follow-redirects";
6
7
  import { databaseOptionsWithExternalSources, DatabaseStructure, Script } from "../types.js";
7
8
  import { HostBase } from "./HostBase.js";
8
9
  import { DatabaseBase } from "./databaseBase";
@@ -24,5 +25,5 @@ export declare class Database<T extends DatabaseStructure> extends EventEmitter
24
25
  setGlobals(globalFields: any): Promise<void>;
25
26
  script(name: any, parameter?: string): Script;
26
27
  _tokenExpired(): void;
27
- streamContainer(url: any): Promise<import("node-fetch").Response>;
28
+ streamContainer(field: any, url: any): Promise<http.IncomingMessage>;
28
29
  }
@@ -15,6 +15,7 @@ import fetch from "node-fetch";
15
15
  import { generateAuthorizationHeaders } from "./generateAuthorizationHeaders.js";
16
16
  import { FMError } from "../FMError.js";
17
17
  import { Layout } from "../layouts/layout.js";
18
+ import { http, https } from "follow-redirects";
18
19
  export class Database extends EventEmitter {
19
20
  constructor(host, conn) {
20
21
  super();
@@ -156,8 +157,16 @@ export class Database extends EventEmitter {
156
157
  _tokenExpired() {
157
158
  this.emit("token_expired");
158
159
  }
159
- streamContainer(url) {
160
- return __awaiter(this, void 0, void 0, function* () {
160
+ streamContainer(field, url) {
161
+ return new Promise((resolve, reject) => {
162
+ if (field.metadata.result !== "container") {
163
+ reject("Cannot stream the field " + field.id + " as it is not a container");
164
+ return;
165
+ }
166
+ if (!url || typeof url !== "string") {
167
+ reject("Container is empty, or has invalid value");
168
+ return;
169
+ }
161
170
  let headers = {};
162
171
  if (Object.keys(this.cookies).length !== 0) {
163
172
  headers["Cookie"] = Object.keys(this.cookies)
@@ -167,17 +176,19 @@ export class Database extends EventEmitter {
167
176
  .join("; ");
168
177
  }
169
178
  // Automatically switch between the http and https modules, based on which is needed
170
- let res = yield fetch(url, {
179
+ (url.startsWith("https") ? https : http).get(url, {
171
180
  headers
172
- });
173
- if (res.headers.get('set-cookie')) {
174
- for (let cookie of res.headers['set-cookie']) {
175
- let cookie_split = cookie.split("=");
176
- this.cookies[cookie_split[0]] = cookie_split[1];
181
+ }, (res) => {
182
+ // Check for the 'set-cookie' header. If it exists, remember it and strip it for better security.
183
+ if (res.headers['set-cookie']) {
184
+ for (let cookie of res.headers['set-cookie']) {
185
+ let cookie_split = cookie.split("=");
186
+ this.cookies[cookie_split[0]] = cookie_split[1];
187
+ }
188
+ res.headers['set-cookie'] = null;
177
189
  }
178
- res.headers.set('set-cookie', null);
179
- }
180
- return res;
190
+ resolve(res);
191
+ });
181
192
  });
182
193
  }
183
194
  }
@@ -8,8 +8,7 @@ import {generateAuthorizationHeaders} from "./generateAuthorizationHeaders.js";
8
8
  import {FMError} from "../FMError.js";
9
9
  import {LayoutInterface} from "../layouts/layoutInterface.js";
10
10
  import {Layout} from "../layouts/layout.js";
11
- import * as http from "http";
12
- import * as https from "https";
11
+ import {http, https} from "follow-redirects"
13
12
  import {
14
13
  databaseOptionsBase,
15
14
  databaseOptionsWithExternalSources, DatabaseStructure,
@@ -181,31 +180,41 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
181
180
  this.emit("token_expired")
182
181
  }
183
182
 
184
- async streamContainer(url) {
183
+ streamContainer(field, url): Promise<http.IncomingMessage> {
184
+ return new Promise((resolve, reject) => {
185
+ if (field.metadata.result !== "container") {
186
+ reject("Cannot stream the field " + field.id + " as it is not a container")
187
+ return
188
+ }
189
+ if (!url || typeof url !== "string") {
190
+ reject("Container is empty, or has invalid value")
191
+ return
192
+ }
185
193
 
194
+ let headers = {}
195
+ if (Object.keys(this.cookies).length !== 0) {
196
+ headers["Cookie"] = Object.keys(this.cookies)
197
+ .map(key => {
198
+ return key + "=" + this.cookies[key]
199
+ })
200
+ .join("; ")
201
+ }
186
202
 
187
- let headers = {}
188
- if (Object.keys(this.cookies).length !== 0) {
189
- headers["Cookie"] = Object.keys(this.cookies)
190
- .map(key => {
191
- return key + "=" + this.cookies[key]
192
- })
193
- .join("; ")
194
- }
203
+ // Automatically switch between the http and https modules, based on which is needed
204
+ (url.startsWith("https") ? https : http).get(url, {
205
+ headers
206
+ }, (res) => {
207
+ // Check for the 'set-cookie' header. If it exists, remember it and strip it for better security.
208
+ if (res.headers['set-cookie']) {
209
+ for (let cookie of res.headers['set-cookie']) {
210
+ let cookie_split = cookie.split("=")
211
+ this.cookies[cookie_split[0]] = cookie_split[1]
212
+ }
213
+ res.headers['set-cookie'] = null
214
+ }
195
215
 
196
- // Automatically switch between the http and https modules, based on which is needed
197
- let res = await fetch(url, {
198
- headers
216
+ resolve(res)
217
+ })
199
218
  })
200
-
201
- if (res.headers.get('set-cookie')) {
202
- for (let cookie of res.headers['set-cookie']) {
203
- let cookie_split = cookie.split("=")
204
- this.cookies[cookie_split[0]] = cookie_split[1]
205
- }
206
- res.headers.set('set-cookie', null)
207
- }
208
- return res
209
219
  }
210
-
211
220
  }
@@ -1,10 +1,8 @@
1
1
  import { HostBase } from "./HostBase.js";
2
2
  import { Request } from "node-fetch";
3
- import { Response } from "node-fetch";
4
3
  export interface DatabaseBase {
5
4
  host: HostBase;
6
5
  readonly name: string;
7
6
  endpoint: string;
8
7
  apiRequest(url: string | Request, options?: any, autoRelogin?: boolean): Promise<any>;
9
- streamContainer(url: string): Promise<Response>;
10
8
  }
@@ -5,7 +5,6 @@
5
5
  import {HostBase} from "./HostBase.js"
6
6
  import {Request} from "node-fetch";
7
7
  import {DatabaseStructure} from "../types";
8
- import {Response} from "node-fetch";
9
8
 
10
9
  export interface DatabaseBase {
11
10
  host: HostBase,
@@ -15,5 +14,4 @@ export interface DatabaseBase {
15
14
  // layouts: DatabaseStructure["layouts"]
16
15
 
17
16
  apiRequest(url: string | Request, options?: any, autoRelogin?: boolean): Promise<any>
18
- streamContainer(url: string): Promise<Response>
19
17
  }
@@ -1,7 +1,8 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  import { RecordBase } from "./recordBase.js";
4
- import { ContainerDataStream, DOWNLOAD_MODES, FieldMetaData } from "../types.js";
4
+ import * as http from "http";
5
+ import { ContainerBufferResult, DOWNLOAD_MODES, FieldMetaData } from "../types.js";
5
6
  export type FieldValue = string | number | Date | Container;
6
7
  export type Container = null;
7
8
  export declare class Field<T extends FieldValue> {
@@ -18,6 +19,6 @@ export declare class Field<T extends FieldValue> {
18
19
  get date(): Date;
19
20
  get number(): number;
20
21
  upload(buffer: Buffer, filename: string, mime: string): Promise<void>;
21
- download(mode: DOWNLOAD_MODES.Stream): Promise<ContainerDataStream<NodeJS.ReadableStream>>;
22
- download(mode: DOWNLOAD_MODES.Buffer): Promise<ContainerDataStream<ArrayBuffer>>;
22
+ download(mode: DOWNLOAD_MODES.Stream): Promise<http.IncomingMessage>;
23
+ download(mode: DOWNLOAD_MODES.Buffer): Promise<ContainerBufferResult>;
23
24
  }
@@ -149,27 +149,32 @@ export class Field {
149
149
  }));
150
150
  }
151
151
  download(mode = DOWNLOAD_MODES.Stream) {
152
- return __awaiter(this, void 0, void 0, function* () {
153
- if (this.metadata.result !== "container") {
154
- throw new Error("Cannot stream the field " + this.id + " as it is not a container");
155
- }
156
- if (!this.value || typeof this.value !== "string") {
157
- throw new Error("Container is empty, or has invalid value");
158
- }
159
- let res = yield this.record.layout.database.streamContainer(this.string);
160
- let data;
161
- switch (mode) {
162
- case DOWNLOAD_MODES.Buffer:
163
- data = yield res.arrayBuffer();
164
- break;
165
- case DOWNLOAD_MODES.Stream:
166
- data = res.body;
167
- break;
168
- }
169
- return {
170
- data,
171
- mime: res.headers.get("content-type")
172
- };
152
+ return new Promise((resolve, reject) => {
153
+ // @ts-ignore
154
+ this.record.layout.database.streamContainer(this, this._value)
155
+ .then(stream => {
156
+ if (mode === DOWNLOAD_MODES.Stream) {
157
+ resolve(stream);
158
+ return;
159
+ }
160
+ let body = [];
161
+ stream.on("data", chunk => {
162
+ body.push(chunk);
163
+ });
164
+ stream.on("error", (e) => {
165
+ reject(e);
166
+ });
167
+ stream.on("end", () => {
168
+ resolve({
169
+ buffer: Buffer.concat(body),
170
+ mime: stream.headers["content-type"],
171
+ request: stream
172
+ });
173
+ });
174
+ })
175
+ .catch(e => {
176
+ reject(e);
177
+ });
173
178
  });
174
179
  }
175
180
  }
@@ -5,7 +5,7 @@
5
5
  import {RecordBase, RecordTypes} from "./recordBase.js";
6
6
  import fetch, {File, FormData} from "node-fetch";
7
7
  import * as http from "http";
8
- import {ContainerDataStream, DOWNLOAD_MODES, FieldMetaData} from "../types.js";
8
+ import {ContainerBufferResult, DOWNLOAD_MODES, FieldMetaData} from "../types.js";
9
9
  import {FMError} from "../FMError.js";
10
10
 
11
11
  export type FieldValue = string | number | Date | Container
@@ -158,26 +158,36 @@ export class Field<T extends FieldValue> {
158
158
  })
159
159
  }
160
160
 
161
- download(mode: DOWNLOAD_MODES.Stream): Promise<ContainerDataStream<NodeJS.ReadableStream>>
162
- download(mode: DOWNLOAD_MODES.Buffer): Promise<ContainerDataStream<ArrayBuffer>>
163
- async download(mode: DOWNLOAD_MODES = DOWNLOAD_MODES.Stream): Promise<ContainerDataStream> {
164
- if (this.metadata.result !== "container") {
165
- throw new Error("Cannot stream the field " + this.id + " as it is not a container")
166
- }
167
- if (!this.value || typeof this.value !== "string") {
168
- throw new Error("Container is empty, or has invalid value")
169
- }
170
-
171
- let res = await this.record.layout.database.streamContainer(this.string)
172
- let data: NodeJS.ReadableStream | ArrayBuffer
173
- switch (mode) {
174
- case DOWNLOAD_MODES.Buffer: data = await res.arrayBuffer(); break
175
- case DOWNLOAD_MODES.Stream: data = res.body; break
176
- }
161
+ download(mode: DOWNLOAD_MODES.Stream): Promise<http.IncomingMessage>
162
+ download(mode: DOWNLOAD_MODES.Buffer): Promise<ContainerBufferResult>
163
+ download(mode: DOWNLOAD_MODES = DOWNLOAD_MODES.Stream): Promise<http.IncomingMessage | ContainerBufferResult> {
164
+ return new Promise((resolve, reject) => {
165
+ // @ts-ignore
166
+ this.record.layout.database.streamContainer(this, this._value)
167
+ .then(stream => {
168
+ if (mode === DOWNLOAD_MODES.Stream) {
169
+ resolve(stream)
170
+ return
171
+ }
177
172
 
178
- return {
179
- data,
180
- mime: res.headers.get("content-type")
181
- }
173
+ let body = []
174
+ stream.on("data", chunk => {
175
+ body.push(chunk)
176
+ })
177
+ stream.on("error", (e) => {
178
+ reject(e)
179
+ })
180
+ stream.on("end", () => {
181
+ resolve({
182
+ buffer: Buffer.concat(body),
183
+ mime: stream.headers["content-type"],
184
+ request: stream
185
+ } as ContainerBufferResult)
186
+ })
187
+ })
188
+ .catch(e => {
189
+ reject(e)
190
+ })
191
+ })
182
192
  }
183
193
  }
package/src/types.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import * as http from "http";
2
4
  import { FMError } from "./FMError.js";
3
5
  import { LayoutInterface } from "./layouts/layoutInterface";
4
6
  export interface DatabaseStructure {
@@ -106,9 +108,10 @@ export interface ScriptResult {
106
108
  scriptError?: FMError;
107
109
  scriptResult?: string;
108
110
  }
109
- export interface ContainerDataStream<T = NodeJS.ReadableStream | ArrayBuffer> {
110
- data: T;
111
+ export interface ContainerBufferResult {
112
+ buffer: Buffer;
111
113
  mime: string;
114
+ request: http.IncomingMessage;
112
115
  }
113
116
  export interface AuthorizationHeaders {
114
117
  "Content-Type": "application/json";
package/src/types.ts CHANGED
@@ -132,9 +132,10 @@ export interface ScriptResult {
132
132
  scriptResult?: string
133
133
  }
134
134
 
135
- export interface ContainerDataStream<T = NodeJS.ReadableStream | ArrayBuffer> {
136
- data: T,
137
- mime: string
135
+ export interface ContainerBufferResult {
136
+ buffer: Buffer,
137
+ mime: string,
138
+ request: http.IncomingMessage
138
139
  }
139
140
 
140
141
  //