@jd-data-limited/easy-fm 4.0.4 → 4.0.7

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 (53) hide show
  1. package/package.json +7 -2
  2. package/src/FMError.d.ts +0 -1
  3. package/src/FMError.js +0 -1
  4. package/src/FMError.ts +0 -1
  5. package/src/bin/cli.d.ts +2 -0
  6. package/src/bin/cli.js +19 -0
  7. package/src/bin/cli.ts +22 -0
  8. package/src/bin/example.xml +0 -0
  9. package/src/bin/generateTypes.d.ts +1 -0
  10. package/src/bin/generateTypes.js +250 -0
  11. package/src/bin/generateTypes.ts +186 -0
  12. package/src/connection/FMHost.js +12 -3
  13. package/src/connection/FMHost.ts +12 -3
  14. package/src/connection/database.d.ts +2 -1
  15. package/src/connection/database.js +10 -6
  16. package/src/connection/database.ts +11 -7
  17. package/src/connection/databaseBase.d.ts +2 -1
  18. package/src/connection/databaseBase.ts +2 -1
  19. package/src/index.d.ts +2 -1
  20. package/src/index.js +2 -1
  21. package/src/index.ts +4 -1
  22. package/src/layouts/layout.d.ts +1 -1
  23. package/src/layouts/layout.js +9 -5
  24. package/src/layouts/layout.ts +7 -5
  25. package/src/layouts/layoutRecordManager.js +3 -3
  26. package/src/layouts/layoutRecordManager.ts +3 -3
  27. package/src/models/apiResults.d.ts +1 -1
  28. package/src/models/apiResults.ts +1 -1
  29. package/src/records/fieldBase.js +3 -1
  30. package/src/records/fieldBase.ts +2 -1
  31. package/src/records/getOperations/recordGetOperation.d.ts +2 -1
  32. package/src/records/getOperations/recordGetOperation.js +33 -26
  33. package/src/records/getOperations/recordGetOperation.ts +39 -33
  34. package/src/records/layoutRecord.d.ts +3 -2
  35. package/src/records/layoutRecord.js +58 -18
  36. package/src/records/layoutRecord.ts +61 -19
  37. package/src/records/portal.d.ts +1 -1
  38. package/src/records/portal.js +3 -3
  39. package/src/records/portal.ts +3 -3
  40. package/src/records/portalRecord.d.ts +3 -2
  41. package/src/records/portalRecord.js +2 -4
  42. package/src/records/portalRecord.ts +7 -11
  43. package/src/records/recordBase.d.ts +3 -4
  44. package/src/records/recordBase.js +3 -32
  45. package/src/records/recordBase.ts +5 -37
  46. package/src/utils/fmQuery.d.ts +4 -0
  47. package/src/utils/fmQuery.js +20 -0
  48. package/src/utils/query.d.ts +4 -0
  49. package/src/utils/query.js +20 -0
  50. package/src/utils/query.ts +25 -0
  51. package/src/records/field.d.ts +0 -5
  52. package/src/records/field.js +0 -7
  53. package/src/records/field.ts +0 -10
