@jd-data-limited/easy-fm 4.0.14 → 4.1.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/package.json +12 -6
- package/src/FMError.d.ts +2 -2
- package/src/FMError.js +507 -508
- package/src/FMError.ts +510 -511
- package/src/bin/cli.js +7 -5
- package/src/bin/generateTypes.js +215 -121
- package/src/connection/FMHost.d.ts +28 -6
- package/src/connection/FMHost.js +52 -25
- package/src/connection/FMHost.ts +75 -43
- package/src/connection/HostBase.d.ts +7 -3
- package/src/connection/HostBase.ts +8 -4
- package/src/connection/database.d.ts +50 -17
- package/src/connection/database.js +94 -66
- package/src/connection/database.ts +125 -105
- package/src/connection/databaseBase.d.ts +11 -6
- package/src/connection/databaseBase.ts +9 -8
- package/src/connection/generateAuthorizationHeaders.d.ts +1 -1
- package/src/connection/generateAuthorizationHeaders.js +10 -10
- package/src/connection/generateAuthorizationHeaders.ts +21 -21
- package/src/databaseStructure.d.ts +2 -4
- package/src/databaseStructure.ts +3 -5
- package/src/index.d.ts +17 -17
- package/src/index.js +14 -14
- package/src/index.ts +28 -25
- package/src/layouts/layout.d.ts +17 -6
- package/src/layouts/layout.js +19 -8
- package/src/layouts/layout.ts +33 -23
- package/src/layouts/layoutBase.d.ts +5 -5
- package/src/layouts/layoutBase.ts +6 -6
- package/src/layouts/layoutInterface.d.ts +3 -5
- package/src/layouts/layoutInterface.ts +4 -6
- package/src/layouts/layoutRecordManager.d.ts +29 -6
- package/src/layouts/layoutRecordManager.js +32 -9
- package/src/layouts/layoutRecordManager.ts +42 -19
- package/src/layouts/recordFieldsMap.d.ts +2 -4
- package/src/layouts/recordFieldsMap.ts +2 -4
- package/src/models/apiResults.d.ts +7 -13
- package/src/models/apiResults.ts +58 -58
- package/src/records/field.d.ts +42 -12
- package/src/records/field.js +69 -59
- package/src/records/field.ts +102 -81
- package/src/records/getOperations/recordGetOperation.d.ts +44 -24
- package/src/records/getOperations/recordGetOperation.js +89 -58
- package/src/records/getOperations/recordGetOperation.ts +137 -108
- package/src/records/layoutRecord.d.ts +28 -14
- package/src/records/layoutRecord.js +75 -65
- package/src/records/layoutRecord.ts +126 -123
- package/src/records/layoutRecordBase.d.ts +2 -2
- package/src/records/layoutRecordBase.ts +3 -3
- package/src/records/portal.d.ts +19 -5
- package/src/records/portal.js +19 -5
- package/src/records/portal.ts +28 -16
- package/src/records/portalBase.d.ts +5 -5
- package/src/records/portalBase.ts +6 -6
- package/src/records/portalRecord.d.ts +16 -8
- package/src/records/portalRecord.js +16 -6
- package/src/records/portalRecord.ts +29 -19
- package/src/records/recordBase.d.ts +17 -7
- package/src/records/recordBase.js +32 -22
- package/src/records/recordBase.ts +50 -43
- package/src/types.d.ts +21 -24
- package/src/types.ts +55 -59
- package/src/utils/query.d.ts +12 -5
- package/src/utils/query.js +28 -9
- package/src/utils/query.ts +40 -15
package/src/models/apiResults.ts
CHANGED
|
@@ -3,108 +3,108 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export enum ApiFieldTypes {
|
|
6
|
-
NORMAL =
|
|
7
|
-
CALCULATION =
|
|
8
|
-
SUMMARY =
|
|
6
|
+
NORMAL = 'normal',
|
|
7
|
+
CALCULATION = 'calculation',
|
|
8
|
+
SUMMARY = 'summary'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export enum ApiFieldDisplayTypes {
|
|
12
|
-
EDIT_TEXT =
|
|
13
|
-
POPUP_LIST =
|
|
14
|
-
CHECKBOX =
|
|
15
|
-
RADIO_BUTTONS =
|
|
16
|
-
SELECTION_LIST =
|
|
17
|
-
CALENDAR =
|
|
18
|
-
SECURE_TEXT =
|
|
12
|
+
EDIT_TEXT = 'editText',
|
|
13
|
+
POPUP_LIST = 'popupList',
|
|
14
|
+
CHECKBOX = 'checkBox',
|
|
15
|
+
RADIO_BUTTONS = 'radioButtons',
|
|
16
|
+
SELECTION_LIST = 'selectionList',
|
|
17
|
+
CALENDAR = 'calendar',
|
|
18
|
+
SECURE_TEXT = 'secureText'
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export enum ApiFieldResultTypes {
|
|
22
|
-
TEXT =
|
|
23
|
-
NUMBER =
|
|
24
|
-
DATE =
|
|
25
|
-
TIME =
|
|
26
|
-
TIMESTAMP =
|
|
27
|
-
CONTAINER =
|
|
22
|
+
TEXT = 'text',
|
|
23
|
+
NUMBER = 'number',
|
|
24
|
+
DATE = 'date',
|
|
25
|
+
TIME = 'time',
|
|
26
|
+
TIMESTAMP = 'timeStamp',
|
|
27
|
+
CONTAINER = 'container'
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export interface ApiMessage {
|
|
31
|
-
code: string
|
|
31
|
+
code: string
|
|
32
32
|
message: string
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export interface ApiResults<T = unknown> {
|
|
36
|
-
response?: null | T & {scriptError
|
|
37
|
-
messages: ApiMessage[]
|
|
36
|
+
response?: null | T & { scriptError?: string }
|
|
37
|
+
messages: ApiMessage[]
|
|
38
38
|
httpStatus: number
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export interface ApiLayout {
|
|
42
|
-
name: string
|
|
43
|
-
isFolder?: boolean
|
|
42
|
+
name: string
|
|
43
|
+
isFolder?: boolean
|
|
44
44
|
folderLayoutNames?: ApiLayout[]
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export interface ApiLayoutMetadata {
|
|
48
|
-
fieldMetaData: ApiFieldMetadata[]
|
|
49
|
-
portalMetaData:
|
|
48
|
+
fieldMetaData: ApiFieldMetadata[]
|
|
49
|
+
portalMetaData: Record<string, ApiFieldMetadata[]>
|
|
50
50
|
valueLists: ApiValueList[]
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export interface ApiFieldMetadata {
|
|
54
|
-
name: string
|
|
55
|
-
type: ApiFieldTypes
|
|
56
|
-
displayType: ApiFieldDisplayTypes
|
|
57
|
-
result: ApiFieldResultTypes
|
|
58
|
-
global: boolean
|
|
59
|
-
autoEnter: boolean
|
|
60
|
-
fourDigitYear: boolean
|
|
61
|
-
maxRepeat: number
|
|
62
|
-
maxCharacters: number
|
|
63
|
-
notEmpty: boolean
|
|
64
|
-
numeric: boolean
|
|
65
|
-
repetitions: number
|
|
66
|
-
timeOfDay: boolean
|
|
54
|
+
name: string
|
|
55
|
+
type: ApiFieldTypes
|
|
56
|
+
displayType: ApiFieldDisplayTypes
|
|
57
|
+
result: ApiFieldResultTypes
|
|
58
|
+
global: boolean
|
|
59
|
+
autoEnter: boolean
|
|
60
|
+
fourDigitYear: boolean
|
|
61
|
+
maxRepeat: number
|
|
62
|
+
maxCharacters: number
|
|
63
|
+
notEmpty: boolean
|
|
64
|
+
numeric: boolean
|
|
65
|
+
repetitions: number
|
|
66
|
+
timeOfDay: boolean
|
|
67
67
|
valueList: string
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export interface ApiValueList {
|
|
71
|
-
name: string
|
|
72
|
-
type: string
|
|
73
|
-
values: {value: string, displayName: string}
|
|
71
|
+
name: string
|
|
72
|
+
type: string
|
|
73
|
+
values: Array<{ value: string, displayName: string }>
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
export interface ApiScriptResult {
|
|
77
|
-
scriptError: string
|
|
77
|
+
scriptError: string
|
|
78
78
|
scriptResult?: string
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export interface ApiRecordResponseObj {
|
|
82
|
-
data: ApiRowDataDef[]
|
|
82
|
+
data: ApiRowDataDef[]
|
|
83
83
|
dataInfo: ApiResultSetObj
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
export type ApiFieldData =
|
|
86
|
+
export type ApiFieldData = Record<string, string | number>
|
|
87
87
|
|
|
88
|
-
export
|
|
88
|
+
export type ApiPortalData = Record<string, ApiFieldData[]>
|
|
89
89
|
|
|
90
90
|
export interface ApiResultSetObj {
|
|
91
|
-
database: string
|
|
92
|
-
layout: string
|
|
93
|
-
table: string
|
|
94
|
-
totalRecordCount: number
|
|
95
|
-
foundCount: number
|
|
91
|
+
database: string
|
|
92
|
+
layout: string
|
|
93
|
+
table: string
|
|
94
|
+
totalRecordCount: number
|
|
95
|
+
foundCount: number
|
|
96
96
|
returnedCount: number
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
export interface ApiRowDataDef {
|
|
100
|
-
fieldData: ApiFieldData
|
|
101
|
-
portalData: ApiPortalData
|
|
102
|
-
modId: string
|
|
103
|
-
recordId: string
|
|
104
|
-
portalDataInfo?: {
|
|
105
|
-
database: string
|
|
106
|
-
table: string
|
|
107
|
-
foundCount: number
|
|
100
|
+
fieldData: ApiFieldData
|
|
101
|
+
portalData: ApiPortalData
|
|
102
|
+
modId: string
|
|
103
|
+
recordId: string
|
|
104
|
+
portalDataInfo?: Array<{
|
|
105
|
+
database: string
|
|
106
|
+
table: string
|
|
107
|
+
foundCount: number
|
|
108
108
|
returnedCount: number
|
|
109
|
-
}
|
|
110
|
-
}
|
|
109
|
+
}>
|
|
110
|
+
}
|
package/src/records/field.d.ts
CHANGED
|
@@ -1,31 +1,61 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
/// <reference types="node" resolution-mode="require"/>
|
|
3
|
-
import * as http from
|
|
4
|
-
import { ContainerBufferResult, DownloadModes, RecordTypes } from
|
|
5
|
-
import { ApiFieldMetadata } from
|
|
6
|
-
import { LayoutBase } from
|
|
7
|
-
import { Moment } from
|
|
3
|
+
import type * as http from 'http';
|
|
4
|
+
import { type ContainerBufferResult, DownloadModes, RecordTypes } from '../types.js';
|
|
5
|
+
import { type ApiFieldMetadata } from '../models/apiResults.js';
|
|
6
|
+
import { type LayoutBase } from '../layouts/layoutBase.js';
|
|
7
|
+
import { type Moment } from 'moment';
|
|
8
8
|
export type FieldValue = string | number | Moment | Container;
|
|
9
9
|
export type Container = null;
|
|
10
|
-
export
|
|
10
|
+
export interface Parentable {
|
|
11
11
|
layout: LayoutBase;
|
|
12
12
|
type: RecordTypes;
|
|
13
13
|
endpoint: string;
|
|
14
|
-
|
|
14
|
+
portal?: {
|
|
15
|
+
name: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A class representing a field in a record.
|
|
20
|
+
*
|
|
21
|
+
* @template T - The type of the field value.
|
|
22
|
+
*/
|
|
15
23
|
export declare class Field<T extends FieldValue> {
|
|
16
24
|
parent: Parentable;
|
|
17
25
|
id: string;
|
|
18
|
-
protected _value: T;
|
|
26
|
+
protected _value: T | null;
|
|
19
27
|
edited: boolean;
|
|
20
28
|
constructor(record: Parentable, id: string, contents: T);
|
|
21
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Sets the value of the field.
|
|
31
|
+
*
|
|
32
|
+
* @param {T | null} content - The new content value to be set. Can be either the type T or null.
|
|
33
|
+
* @throws {Error} Cannot set container value using set(). Use upload() instead, if the result is a 'container'.
|
|
34
|
+
*/
|
|
35
|
+
set(content: T | null): void;
|
|
22
36
|
get metadata(): ApiFieldMetadata;
|
|
23
|
-
get value(): T;
|
|
37
|
+
get value(): T | null;
|
|
24
38
|
set value(value: T);
|
|
25
39
|
get string(): string;
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Uploads a file to the container field.
|
|
42
|
+
*
|
|
43
|
+
* @param {Buffer} buffer - The file content as a buffer.
|
|
44
|
+
* @param {string} filename - The filename of the file.
|
|
45
|
+
* @param {string} mime - The MIME type of the file.
|
|
46
|
+
*
|
|
47
|
+
* @throws {Error} - Cannot upload a file to the field if it's not a container field.
|
|
48
|
+
* @throws {Error} - Upload failed with HTTP error.
|
|
49
|
+
*
|
|
50
|
+
* @returns {Promise<void>} - A promise that resolves when the file is successfully uploaded.
|
|
51
|
+
*/
|
|
28
52
|
upload(buffer: Buffer, filename: string, mime: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Downloads a resource from the server using the specified download mode.
|
|
55
|
+
*
|
|
56
|
+
* @param {DownloadModes} mode - The mode to use for downloading the resource.
|
|
57
|
+
* @return {Promise<http.IncomingMessage>} - A promise that resolves with the incoming message representing the downloaded resource.
|
|
58
|
+
*/
|
|
29
59
|
download(mode: DownloadModes.Stream): Promise<http.IncomingMessage>;
|
|
30
60
|
download(mode: DownloadModes.Buffer): Promise<ContainerBufferResult>;
|
|
31
61
|
}
|
package/src/records/field.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
|
-
import { DownloadModes, RecordTypes } from
|
|
5
|
-
import { ApiFieldDisplayTypes, ApiFieldResultTypes, ApiFieldTypes } from
|
|
4
|
+
import { DownloadModes, RecordTypes } from '../types.js';
|
|
5
|
+
import { ApiFieldDisplayTypes, ApiFieldResultTypes, ApiFieldTypes } from '../models/apiResults.js';
|
|
6
|
+
/**
|
|
7
|
+
* A class representing a field in a record.
|
|
8
|
+
*
|
|
9
|
+
* @template T - The type of the field value.
|
|
10
|
+
*/
|
|
6
11
|
export class Field {
|
|
7
12
|
parent;
|
|
8
13
|
id;
|
|
@@ -14,13 +19,15 @@ export class Field {
|
|
|
14
19
|
this._value = contents;
|
|
15
20
|
this.edited = false;
|
|
16
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Sets the value of the field.
|
|
24
|
+
*
|
|
25
|
+
* @param {T | null} content - The new content value to be set. Can be either the type T or null.
|
|
26
|
+
* @throws {Error} Cannot set container value using set(). Use upload() instead, if the result is a 'container'.
|
|
27
|
+
*/
|
|
17
28
|
set(content) {
|
|
18
|
-
if (this.metadata.result ===
|
|
19
|
-
throw
|
|
20
|
-
// @ts-ignore
|
|
21
|
-
if (!content)
|
|
22
|
-
this._value = "";
|
|
23
|
-
// @ts-ignore
|
|
29
|
+
if (this.metadata.result === 'container')
|
|
30
|
+
throw new Error('Cannot set container value using set(). Use upload() instead.');
|
|
24
31
|
else
|
|
25
32
|
this._value = content;
|
|
26
33
|
this.edited = true;
|
|
@@ -42,30 +49,30 @@ export class Field {
|
|
|
42
49
|
numeric: false,
|
|
43
50
|
timeOfDay: false,
|
|
44
51
|
repetitions: 1,
|
|
45
|
-
valueList:
|
|
52
|
+
valueList: ''
|
|
46
53
|
};
|
|
47
54
|
}
|
|
48
|
-
if (this.parent.type === RecordTypes.PORTAL) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
55
|
+
if (this.parent.type === RecordTypes.PORTAL && this.parent.portal) {
|
|
56
|
+
return this.parent.layout.metadata.portalMetaData[this.parent.portal.name || 'portal not attached'].find(i => i.name === this.id) ??
|
|
57
|
+
{
|
|
58
|
+
name: this.id.toString(),
|
|
59
|
+
type: ApiFieldTypes.NORMAL,
|
|
60
|
+
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
61
|
+
result: ApiFieldResultTypes.TEXT,
|
|
62
|
+
global: false,
|
|
63
|
+
autoEnter: true,
|
|
64
|
+
fourDigitYear: false,
|
|
65
|
+
maxRepeat: 1,
|
|
66
|
+
maxCharacters: 0,
|
|
67
|
+
notEmpty: false,
|
|
68
|
+
numeric: false,
|
|
69
|
+
timeOfDay: false,
|
|
70
|
+
repetitions: 1,
|
|
71
|
+
valueList: ''
|
|
72
|
+
};
|
|
66
73
|
}
|
|
67
74
|
else {
|
|
68
|
-
return this.parent.layout.metadata.fieldMetaData.find(i => i.name === this.id)
|
|
75
|
+
return this.parent.layout.metadata.fieldMetaData.find(i => i.name === this.id) ?? {
|
|
69
76
|
name: this.id.toString(),
|
|
70
77
|
type: ApiFieldTypes.NORMAL,
|
|
71
78
|
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
@@ -79,7 +86,7 @@ export class Field {
|
|
|
79
86
|
numeric: false,
|
|
80
87
|
timeOfDay: false,
|
|
81
88
|
repetitions: 1,
|
|
82
|
-
valueList:
|
|
89
|
+
valueList: ''
|
|
83
90
|
};
|
|
84
91
|
}
|
|
85
92
|
}
|
|
@@ -91,32 +98,35 @@ export class Field {
|
|
|
91
98
|
this._value = value;
|
|
92
99
|
}
|
|
93
100
|
get string() {
|
|
94
|
-
if (typeof this._value ===
|
|
95
|
-
return this._value;
|
|
96
|
-
}
|
|
97
|
-
throw "Field value is not a string";
|
|
98
|
-
}
|
|
99
|
-
get date() {
|
|
100
|
-
if (this._value instanceof Date) {
|
|
101
|
+
if (typeof this._value === 'string') {
|
|
101
102
|
return this._value;
|
|
102
103
|
}
|
|
103
|
-
throw
|
|
104
|
-
}
|
|
105
|
-
get number() {
|
|
106
|
-
if (typeof this._value === "number") {
|
|
107
|
-
return this._value;
|
|
108
|
-
}
|
|
109
|
-
throw "Field value is not a number";
|
|
104
|
+
throw new Error('Field value is not a string');
|
|
110
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Uploads a file to the container field.
|
|
108
|
+
*
|
|
109
|
+
* @param {Buffer} buffer - The file content as a buffer.
|
|
110
|
+
* @param {string} filename - The filename of the file.
|
|
111
|
+
* @param {string} mime - The MIME type of the file.
|
|
112
|
+
*
|
|
113
|
+
* @throws {Error} - Cannot upload a file to the field if it's not a container field.
|
|
114
|
+
* @throws {Error} - Upload failed with HTTP error.
|
|
115
|
+
*
|
|
116
|
+
* @returns {Promise<void>} - A promise that resolves when the file is successfully uploaded.
|
|
117
|
+
*/
|
|
111
118
|
async upload(buffer, filename, mime) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
form.append(
|
|
117
|
-
|
|
118
|
-
method:
|
|
119
|
-
|
|
119
|
+
if (this.metadata.result !== 'container') {
|
|
120
|
+
throw new Error('Cannot upload a file to the field; ' + this.id + ' (not a container field)');
|
|
121
|
+
}
|
|
122
|
+
const form = new FormData();
|
|
123
|
+
form.append('upload', new File([buffer], filename, { type: mime }));
|
|
124
|
+
const res = await this.parent.layout.database._apiRequestRaw(`${this.parent.endpoint}/containers/${this.id}/1`, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers: {
|
|
127
|
+
Authorization: 'Bearer ' + this.parent.layout.database.token,
|
|
128
|
+
'Content-Type': 'multipart/form-data'
|
|
129
|
+
},
|
|
120
130
|
body: form
|
|
121
131
|
});
|
|
122
132
|
if (!res.ok)
|
|
@@ -124,23 +134,23 @@ export class Field {
|
|
|
124
134
|
}
|
|
125
135
|
async download(mode = DownloadModes.Stream) {
|
|
126
136
|
if (this.metadata.result !== ApiFieldResultTypes.CONTAINER)
|
|
127
|
-
throw new Error(
|
|
128
|
-
|
|
137
|
+
throw new Error('Cannot perform download() on a non-container field');
|
|
138
|
+
const stream = await this.parent.layout.database.streamURL(this.string);
|
|
129
139
|
if (mode === DownloadModes.Stream) {
|
|
130
140
|
return stream;
|
|
131
141
|
}
|
|
132
|
-
|
|
133
|
-
return new Promise((resolve, reject) => {
|
|
134
|
-
stream.on(
|
|
142
|
+
const body = [];
|
|
143
|
+
return await new Promise((resolve, reject) => {
|
|
144
|
+
stream.on('data', (chunk) => {
|
|
135
145
|
body.push(chunk);
|
|
136
146
|
});
|
|
137
|
-
stream.on(
|
|
147
|
+
stream.on('error', (e) => {
|
|
138
148
|
reject(e);
|
|
139
149
|
});
|
|
140
|
-
stream.on(
|
|
150
|
+
stream.on('end', () => {
|
|
141
151
|
resolve({
|
|
142
152
|
buffer: Buffer.concat(body),
|
|
143
|
-
mime: stream.headers[
|
|
153
|
+
mime: stream.headers['content-type'],
|
|
144
154
|
request: stream
|
|
145
155
|
});
|
|
146
156
|
});
|