@jd-data-limited/easy-fm 3.2.3 → 3.2.5

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,12 +1,12 @@
1
1
  {
2
2
  "name": "@jd-data-limited/easy-fm",
3
- "version": "3.2.3",
3
+ "version": "3.2.5",
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
- "node-fetch-cookies": "^2.1.0",
10
10
  "typescript": "^5.2.2",
11
11
  "ytdl-core": "^4.11.4"
12
12
  },
@@ -1,8 +1,9 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from "events";
3
- import { Request } from "node-fetch-cookies";
3
+ import { Request } from "node-fetch";
4
4
  import { LayoutInterface } from "../layouts/layoutInterface.js";
5
5
  import { Layout } from "../layouts/layout.js";
6
+ import redirecter 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";
@@ -10,7 +11,7 @@ export declare class Database<T extends DatabaseStructure> extends EventEmitter
10
11
  private _token;
11
12
  readonly host: HostBase;
12
13
  private connection_details;
13
- private cookieJar;
14
+ private cookies;
14
15
  readonly name: string;
15
16
  constructor(host: HostBase, conn: databaseOptionsWithExternalSources);
16
17
  private generateExternalSourceLogin;
@@ -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<any>;
28
+ streamContainer(field: any, url: any): Promise<redirecter.http.IncomingMessage>;
28
29
  }
@@ -11,14 +11,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  });
12
12
  };
13
13
  import { EventEmitter } from "events";