@@ -85,7 +85,7 @@ export class Database extends EventEmitter {
85
85
  get endpoint() {
86
86
  return `${this.host.hostname}/fmi/data/v2/databases/${this.name}`;
87
87
  }
88
- async apiRequest(url, options = {}, autoRelogin = true) {
88
+ async apiRequestRaw(url, options = {}) {
89
89
  if (!options.headers)
90
90
  options.headers = {};
91
91
  options.headers["content-type"] = options.headers["content-type"] ? options.headers["content-type"] : "application/json";
@@ -93,20 +93,24 @@ export class Database extends EventEmitter {
93
93
  options.rejectUnauthorized = this.host.verify;
94
94
  let _fetch = await fetch(url, options);
95
95
  if (_fetch.headers.get('set-cookie')) {
96
- for (let cookie of _fetch.headers.get('set-cookie')) {
96
+ for (let cookie of _fetch.headers.get('set-cookie') || []) {
97
97
  let cookie_split = cookie.split("=");
98
98
  this.cookies[cookie_split[0]] = cookie_split[1];
99
99
  }
100
100
  }
101
+ return _fetch;
102
+ }
103
+ async apiRequestJSON(url, options = {}, autoRelogin = true) {
104
+ let _fetch = await this.apiRequestRaw(url, options);
101
105
  let data = await _fetch.json();
102
106
  // Remove response if it is empty. This makes checking for an empty response easier
103
- if (Object.keys(data.response).length === 0)
107
+ if (data.response && Object.keys(data.response).length === 0)
104
108
  delete data.response;
105
109
  // console.log(data.messages[0])
106
110
  if (data.messages[0].code === "952" && autoRelogin) {
107
111
  this._token = null;
108
112
  await this.login();
109
- return await this.apiRequest(url, options, false);
113
+ return await this.apiRequestJSON(url, options, false);
110
114
  }
111
115
  else if (data.messages[0].code !== "0") {
112
116
  throw new FMError(data.messages[0].code, _fetch.status, data);
@@ -115,7 +119,7 @@ export class Database extends EventEmitter {
115
119
  return data;
116
120
  }
117
121
  async listLayouts() {
118
- let req = await this.apiRequest(`${this.endpoint}/layouts?page=2`);
122
+ let req = await this.apiRequestJSON(`${this.endpoint}/layouts?page=2`);
119
123
  if (!req.response)
120
124
  throw new FMError(req.messages[0].code, req.httpStatus, req.messages[0].message);
121
125
  const cycleLayoutNames = (layouts) => {
@@ -160,7 +164,7 @@ export class Database extends EventEmitter {
160
164
  let cookie_split = cookie.split("=");
161
165
  this.cookies[cookie_split[0]] = cookie_split[1];
162
166
  }
163
- res.headers['set-cookie'] = null;
167
+ res.headers['set-cookie'] = undefined;
164
168
  }
165
169
  };
166
170
  // Automatically switch between the http and https modules, based on which is needed
@@ -110,7 +110,7 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
110
110
  return `${this.host.hostname}/fmi/data/v2/databases/${this.name}`
111
111
  }
112
112
 
113
- async apiRequest<T = any>(url: string | Request, options: any = {}, autoRelogin = true): Promise<ApiResults<T>> {
113
+ async apiRequestRaw(url: string | Request, options: any = {}) {
114
114
  if (!options.headers) options.headers = {}
115
115
  options.headers["content-type"] = options.headers["content-type"] ? options.headers["content-type"] : "application/json"
116
116
  options.headers["authorization"] = "Bearer " + this._token
@@ -118,21 +118,25 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
118
118
 
119
119
  let _fetch = await fetch(url, options)
120
120
  if (_fetch.headers.get('set-cookie')) {
121
- for (let cookie of _fetch.headers.get('set-cookie')) {
121
+ for (let cookie of _fetch.headers.get('set-cookie') || []) {
122
122
  let cookie_split = cookie.split("=")
123
123
  this.cookies[cookie_split[0]] = cookie_split[1]
124
124
  }
125
125
  }
126
+ return _fetch
127
+ }
128
+ async apiRequestJSON<T = any>(url: string | Request, options: any = {}, autoRelogin = true): Promise<ApiResults<T>> {
129
+ let _fetch = await this.apiRequestRaw(url, options)
126
130
  let data = await _fetch.json() as ApiResults<T>
127
131
 
128
132
  // Remove response if it is empty. This makes checking for an empty response easier
129
- if (Object.keys(data.response).length === 0) delete data.response
133
+ if (data.response && Object.keys(data.response).length === 0) delete data.response
130
134
 
131
135
  // console.log(data.messages[0])
132
136
  if (data.messages[0].code === "952" && autoRelogin) {
133
137
  this._token = null
134
138
  await this.login()
135
- return await this.apiRequest(url, options, false)
139
+ return await this.apiRequestJSON(url, options, false)
136
140
  }
137
141
  else if (data.messages[0].code !== "0") {
138
142
  throw new FMError(data.messages[0].code, _fetch.status, data)
@@ -143,7 +147,7 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
143
147
  }
144
148
 
145
149
  async listLayouts() {
146
- let req = await this.apiRequest<{layouts: ApiLayout[]}>(`${this.endpoint}/layouts?page=2`)
150
+ let req = await this.apiRequestJSON<{layouts: ApiLayout[]}>(`${this.endpoint}/layouts?page=2`)
147
151
  if (!req.response) throw new FMError(req.messages[0].code, req.httpStatus, req.messages[0].message)
148
152
 
149
153
  const cycleLayoutNames = (layouts: ApiLayout[]) => {
@@ -195,14 +199,14 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
195
199
  let cookie_split = cookie.split("=")
196
200
  this.cookies[cookie_split[0]] = cookie_split[1]
197
201
  }
198
- res.headers['set-cookie'] = null
202
+ res.headers['set-cookie'] = undefined
199
203
  }
200
204
  }
201
205
 
202
206
  // Automatically switch between the http and https modules, based on which is needed
203
207
  (url.startsWith("https") ? HTTP_REDIRECT.https : HTTP_REDIRECT.http).get(url, {
204
208
  headers,
205
- beforeRedirect: (options, res) => check_for_cookies(res)
209
+ beforeRedirect: (options: any, res: any) => check_for_cookies(res)
206
210
  }, (res) => {
207
211
  check_for_cookies(res)
208
212
 
@@ -6,6 +6,7 @@ export interface DatabaseBase {
6
6
  host: HostBase;
7
7
  readonly name: string;
8
8
  endpoint: string;
9
- apiRequest<T = unknown>(url: string | Request, options?: any, autoRelogin?: boolean): Promise<ApiResults<T>>;
9
+ apiRequestJSON<T = unknown>(url: string | Request, options?: RequestInit | undefined, autoRelogin?: boolean): Promise<ApiResults<T>>;
10
+ apiRequestRaw(url: string | Request, options?: RequestInit | undefined): Promise<Response>;
10
11
  streamURL(url: string): Promise<IncomingMessage>;
11
12
  }
@@ -13,6 +13,7 @@ export interface DatabaseBase {
13
13
 
14
14
  // layouts: DatabaseStructure["layouts"]
15
15
 
16
- apiRequest<T = unknown>(url: string | Request, options?: any, autoRelogin?: boolean): Promise<ApiResults<T>>
16
+ apiRequestJSON<T = unknown>(url: string | Request, options?: RequestInit | undefined, autoRelogin?: boolean): Promise<ApiResults<T>>
17
+ apiRequestRaw(url: string | Request, options?: RequestInit | undefined): Promise<Response>
17
18
  streamURL(url: string): Promise<IncomingMessage>
18
19
  }
package/src/index.d.ts CHANGED
@@ -13,5 +13,6 @@ import { Container, FieldBase } from "./records/fieldBase.js";
13
13
  import { RecordGetOperation } from "./records/getOperations/recordGetOperation.js";
14
14
  import { LayoutRecordManager } from "./layouts/layoutRecordManager.js";
15
15
  import { RecordFieldsMap } from "./layouts/recordFieldsMap.js";
16
+ import { query, queryEscape } from "./utils/query.js";
16
17
  export default FMHost;
17
- export { FMError, TYPES, Database, Layout, RecordBase, LayoutRecord, LayoutInterface, RecordFieldsMap, PortalInterface, PortalRecord, Portal, FieldBase, RecordGetOperation, LayoutRecordManager, Container, PickPortals };
18
+ export { FMError, TYPES, Database, Layout, RecordBase, LayoutRecord, LayoutInterface, RecordFieldsMap, PortalInterface, PortalRecord, Portal, FieldBase, RecordGetOperation, LayoutRecordManager, Container, PickPortals, query, queryEscape };
package/src/index.js CHANGED
@@ -13,5 +13,6 @@ import { Portal } from "./records/portal.js";
13
13
  import { FieldBase } from "./records/fieldBase.js";
14
14
  import { RecordGetOperation } from "./records/getOperations/recordGetOperation.js";
15
15
  import { LayoutRecordManager } from "./layouts/layoutRecordManager.js";
16
+ import { query, queryEscape } from "./utils/query.js";
16
17
  export default FMHost;
17
- export { FMError, TYPES, Database, Layout, RecordBase, LayoutRecord, PortalRecord, Portal, FieldBase, RecordGetOperation, LayoutRecordManager };
18
+ export { FMError, TYPES, Database, Layout, RecordBase, LayoutRecord, PortalRecord, Portal, FieldBase, RecordGetOperation, LayoutRecordManager, query, queryEscape };
package/src/index.ts CHANGED
@@ -17,6 +17,7 @@ import {Container, FieldBase} from "./records/fieldBase.js";
17
17
  import {RecordGetOperation} from "./records/getOperations/recordGetOperation.js";
18
18
  import {LayoutRecordManager} from "./layouts/layoutRecordManager.js";
19
19
  import {RecordFieldsMap} from "./layouts/recordFieldsMap.js";
20
+ import {query, queryEscape} from "./utils/query.js";
20
21
 
21
22
  export default FMHost
22
23
  export {
@@ -35,5 +36,7 @@ export {
35
36
  RecordGetOperation,
36
37
  LayoutRecordManager,
37
38
  Container,
38
- PickPortals
39
+ PickPortals,
40
+ query,
41
+ queryEscape
39
42
  }
@@ -8,7 +8,7 @@ export declare class Layout<T extends LayoutInterface> implements LayoutBase {
8
8
  readonly database: DatabaseBase;
9
9
  readonly name: string;
10
10
  readonly records: LayoutRecordManager<T>;
11
- metadata: ApiLayoutMetadata;
11
+ metadata: ApiLayoutMetadata | null;
12
12
  constructor(database: DatabaseBase, name: string);
13
13
  get endpoint(): string;
14
14
  runScript(script: Script): Promise<ScriptResult>;
@@ -7,7 +7,7 @@ export class Layout {
7
7
  database;
8
8
  name;
9
9
  records = new LayoutRecordManager(this);
10
- metadata;
10
+ metadata = null;
11
11
  constructor(database, name) {
12
12
  this.database = database;
13
13
  this.name = name;
@@ -19,23 +19,27 @@ export class Layout {
19
19
  let url = `${this.endpoint}/script/${encodeURIComponent(script.name)}`;
20
20
  if (script.parameter)
21
21
  url += "?script.param=" + encodeURIComponent(script.parameter);
22
- let res = await this.database.apiRequest(url, {
23
- port: 443,
22
+ let res = await this.database.apiRequestJSON(url, {
24
23
  method: "GET"
25
24
  });
26
- if (res.messages[0].code === "0") {
25
+ if (res.response && res.messages[0].code === "0") {
27
26
  let error = parseInt(res.response.scriptError);
28
27
  return {
29
28
  scriptError: error ? new FMError(error, 200, res) : undefined,
30
29
  scriptResult: res.response.scriptResult
31
30
  };
32
31
  }
32
+ else {
33
+ throw new FMError(res.messages[0].code, res.httpStatus, res);
34
+ }
33
35
  }
34
36
  async getLayoutMeta() {
35
37
  if (this.metadata) {
36
38
  return this.metadata;
37
39
  }
38
- let res = await this.database.apiRequest(this.endpoint);
40
+ let res = await this.database.apiRequestJSON(this.endpoint);
41
+ if (!res.response)
42
+ throw new FMError(res.messages[0].code, res.httpStatus, res);
39
43
  this.metadata = res.response;
40
44
  return this.metadata;
41
45
  }
@@ -14,7 +14,7 @@ export class Layout<T extends LayoutInterface> implements LayoutBase {
14
14
  readonly database: DatabaseBase;
15
15
  readonly name: string;
16
16
  readonly records = new LayoutRecordManager<T>(this)
17
- metadata: ApiLayoutMetadata;
17
+ metadata: ApiLayoutMetadata | null = null;
18
18
 
19
19
  constructor(database: DatabaseBase, name: string) {
20
20
  this.database = database
@@ -29,16 +29,17 @@ export class Layout<T extends LayoutInterface> implements LayoutBase {
29
29
  async runScript(script: Script): Promise<ScriptResult> {
30
30
  let url = `${this.endpoint}/script/${encodeURIComponent(script.name)}`
31
31
  if (script.parameter) url += "?script.param=" + encodeURIComponent(script.parameter)
32
- let res = await this.database.apiRequest<ApiScriptResult>(url, {
33
- port: 443,
32
+ let res = await this.database.apiRequestJSON<ApiScriptResult>(url, {
34
33
  method: "GET"
35
34
  })
36
- if (res.messages[0].code === "0") {
35
+ if (res.response && res.messages[0].code === "0") {
37
36
  let error = parseInt(res.response.scriptError)
38
37
  return {
39
38
  scriptError: error ? new FMError(error, 200, res) : undefined,
40
39
  scriptResult: res.response.scriptResult
41
40
  }
41
+ } else {
42
+ throw new FMError(res.messages[0].code, res.httpStatus, res);
42
43
  }
43
44
  }
44
45
 
@@ -47,7 +48,8 @@ export class Layout<T extends LayoutInterface> implements LayoutBase {
47
48
  return this.metadata
48
49
  }
49
50
 
50
- let res = await this.database.apiRequest<ApiLayoutMetadata>(this.endpoint)
51
+ let res = await this.database.apiRequestJSON<ApiLayoutMetadata>(this.endpoint)
52
+ if (!res.response) throw new FMError(res.messages[0].code, res.httpStatus, res)
51
53
  this.metadata = res.response
52
54
  return this.metadata
53
55
  }
@@ -9,13 +9,13 @@ export class LayoutRecordManager {
9
9
  this.layout = layout;
10
10
  }
11
11
  async create(options) {
12
- await this.layout.getLayoutMeta();
12
+ let metadata = await this.layout.getLayoutMeta();
13
13
  let fields = {};
14
- for (let _field of this.layout.metadata.fieldMetaData) {
14
+ for (let _field of metadata.fieldMetaData) {
15
15
  fields[_field.name] = "";
16
16
  }
17
17
  let portals = {};
18
- for (let _portal of Object.keys(this.layout.metadata.portalMetaData))
18
+ for (let _portal of Object.keys(metadata.portalMetaData))
19
19
  portals[_portal] = [];
20
20
  return new LayoutRecord(this.layout, -1, 0, fields, portals);
21
21
  }
@@ -18,13 +18,13 @@ export class LayoutRecordManager<T extends LayoutInterface> {
18
18
  async create<OPTIONS extends RecordFetchOptions>(options: OPTIONS): Promise<LayoutRecord<
19
19
  PickPortals<T, OPTIONS["portals"][number]>
20
20
  >> {
21
- await this.layout.getLayoutMeta()
21
+ let metadata = await this.layout.getLayoutMeta()
22
22
  let fields: ApiFieldData = {}
23
- for (let _field of this.layout.metadata.fieldMetaData) {
23
+ for (let _field of metadata.fieldMetaData) {
24
24
  fields[_field.name] = ""
25
25
  }
26
26
  let portals: {[key: string]: []} = {}
27
- for (let _portal of Object.keys(this.layout.metadata.portalMetaData)) portals[_portal] = []
27
+ for (let _portal of Object.keys(metadata.portalMetaData)) portals[_portal] = []
28
28
  return new LayoutRecord(this.layout, -1, 0, fields, portals)
29
29
  }
30
30
 
@@ -94,7 +94,7 @@ export interface ApiRowDataDef {
94
94
  portalData: ApiPortalData;
95
95
  modId: string;
96
96
  recordId: string;
97
- portalDataInfo: {
97
+ portalDataInfo?: {
98
98
  database: string;
99
99
  table: string;
100
100
  foundCount: number;
@@ -101,7 +101,7 @@ export interface ApiRowDataDef {
101
101
  portalData: ApiPortalData,
102
102
  modId: string,
103
103
  recordId: string,
104
- portalDataInfo: {
104
+ portalDataInfo?: {
105
105
  database: string,
106
106
  table: string,
107
107
  foundCount: number,
@@ -120,12 +120,14 @@ export class FieldBase {
120
120
  throw "Cannot upload a file to the field; " + this.id + " (not a container field)";
121
121
  let form = new FormData();
122
122
  form.append("upload", new File([buffer], filename, { type: mime }));
123
- await this.parent.layout.database.apiRequest(`${this.parent.endpoint}/containers/${this.id}/1`, {
123
+ let res = await this.parent.layout.database.apiRequestRaw(`${this.parent.endpoint}/containers/${this.id}/1`, {
124
124
  method: "POST",
125
125
  // @ts-ignore
126
126
  headers: { "Authorization": "Bearer " + this.parent.layout.database.token },
127
127
  body: form
128
128
  });
129
+ if (!res.ok)
130
+ throw new Error(`Upload failed with HTTP error: ${res.status} (${res.statusText})`);
129
131
  }
130
132
  async download(mode = DOWNLOAD_MODES.Stream) {
131
133
  if (this.metadata.result !== ApiFieldResultTypes.CONTAINER)
@@ -136,12 +136,13 @@ export class FieldBase<T extends FieldValue> {
136
136
  let form = new FormData()
137
137
  form.append("upload", new File([buffer], filename, {type: mime}))
138
138
 
139
- await this.parent.layout.database.apiRequest<null>(`${this.parent.endpoint}/containers/${this.id}/1`, {
139
+ let res = await this.parent.layout.database.apiRequestRaw(`${this.parent.endpoint}/containers/${this.id}/1`, {
140
140
  method: "POST",
141
141
  // @ts-ignore
142
142
  headers: {"Authorization": "Bearer " + this.parent.layout.database.token},
143
143
  body: form
144
144
  })
145
+ if (!res.ok) throw new Error(`Upload failed with HTTP error: ${res.status} (${res.statusText})`)
145
146
  }
146
147
 
147
148
  download(mode: DOWNLOAD_MODES.Stream): Promise<http.IncomingMessage>
@@ -5,6 +5,7 @@ import { LayoutRecord } from "../layoutRecord.js";
5
5
  export type SortOrder = "ascend" | "descend";
6
6
  export type FindRequest = {
7
7
  [key: string]: string;
8
+ } & {
8
9
  omit?: "true" | "false";
9
10
  };
10
11
  export type PortalRequest = {
@@ -46,7 +47,7 @@ export declare class RecordGetOperation<T extends LayoutInterface, OPTIONS exten
46
47
  [Symbol.asyncIterator](): {
47
48
  next: () => Promise<{
48
49
  done: boolean;
49
- value: LayoutRecord<PickPortals<T, keyof OPTIONS["portals"]>>;
50
+ value: LayoutRecord<PickPortals<T, keyof OPTIONS["portals"]>> | undefined;
50
51
  }>;
51
52
  };
52
53
  }
@@ -33,20 +33,20 @@ export class RecordGetOperation {
33
33
  if (this.scriptData.after?.parameter)
34
34
  params["script.param"] = this.scriptData.after.parameter;
35
35
  if (this.scriptData.presort)
36
- params["script.presort"] = this.scriptData.after.name;
36
+ params["script.presort"] = this.scriptData.presort.name;
37
37
  if (this.scriptData.presort?.parameter)
38
- params["script.presort.param"] = this.scriptData.after.parameter;
38
+ params["script.presort.param"] = this.scriptData.presort.parameter;
39
39
  if (this.scriptData.prerequest)
40
- params["script.prerequest"] = this.scriptData.after.name;
40
+ params["script.prerequest"] = this.scriptData.prerequest.name;
41
41
  if (this.scriptData.prerequest?.parameter)
42
- params["script.prerequest.param"] = this.scriptData.after.parameter;
42
+ params["script.prerequest.param"] = this.scriptData.prerequest.parameter;
43
43
  if (this.queries.length !== 0)
44
44
  params["query"] = this.queries;
45
45
  let portals = Object.keys(this.portals);
46
46
  params["portal"] = portals;
47
47
  for (let portal of portals) {
48
- params[`offset.${portal}`] = this.portals[portal].offset;
49
- params[`limit.${portal}`] = this.portals[portal].limit;
48
+ params[`offset.${portal.toString()}`] = this.portals[portal]?.offset;
49
+ params[`limit.${portal.toString()}`] = this.portals[portal]?.limit;
50
50
  }
51
51
  return params;
52
52
  }
@@ -62,17 +62,17 @@ export class RecordGetOperation {
62
62
  if (this.scriptData.after?.parameter)
63
63
  params.set("script.param", this.scriptData.after.parameter);
64
64
  if (this.scriptData.presort)
65
- params.set("script.presort", this.scriptData.after.name);
65
+ params.set("script.presort", this.scriptData.presort.name);
66
66
  if (this.scriptData.presort?.parameter)
67
- params.set("script.presort.param", this.scriptData.after.parameter);
67
+ params.set("script.presort.param", this.scriptData.presort.parameter);
68
68
  if (this.scriptData.prerequest)
69
- params.set("script.prerequest", this.scriptData.after.name);
69
+ params.set("script.prerequest", this.scriptData.prerequest.name);
70
70
  if (this.scriptData.prerequest?.parameter)
71
- params.set("script.prerequest.param", this.scriptData.after.parameter);
71
+ params.set("script.prerequest.param", this.scriptData.prerequest.parameter);
72
72
  let portals = Object.keys(this.portals);
73
73
  for (let portal of portals) {
74
- params.set(`_offset.${portal}`, this.portals[portal].limit.toString());
75
- params.set(`_offset.${portal}`, this.portals[portal].offset.toString());
74
+ params.set(`_offset.${portal.toString()}`, (this.portals[portal]?.limit || "").toString());
75
+ params.set(`_offset.${portal.toString()}`, (this.portals[portal]?.offset || "").toString());
76
76
  }
77
77
  params.set('portal', JSON.stringify(portals));
78
78
  return params;
@@ -104,21 +104,28 @@ export class RecordGetOperation {
104
104
  method: is_find ? "POST" : "GET",
105
105
  body: is_find ? JSON.stringify(this.generateParamsBody(offset, limit)) : undefined,
106
106
  };
107
- let res = await this.layout.database.apiRequest(endpoint, reqData);
108
- if (res.messages[0].code === "0") {
109
- // console.log("RESOLVING")
110
- if (!this.layout.metadata)
111
- await this.layout.getLayoutMeta();
112
- return res.response.data.map(item => {
113
- return new LayoutRecord(this.layout, item.recordId, item.modId, item.fieldData, item.portalData);
114
- });
115
- }
116
- else if (res.messages[0].code == "401") {
117
- // No records found, so return empty set
118
- return [];
107
+ try {
108
+ let res = await this.layout.database.apiRequestJSON(endpoint, reqData);
109
+ if (res.messages[0].code === "0" && res.response) {
110
+ // console.log("RESOLVING")
111
+ if (!this.layout.metadata)
112
+ await this.layout.getLayoutMeta();
113
+ return res.response.data.map(item => {
114
+ return new LayoutRecord(this.layout, item.recordId, item.modId, item.fieldData, item.portalData);
115
+ });
116
+ }
117
+ else {
118
+ throw new FMError(res.messages[0].code, res.httpStatus, res, trace);
119
+ }
119
120
  }
120
- else {
121
- throw new FMError(res.messages[0].code, res.httpStatus, res, trace);
121
+ catch (e) {
122
+ if (e instanceof FMError) {
123
+ if (e.code === 401) {
124
+ // No records found, so return empty set
125
+ return [];
126
+ }
127
+ }
128
+ throw e;
122
129
  }
123
130
  }
124
131
  [Symbol.asyncIterator]() {
@@ -12,8 +12,8 @@ import {FMError} from "../../FMError.js";
12
12
  export type SortOrder = "ascend" | "descend"
13
13
  export type FindRequest = {
14
14
  [key: string]: string,
15
- omit?: "true" | "false"
16
- }
15
+ } & {omit?: "true" | "false"}
16
+
17
17
  export type PortalRequest = {
18
18
  name: string,
19
19
  }
@@ -62,19 +62,19 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
62
62
  if (this.scriptData.after) params["script"] = this.scriptData.after.name
63
63
  if (this.scriptData.after?.parameter) params["script.param"] = this.scriptData.after.parameter
64
64
 
65
- if (this.scriptData.presort) params["script.presort"] = this.scriptData.after.name
66
- if (this.scriptData.presort?.parameter) params["script.presort.param"] = this.scriptData.after.parameter
65
+ if (this.scriptData.presort) params["script.presort"] = this.scriptData.presort.name
66
+ if (this.scriptData.presort?.parameter) params["script.presort.param"] = this.scriptData.presort.parameter
67
67
 
68
- if (this.scriptData.prerequest) params["script.prerequest"] = this.scriptData.after.name
69
- if (this.scriptData.prerequest?.parameter) params["script.prerequest.param"] = this.scriptData.after.parameter
68
+ if (this.scriptData.prerequest) params["script.prerequest"] = this.scriptData.prerequest.name
69
+ if (this.scriptData.prerequest?.parameter) params["script.prerequest.param"] = this.scriptData.prerequest.parameter
70
70
 
71
71
  if (this.queries.length !== 0) params["query"] = this.queries
72
72
 
73
- let portals = Object.keys(this.portals)
73
+ let portals: (keyof typeof this.portals)[] = Object.keys(this.portals)
74
74
  params["portal"] = portals
75
75
  for (let portal of portals) {
76
- params[`offset.${portal}`] = this.portals[portal].offset
77
- params[`limit.${portal}`] = this.portals[portal].limit
76
+ params[`offset.${portal.toString()}`] = this.portals[portal]?.offset
77
+ params[`limit.${portal.toString()}`] = this.portals[portal]?.limit
78
78
  }
79
79
 
80
80
  return params
@@ -89,16 +89,16 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
89
89
  if (this.scriptData.after) params.set("script", this.scriptData.after.name)
90
90
  if (this.scriptData.after?.parameter) params.set("script.param", this.scriptData.after.parameter)
91
91
 
92
- if (this.scriptData.presort) params.set("script.presort", this.scriptData.after.name)
93
- if (this.scriptData.presort?.parameter) params.set("script.presort.param", this.scriptData.after.parameter)
92
+ if (this.scriptData.presort) params.set("script.presort", this.scriptData.presort.name)
93
+ if (this.scriptData.presort?.parameter) params.set("script.presort.param", this.scriptData.presort.parameter)
94
94
 
95
- if (this.scriptData.prerequest) params.set("script.prerequest", this.scriptData.after.name)
96
- if (this.scriptData.prerequest?.parameter) params.set("script.prerequest.param", this.scriptData.after.parameter)
95
+ if (this.scriptData.prerequest) params.set("script.prerequest", this.scriptData.prerequest.name)
96
+ if (this.scriptData.prerequest?.parameter) params.set("script.prerequest.param", this.scriptData.prerequest.parameter)
97
97
 
98
- let portals = Object.keys(this.portals)
98
+ let portals: (keyof typeof this.portals)[] = Object.keys(this.portals)
99
99
  for (let portal of portals) {
100
- params.set(`_offset.${portal}`, this.portals[portal].limit.toString())
101
- params.set(`_offset.${portal}`, this.portals[portal].offset.toString())
100
+ params.set(`_offset.${portal.toString()}`, (this.portals[portal]?.limit || "").toString())
101
+ params.set(`_offset.${portal.toString()}`, (this.portals[portal]?.offset || "").toString())
102
102
  }
103
103
  params.set('portal', JSON.stringify(portals))
104
104
 
@@ -139,23 +139,29 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
139
139
  body: is_find ? JSON.stringify(this.generateParamsBody(offset, limit)) : undefined,
140
140
  }
141
141
 
142
- let res = await this.layout.database.apiRequest<ApiRecordResponseObj>(
143
- endpoint,
144
- reqData
145
- )
146
- if (res.messages[0].code === "0") {
147
- // console.log("RESOLVING")
148
- if (!this.layout.metadata) await this.layout.getLayoutMeta()
149
- return res.response.data.map(item => {
150
- return new LayoutRecord(this.layout, item.recordId, item.modId, item.fieldData, item.portalData)
151
- })
152
- }
153
- else if (res.messages[0].code == "401") {
154
- // No records found, so return empty set
155
- return []
156
- }
157
- else {
158
- throw new FMError(res.messages[0].code, res.httpStatus, res, trace)
142
+ try {
143
+ let res = await this.layout.database.apiRequestJSON<ApiRecordResponseObj>(
144
+ endpoint,
145
+ reqData
146
+ )
147
+ if (res.messages[0].code === "0" && res.response) {
148
+ // console.log("RESOLVING")
149
+ if (!this.layout.metadata) await this.layout.getLayoutMeta()
150
+ return res.response.data.map(item => {
151
+ return new LayoutRecord(this.layout, item.recordId, item.modId, item.fieldData, item.portalData)
152
+ })
153
+ }
154
+ else {
155
+ throw new FMError(res.messages[0].code, res.httpStatus, res, trace)
156
+ }
157
+ } catch(e) {
158
+ if (e instanceof FMError) {
159
+ if (e.code === 401) {
160
+ // No records found, so return empty set
161
+ return []
162
+ }
163
+ }
164
+ throw e
159
165
  }
160
166
  }
161
167
 
@@ -4,7 +4,7 @@ import { PortalRecord } from "./portalRecord.js";
4
4
  import { Portal } from "./portal.js";
5
5
  import { LayoutInterface } from "../layouts/layoutInterface.js";
6
6
  import { LayoutRecordBase } from "./layoutRecordBase.js";
7
- import { ApiPortalData } from "../models/apiResults.js";
7
+ import { ApiPortalData, ApiRowDataDef } from "../models/apiResults.js";
8
8
  import { LayoutBase } from "../layouts/layoutBase.js";
9
9
  import { FieldBase, FieldValue } from "./fieldBase.js";
10
10
  export declare class LayoutRecord<LAYOUT extends LayoutInterface> extends RecordBase<LAYOUT["fields"]> implements LayoutRecordBase {
@@ -17,5 +17,6 @@ export declare class LayoutRecord<LAYOUT extends LayoutInterface> extends Record
17
17
  get(): Promise<this>;
18
18
  duplicate(): Promise<LayoutRecord<LAYOUT>>;
19
19
  delete(): Promise<void>;
20
- toObject(filter?: (a: FieldBase<FieldValue>) => any, portalFilter?: (a: Portal<any>) => any, portalRowFilter?: (a: PortalRecord<never>) => any, portalFieldFilter?: (a: FieldBase<FieldValue>) => any): Partial<Omit<import("../models/apiResults.js").ApiRowDataDef, "portalDataInfo">>;
20
+ fieldsToObject(filter?: (a: FieldBase<FieldValue>) => boolean): Omit<ApiRowDataDef, "portalData">;
21
+ toObject(filter?: (a: FieldBase<FieldValue>) => any, portalFilter?: (a: Portal<any>) => any, portalRowFilter?: (a: PortalRecord<never>) => any, portalFieldFilter?: (a: FieldBase<FieldValue>) => any): ApiRowDataDef;
21
22
  }