@jd-data-limited/easy-fm 4.1.0 → 4.1.2
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 +5 -2
- package/src/bin/generateTypes.js +121 -215
- package/src/connection/database.d.ts +7 -7
- package/src/connection/database.js +34 -50
- package/src/connection/database.ts +43 -60
- package/src/connection/databaseBase.d.ts +4 -5
- package/src/connection/databaseBase.ts +3 -4
- package/src/records/field.d.ts +8 -16
- package/src/records/field.js +225 -124
- package/src/records/field.ts +86 -39
- package/src/records/layoutRecord.js +0 -1
- package/src/records/layoutRecord.ts +0 -1
- package/src/records/recordBase.d.ts +1 -1
- package/src/types.d.ts +2 -6
- package/src/types.js +0 -5
- package/src/types.ts +0 -5
package/src/records/field.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import {type ContainerBufferResult, DownloadModes, RecordTypes} from '../types.js'
|
|
5
|
+
import {RecordTypes} from '../types.js'
|
|
7
6
|
import {ApiFieldDisplayTypes, type ApiFieldMetadata, ApiFieldResultTypes, ApiFieldTypes} from '../models/apiResults.js'
|
|
8
7
|
import {type LayoutBase} from '../layouts/layoutBase.js'
|
|
9
8
|
import {type Moment} from 'moment'
|
|
9
|
+
import {FMError} from '../FMError.js'
|
|
10
10
|
|
|
11
11
|
export type FieldValue = string | number | Moment | Container
|
|
12
12
|
export type Container = null
|
|
@@ -29,6 +29,8 @@ export class Field<T extends FieldValue> {
|
|
|
29
29
|
protected _value: T | null
|
|
30
30
|
edited: boolean
|
|
31
31
|
|
|
32
|
+
static firstContainerDownload: Promise<any> | null = null
|
|
33
|
+
|
|
32
34
|
constructor (record: Parentable, id: string, contents: T) {
|
|
33
35
|
this.parent = record
|
|
34
36
|
this.id = id
|
|
@@ -125,64 +127,109 @@ export class Field<T extends FieldValue> {
|
|
|
125
127
|
/**
|
|
126
128
|
* Uploads a file to the container field.
|
|
127
129
|
*
|
|
128
|
-
* @param {Buffer}
|
|
129
|
-
* @param {string} filename - The filename of the file.
|
|
130
|
-
* @param {string} mime - The MIME type of the file.
|
|
130
|
+
* @param {Buffer} file - The file content as a buffer.
|
|
131
131
|
*
|
|
132
132
|
* @throws {Error} - Cannot upload a file to the field if it's not a container field.
|
|
133
133
|
* @throws {Error} - Upload failed with HTTP error.
|
|
134
134
|
*
|
|
135
135
|
* @returns {Promise<void>} - A promise that resolves when the file is successfully uploaded.
|
|
136
136
|
*/
|
|
137
|
-
async upload (
|
|
137
|
+
async upload (file: File): Promise<void> {
|
|
138
138
|
if (this.metadata.result !== 'container') {
|
|
139
139
|
throw new Error('Cannot upload a file to the field; ' + this.id + ' (not a container field)')
|
|
140
140
|
}
|
|
141
141
|
const form = new FormData()
|
|
142
|
-
form.append('upload',
|
|
142
|
+
form.append('upload', file)
|
|
143
143
|
|
|
144
144
|
const res = await this.parent.layout.database._apiRequestRaw(`${this.parent.endpoint}/containers/${this.id}/1`, {
|
|
145
145
|
method: 'POST',
|
|
146
146
|
headers: {
|
|
147
|
-
Authorization: 'Bearer ' + this.parent.layout.database.token,
|
|
148
|
-
'Content-Type': 'multipart/form-data'
|
|
147
|
+
// Authorization: 'Bearer ' + this.parent.layout.database.token,
|
|
148
|
+
// 'Content-Type': 'multipart/form-data'
|
|
149
149
|
},
|
|
150
150
|
body: form
|
|
151
151
|
})
|
|
152
|
-
if (!res.ok)
|
|
152
|
+
if (!res.ok) {
|
|
153
|
+
throw new Error(`Upload failed with HTTP error: ${res.status} (${res.statusText})`)
|
|
154
|
+
}
|
|
155
|
+
const data: { messages: Array<{ code: string }> } = await res.json() as any
|
|
156
|
+
if (data.messages[0].code === '0') return
|
|
157
|
+
else {
|
|
158
|
+
throw new FMError(data.messages[0].code, res.status, res)
|
|
159
|
+
}
|
|
153
160
|
}
|
|
154
161
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
*/
|
|
161
|
-
download (mode: DownloadModes.Stream): Promise<http.IncomingMessage>
|
|
162
|
-
download (mode: DownloadModes.Buffer): Promise<ContainerBufferResult>
|
|
163
|
-
async download (mode: DownloadModes = DownloadModes.Stream): Promise<http.IncomingMessage | ContainerBufferResult> {
|
|
164
|
-
if (this.metadata.result !== ApiFieldResultTypes.CONTAINER) throw new Error('Cannot perform download() on a non-container field')
|
|
165
|
-
|
|
166
|
-
const stream = await this.parent.layout.database.streamURL(this.string)
|
|
167
|
-
if (mode === DownloadModes.Stream) {
|
|
168
|
-
return stream
|
|
162
|
+
@containerDownloadFunction
|
|
163
|
+
async #streamAsync () {
|
|
164
|
+
const req = await this.parent.layout.database._apiRequestRaw(this.string, {useCookieJar: true})
|
|
165
|
+
if (!req.ok || !req.body) {
|
|
166
|
+
throw new Error(`HTTP Error: ${req.status} (${req.statusText})`)
|
|
169
167
|
}
|
|
168
|
+
return req.body
|
|
169
|
+
}
|
|
170
170
|
|
|
171
|
-
|
|
172
|
-
return await
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
171
|
+
async stream () {
|
|
172
|
+
return await this.#streamAsync()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@containerDownloadFunction
|
|
176
|
+
async arrayBuffer () {
|
|
177
|
+
const req = await this.parent.layout.database._apiRequestRaw(this.string, {useCookieJar: true})
|
|
178
|
+
if (!req.ok) throw new Error(`HTTP Error: ${req.status} (${req.statusText})`)
|
|
179
|
+
return await req.arrayBuffer()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function containerDownloadFunction<PROPS extends any[], T extends FieldValue, R = unknown> (originalMethod: (...p: PROPS) => Promise<R>, context: ClassMethodDecoratorContext<Field<T>>) {
|
|
184
|
+
async function replacementMethod (this: Field<T>, ...args: PROPS) {
|
|
185
|
+
return await ContainerDownloadExecutor.processTask(async () => await originalMethod.call(this, ...args))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return replacementMethod
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
class ContainerDownloadExecutorClass {
|
|
192
|
+
hasDownloadedFirstContainer: 0 | 1 | 2 = 0
|
|
193
|
+
waitingFuncs: Array<{
|
|
194
|
+
func: (() => any)
|
|
195
|
+
done: ((...args: any[]) => any)
|
|
196
|
+
err: ((e: any) => any)
|
|
197
|
+
}> = []
|
|
198
|
+
|
|
199
|
+
async processTask<T extends () => Promise<any>>(task: T) {
|
|
200
|
+
const isFirstTask = this.hasDownloadedFirstContainer === 0
|
|
201
|
+
if (isFirstTask) {
|
|
202
|
+
this.hasDownloadedFirstContainer = 1
|
|
203
|
+
let res
|
|
204
|
+
try {
|
|
205
|
+
res = await task()
|
|
206
|
+
} catch (e) {
|
|
207
|
+
this.hasDownloadedFirstContainer = 0
|
|
208
|
+
const nextTask = this.waitingFuncs.splice(0, 1)[0]
|
|
209
|
+
if (nextTask) {
|
|
210
|
+
this.processTask(nextTask.func)
|
|
211
|
+
.then(res => nextTask.done(res))
|
|
212
|
+
.catch(e => nextTask.err(e))
|
|
213
|
+
}
|
|
214
|
+
throw e
|
|
215
|
+
}
|
|
216
|
+
this.hasDownloadedFirstContainer = 2
|
|
217
|
+
for (const task of this.waitingFuncs) {
|
|
218
|
+
task.func()
|
|
219
|
+
.then((res: any) => task.done(res))
|
|
220
|
+
.catch((e: any) => task.err(e))
|
|
221
|
+
}
|
|
222
|
+
return res
|
|
223
|
+
} else if (this.hasDownloadedFirstContainer === 1) {
|
|
224
|
+
return await new Promise((resolve, reject) => {
|
|
225
|
+
this.waitingFuncs.push({
|
|
226
|
+
func: task,
|
|
227
|
+
done: resolve,
|
|
228
|
+
err: reject
|
|
229
|
+
})
|
|
185
230
|
})
|
|
186
|
-
})
|
|
231
|
+
} else return await task()
|
|
187
232
|
}
|
|
188
233
|
}
|
|
234
|
+
|
|
235
|
+
const ContainerDownloadExecutor = new ContainerDownloadExecutorClass()
|
|
@@ -153,7 +153,6 @@ export class LayoutRecord extends RecordBase {
|
|
|
153
153
|
const res = await this.layout.database._apiRequestJSON(this.endpoint, {
|
|
154
154
|
method: 'DELETE'
|
|
155
155
|
});
|
|
156
|
-
console.log(res);
|
|
157
156
|
if (typeof res.response?.scriptError !== 'undefined' && res.response?.scriptError !== '0') {
|
|
158
157
|
throw new FMError(res.response.scriptError, res.httpStatus, res);
|
|
159
158
|
}
|
|
@@ -177,7 +177,6 @@ export class LayoutRecord<LAYOUT extends LayoutInterface> extends RecordBase<LAY
|
|
|
177
177
|
const res = await this.layout.database._apiRequestJSON(this.endpoint, {
|
|
178
178
|
method: 'DELETE'
|
|
179
179
|
})
|
|
180
|
-
console.log(res)
|
|
181
180
|
if (typeof res.response?.scriptError !== 'undefined' && res.response?.scriptError !== '0') {
|
|
182
181
|
throw new FMError(res.response.scriptError, res.httpStatus, res)
|
|
183
182
|
} else if (res.messages[0].code === '0') {
|
package/src/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/// <reference types="node"
|
|
2
|
-
/// <reference types="node"
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
3
|
import type * as http from 'http';
|
|
4
4
|
import { type FMError } from './FMError.js';
|
|
5
5
|
import { type LayoutInterface } from './layouts/layoutInterface.js';
|
|
@@ -52,10 +52,6 @@ export interface ScriptRequestData {
|
|
|
52
52
|
export interface extraBodyOptions {
|
|
53
53
|
scripts?: ScriptRequestData;
|
|
54
54
|
}
|
|
55
|
-
export declare enum DownloadModes {
|
|
56
|
-
Stream = 0,
|
|
57
|
-
Buffer = 1
|
|
58
|
-
}
|
|
59
55
|
export interface Script {
|
|
60
56
|
name: string;
|
|
61
57
|
parameter: string;
|
package/src/types.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright (c) 2022-2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
|
-
export var DownloadModes;
|
|
5
|
-
(function (DownloadModes) {
|
|
6
|
-
DownloadModes[DownloadModes["Stream"] = 0] = "Stream";
|
|
7
|
-
DownloadModes[DownloadModes["Buffer"] = 1] = "Buffer";
|
|
8
|
-
})(DownloadModes || (DownloadModes = {}));
|
|
9
4
|
export var RecordTypes;
|
|
10
5
|
(function (RecordTypes) {
|
|
11
6
|
RecordTypes[RecordTypes["UNKNOWN"] = 0] = "UNKNOWN";
|