@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.
Files changed (65) hide show
  1. package/package.json +12 -6
  2. package/src/FMError.d.ts +2 -2
  3. package/src/FMError.js +507 -508
  4. package/src/FMError.ts +510 -511
  5. package/src/bin/cli.js +7 -5
  6. package/src/bin/generateTypes.js +215 -121
  7. package/src/connection/FMHost.d.ts +28 -6
  8. package/src/connection/FMHost.js +52 -25
  9. package/src/connection/FMHost.ts +75 -43
  10. package/src/connection/HostBase.d.ts +7 -3
  11. package/src/connection/HostBase.ts +8 -4
  12. package/src/connection/database.d.ts +50 -17
  13. package/src/connection/database.js +94 -66
  14. package/src/connection/database.ts +125 -105
  15. package/src/connection/databaseBase.d.ts +11 -6
  16. package/src/connection/databaseBase.ts +9 -8
  17. package/src/connection/generateAuthorizationHeaders.d.ts +1 -1
  18. package/src/connection/generateAuthorizationHeaders.js +10 -10
  19. package/src/connection/generateAuthorizationHeaders.ts +21 -21
  20. package/src/databaseStructure.d.ts +2 -4
  21. package/src/databaseStructure.ts +3 -5
  22. package/src/index.d.ts +17 -17
  23. package/src/index.js +14 -14
  24. package/src/index.ts +28 -25
  25. package/src/layouts/layout.d.ts +17 -6
  26. package/src/layouts/layout.js +19 -8
  27. package/src/layouts/layout.ts +33 -23
  28. package/src/layouts/layoutBase.d.ts +5 -5
  29. package/src/layouts/layoutBase.ts +6 -6
  30. package/src/layouts/layoutInterface.d.ts +3 -5
  31. package/src/layouts/layoutInterface.ts +4 -6
  32. package/src/layouts/layoutRecordManager.d.ts +29 -6
  33. package/src/layouts/layoutRecordManager.js +32 -9
  34. package/src/layouts/layoutRecordManager.ts +42 -19
  35. package/src/layouts/recordFieldsMap.d.ts +2 -4
  36. package/src/layouts/recordFieldsMap.ts +2 -4
  37. package/src/models/apiResults.d.ts +7 -13
  38. package/src/models/apiResults.ts +58 -58
  39. package/src/records/field.d.ts +42 -12
  40. package/src/records/field.js +69 -59
  41. package/src/records/field.ts +102 -81
  42. package/src/records/getOperations/recordGetOperation.d.ts +44 -24
  43. package/src/records/getOperations/recordGetOperation.js +89 -58
  44. package/src/records/getOperations/recordGetOperation.ts +137 -108
  45. package/src/records/layoutRecord.d.ts +28 -14
  46. package/src/records/layoutRecord.js +75 -65
  47. package/src/records/layoutRecord.ts +126 -123
  48. package/src/records/layoutRecordBase.d.ts +2 -2
  49. package/src/records/layoutRecordBase.ts +3 -3
  50. package/src/records/portal.d.ts +19 -5
  51. package/src/records/portal.js +19 -5
  52. package/src/records/portal.ts +28 -16
  53. package/src/records/portalBase.d.ts +5 -5
  54. package/src/records/portalBase.ts +6 -6
  55. package/src/records/portalRecord.d.ts +16 -8
  56. package/src/records/portalRecord.js +16 -6
  57. package/src/records/portalRecord.ts +29 -19
  58. package/src/records/recordBase.d.ts +17 -7
  59. package/src/records/recordBase.js +32 -22
  60. package/src/records/recordBase.ts +50 -43
  61. package/src/types.d.ts +21 -24
  62. package/src/types.ts +55 -59
  63. package/src/utils/query.d.ts +12 -5
  64. package/src/utils/query.js +28 -9
  65. package/src/utils/query.ts +40 -15
@@ -3,108 +3,108 @@
3
3
  */
4
4
 
5
5
  export enum ApiFieldTypes {
6
- NORMAL = "normal",
7
- CALCULATION = "calculation",
8
- SUMMARY = "summary"
6
+ NORMAL = 'normal',
7
+ CALCULATION = 'calculation',
8
+ SUMMARY = 'summary'
9
9
  }
10
10
 
11
11
  export enum ApiFieldDisplayTypes {
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"
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 = "text",
23
- NUMBER = "number",
24
- DATE = "date",
25
- TIME = "time",
26
- TIMESTAMP = "timeStamp",
27
- CONTAINER = "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? : string},
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: {[key: string]: ApiFieldMetadata[]},
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 = {[key: string]: string | number}
86
+ export type ApiFieldData = Record<string, string | number>
87
87
 
88
- export interface ApiPortalData {[key: string]: ApiFieldData[]}
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
+ }
@@ -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 "http";
4
- import { ContainerBufferResult, DownloadModes, RecordTypes } from "../types.js";
5
- import { ApiFieldMetadata } from "../models/apiResults.js";
6
- import { LayoutBase } from "../layouts/layoutBase.js";
7
- import { Moment } from "moment";
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 type Parentable = {
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
- set(content: T): void;
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
- get date(): Date;
27
- get number(): number;
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
  }
@@ -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 "../types.js";
5
- import { ApiFieldDisplayTypes, ApiFieldResultTypes, ApiFieldTypes } from "../models/apiResults.js";
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 === "container")
19
- throw "Cannot set container value using set(). Use upload() instead.";
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
- // @ts-ignore
50
- return this.parent.layout.metadata.portalMetaData[this.parent.portal.name || "portal not attached"].find(i => i.name === this.id) || {
51
- name: this.id.toString(),
52
- type: 'normal',
53
- displayType: 'editText',
54
- result: 'text',
55
- global: false,
56
- autoEnter: true,
57
- fourDigitYear: false,
58
- maxRepeat: 1,
59
- maxCharacters: 0,
60
- notEmpty: false,
61
- numeric: false,
62
- timeOfDay: false,
63
- repetitionStart: 1,
64
- repetitionEnd: 1
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 === "string") {
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 "Field value is not a date";
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
- let trace = new Error();
113
- if (this.metadata.result !== "container")
114
- throw "Cannot upload a file to the field; " + this.id + " (not a container field)";
115
- let form = new FormData();
116
- form.append("upload", new File([buffer], filename, { type: mime }));
117
- let res = await this.parent.layout.database.apiRequestRaw(`${this.parent.endpoint}/containers/${this.id}/1`, {
118
- method: "POST",
119
- // @ts-ignore
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("Cannot perform download() on a non-container field");
128
- let stream = await this.parent.layout.database.streamURL(this.string);
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
- let body = [];
133
- return new Promise((resolve, reject) => {
134
- stream.on("data", chunk => {
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("error", (e) => {
147
+ stream.on('error', (e) => {
138
148
  reject(e);
139
149
  });
140
- stream.on("end", () => {
150
+ stream.on('end', () => {
141
151
  resolve({
142
152
  buffer: Buffer.concat(body),
143
- mime: stream.headers["content-type"],
153
+ mime: stream.headers['content-type'],
144
154
  request: stream
145
155
  });
146
156
  });