14
- import { fetch, CookieJar } from "node-fetch-cookies";
14
+ 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 redirecter from "follow-redirects";
18
19
  export class Database extends EventEmitter {
19
20
  constructor(host, conn) {
20
21
  super();
21
- this.cookieJar = new CookieJar();
22
+ this.cookies = {};
22
23
  this.host = host;
23
24
  this.name = conn.database;
24
25
  this.connection_details = conn;
@@ -40,7 +41,7 @@ export class Database extends EventEmitter {
40
41
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
41
42
  if (!this.token)
42
43
  reject(new Error("Not logged in"));
43
- let _fetch = yield fetch(this.cookieJar, `${this.endpoint}/sessions/${this.token}`, {
44
+ let _fetch = yield fetch(`${this.endpoint}/sessions/${this.token}`, {
44
45
  method: "DELETE",
45
46
  headers: {
46
47
  "content-type": "application/json"
@@ -55,7 +56,7 @@ export class Database extends EventEmitter {
55
56
  login() {
56
57
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
57
58
  // Reset cookies
58
- this.cookieJar = {};
59
+ this.cookies = {};
59
60
  try {
60
61
  yield this.host.getMetadata();
61
62
  }
@@ -70,7 +71,7 @@ export class Database extends EventEmitter {
70
71
  resolve(this.token);
71
72
  }
72
73
  else {
73
- fetch(this.cookieJar, `${this.endpoint}/sessions`, {
74
+ fetch(`${this.endpoint}/sessions`, {
74
75
  hostname: this.host.hostname,
75
76
  port: 443,
76
77
  method: "POST",
@@ -110,11 +111,11 @@ export class Database extends EventEmitter {
110
111
  options.headers["content-type"] = options.headers["content-type"] ? options.headers["content-type"] : "application/json";
111
112
  options.headers["authorization"] = "Bearer " + this._token;
112
113
  options.rejectUnauthorized = this.host.verify;
113
- let _fetch = yield fetch(this.cookieJar, url, options);
114
+ let _fetch = yield fetch(url, options);
114
115
  if (_fetch.headers.get('set-cookie')) {
115
116
  for (let cookie of _fetch.headers.get('set-cookie')) {
116
117
  let cookie_split = cookie.split("=");
117
- this.cookieJar[cookie_split[0]] = cookie_split[1];
118
+ this.cookies[cookie_split[0]] = cookie_split[1];
118
119
  }
119
120
  }
120
121
  let data = yield _fetch.json();
@@ -156,28 +157,38 @@ 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
- if (Object.keys(this.cookieJar).length !== 0) {
163
- headers["Cookie"] = Object.keys(this.cookieJar)
171
+ if (Object.keys(this.cookies).length !== 0) {
172
+ headers["Cookie"] = Object.keys(this.cookies)
164
173
  .map(key => {
165
- return key + "=" + this.cookieJar[key];
174
+ return key + "=" + this.cookies[key];
166
175
  })
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(this.cookieJar, url, {
179
+ (url.startsWith("https") ? redirecter.https : redirecter.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.cookieJar[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
  }
@@ -3,14 +3,12 @@
3
3
  */
4
4
 
5
5
  import {EventEmitter} from "events";
6
- import {HeadersInit} from "node-fetch";
7
- import {fetch, CookieJar, Request} from "node-fetch-cookies"
6
+ import fetch, {HeadersInit, Request} from "node-fetch";
8
7
  import {generateAuthorizationHeaders} from "./generateAuthorizationHeaders.js";
9
8
  import {FMError} from "../FMError.js";
10
9
  import {LayoutInterface} from "../layouts/layoutInterface.js";
11
10
  import {Layout} from "../layouts/layout.js";
12
- import * as http from "http";
13
- import * as https from "https";
11
+ import redirecter from "follow-redirects"
14
12
  import {
15
13
  databaseOptionsBase,
16
14
  databaseOptionsWithExternalSources, DatabaseStructure,
@@ -28,7 +26,7 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
28
26
  private _token: any;
29
27
  readonly host: HostBase;
30
28
  private connection_details: databaseOptionsWithExternalSources
31
- private cookieJar = new CookieJar()
29
+ private cookies: { [key: string]: string } = {}
32
30
  readonly name: string;
33
31
 
34
32
  constructor(host: HostBase, conn: databaseOptionsWithExternalSources) {
@@ -56,7 +54,7 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
56
54
  return new Promise(async (resolve, reject) => {
57
55
  if (!this.token) reject(new Error("Not logged in"))
58
56
 
59
- let _fetch = await fetch(this.cookieJar, `${this.endpoint}/sessions/${this.token}`, {
57
+ let _fetch = await fetch(`${this.endpoint}/sessions/${this.token}`, {
60
58
  method: "DELETE",
61
59
  headers: {
62
60
  "content-type": "application/json"
@@ -72,7 +70,7 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
72
70
  login() {
73
71
  return new Promise<string>(async (resolve, reject) => {
74
72
  // Reset cookies
75
- this.cookieJar = {}
73
+ this.cookies = {}
76
74
 
77
75
  try {
78
76
  await this.host.getMetadata()
@@ -87,7 +85,7 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
87
85
  resolve(this.token)
88
86
  }
89
87
  else {
90
- fetch(this.cookieJar, `${this.endpoint}/sessions`, {
88
+ fetch(`${this.endpoint}/sessions`, {
91
89
  hostname: this.host.hostname,
92
90
  port: 443,
93
91
  method: "POST",
@@ -129,11 +127,11 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
129
127
  options.headers["authorization"] = "Bearer " + this._token
130
128
  options.rejectUnauthorized = this.host.verify
131
129
 
132
- let _fetch = await fetch(this.cookieJar, url, options)
130
+ let _fetch = await fetch(url, options)
133
131
  if (_fetch.headers.get('set-cookie')) {
134
132
  for (let cookie of _fetch.headers.get('set-cookie')) {
135
133
  let cookie_split = cookie.split("=")
136
- this.cookieJar[cookie_split[0]] = cookie_split[1]
134
+ this.cookies[cookie_split[0]] = cookie_split[1]
137
135
  }
138
136
  }
139
137
  let data = await _fetch.json() as fileMakerResponse
@@ -182,31 +180,41 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
182
180
  this.emit("token_expired")
183
181
  }
184
182
 
185
- async streamContainer(url) {
183
+ streamContainer(field, url): Promise<redirecter.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
+ }
186
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
+ }
187
202
 
188
- let headers = {}
189
- if (Object.keys(this.cookieJar).length !== 0) {
190
- headers["Cookie"] = Object.keys(this.cookieJar)
191
- .map(key => {
192
- return key + "=" + this.cookieJar[key]
193
- })
194
- .join("; ")
195
- }
203
+ // Automatically switch between the http and https modules, based on which is needed
204
+ (url.startsWith("https") ? redirecter.https : redirecter.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
+ }
196
215
 
197
- // Automatically switch between the http and https modules, based on which is needed
198
- let res = await fetch(this.cookieJar, url, {
199
- headers
216
+ resolve(res)
217
+ })
200
218
  })
201
-
202
- if (res.headers.get('set-cookie')) {
203
- for (let cookie of res.headers['set-cookie']) {
204
- let cookie_split = cookie.split("=")
205
- this.cookieJar[cookie_split[0]] = cookie_split[1]
206
- }
207
- res.headers.set('set-cookie', null)
208
- }
209
- return res
210
219
  }
211
-
212
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
  //