@jd-data-limited/easy-fm 0.0.1 → 0.0.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/README.md CHANGED
@@ -12,47 +12,160 @@ a [FileMaker server](https://www.claris.com/filemaker/server/). This module inte
12
12
  2. Create a FileMaker database account for easy-fm to use. This account must have the 'Access via FileMaker Data API (
13
13
  fmrest)' extended privilege
14
14
 
15
+ ## Table of contents
15
16
 
16
- ## Usage examples
17
+ 1. [Connecting to a database](#connecting-to-a-database)
18
+ 2. [Working with records](#working-with-records)
19
+ 3. [Performing find requests](#perform-find-requests)
20
+ 4. [Scripts](#scripts)
21
+ 5. [Index](#index)
22
+
23
+ ## Connecting to a database
24
+
25
+ easy-fm currently does not support connecting to external data sources, or authenticating by any method other than plain
26
+ FileMaker authentication.
17
27
 
18
- 1. Get the first record on the 'table1' layout
19
28
  ```javascript
20
29
  import fm, {FMError} from "easy-fm"; // Import the module
21
30
  const connection = new fm(); // This variable will be used for interacting with the server
22
31
 
23
32
  connection.login(hostname, database, username, password).then(async token => { // Login
24
- let layout = connection.getLayout("layout1")
25
- let record = layout.getRecord(1)
26
- await record.get() // Fetch the data for that record
27
- console.log(record)
33
+
28
34
  })
29
35
  ```
30
36
 
31
- 2. Get all related portal records
37
+ ## Working with records
38
+
39
+ When running scripts or interacting with records, the first step that you need to do is get the layout that you want to
40
+ use
41
+
42
+ ```javascript
43
+ let layout = connection.getLayout("layout1") // Get the layout known as 'layout1'
44
+ ```
45
+
46
+ Once you have the layout, you can perform a multitude of tasks
47
+
48
+ ### Get a single record using its RecordID
49
+
50
+ [What's a RecordID?](#recordid)
51
+
52
+ ```javascript
53
+ let record_id = 1
54
+ let record = layout.getRecord(record_id)
55
+
56
+ await record.get() // The 'getRecord' method does not automatically get that record's values, so this step does that instead
57
+
58
+ let field = record.getField("field1")
59
+ console.log(field.value) // Get the value of 'field1'
60
+ ```
61
+
62
+ ### Modify a record
63
+
64
+ WARNING: The commit step is mandatory. Otherwise the changes will never be uploaded
65
+
32
66
  ```javascript
33
- await record.get() // Fetch the record's data
34
- let portal = record.getPortal("portal1") // 'portal1' should be the name you assigned the portal object, when creating the layout
35
- console.log(portal.records)
67
+ let record_id = 1
68
+ let record = layout.getRecord(record_id)
69
+
70
+ await record.get() // The 'getRecord' method does not automatically get that record's values, so this step does that instead
71
+ record.getField("field1").set("This is a value")
72
+ record.getField("field2").set("This is also a value")
73
+ await record.commit()
36
74
  ```
37
75
 
38
- 3. Run a script
76
+ ### Create a new record
77
+
78
+ WARNING: The record is not created on the database until a commit is done
79
+
39
80
  ```javascript
40
- let script = connection.script("script_name", "this is a parameter") // Create a new script object using the script name and parameter (optional)
41
-
42
- // Get the layout we want to run the script on
43
- let layout = connection.getLayout("layout1")
44
-
45
- // Run the script on the layout
46
- let result = await layout.runScript(script)
47
- console.log(result)
81
+ let record = await layout.createRecord()
82
+ record.getField("field1").set("ABC")
83
+ record.getField("field2").set("DEF")
84
+ await record.commit()
48
85
  ```
49
86
 
50
- 4. Perform a find
87
+ ### Downloading container field files
88
+
89
+ ```javascript
90
+ let record_id = 1
91
+ let record = layout.getRecord(record_id)
92
+
93
+ await record.get() // The 'getRecord' method does not automatically get that record's values, so this step does that instead
94
+
95
+ let container = record.getField("container")
96
+ container.download().then(stream => {
97
+ // Returns an IncomingMessage, which is an extension of ReadableStream
98
+ })
99
+ ```
100
+
101
+ [IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)
102
+ , [ReadableStream](https://nodejs.org/api/stream.html#class-streamreadable)
103
+
104
+ ### Uploading container files
105
+
106
+ When uploading files, they should be uploaded as a [Buffer](https://nodejs.org/api/buffer.html) object, along with a
107
+ filename (string) and MIME (also string)
108
+
109
+ MIME types are not currently automatically detected
110
+
111
+ ```javascript
112
+ const fs = require("fs")
113
+ let filename = "image.jpg"
114
+ let buffer = fs.readdirSync("./" + filename)
115
+ let mime = "image/jpeg"
116
+
117
+ let record_id = 1
118
+ let record = layout.getRecord(record_id)
119
+ await record.get() // The 'getRecord' method does not automatically get that record's values, so this step does that instead
120
+
121
+ let container = record.getField("container")
122
+ container.upload(buffer, filename, mime).then(() => {
123
+ console.log("UPLOAD SUCCESSFUL!")
124
+ })
125
+ ```
126
+ [(Mozilla) Common MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)
127
+
128
+ ### Read and modify portal information
129
+
130
+ To be able to read portal information for a record, you'll need to put a portal on the layout you are using. Make sure
131
+ you also:
132
+
133
+ - Give the portal object a name
134
+ - Include the exact fields you need in the portal. Any fields you leave out will not be accessible by node.js, and
135
+ putting extra fields in is not a good idea.
136
+
137
+ ```javascript
138
+ let record = layout.getRecord(1)
139
+
140
+ // Portal data is downloaded when the record is fetched
141
+ await record.get()
142
+ let portal = record.getPortal("Portal1")
143
+
144
+ for (let _record of portal.records) {
145
+ // Runs for all records in the portal
146
+ let field = _record.getField("field2")
147
+ console.log(field.value)
148
+ field.set("GHI")
149
+ }
150
+ ```
151
+
152
+ **WARNING**: Commiting a related portal record will also commit any changes to the parent record as well as any other
153
+ portal records.
154
+
155
+ ## Perform find requests
156
+
157
+ Performing find requests is one of the most common database operations
158
+
159
+ ![img.png](img.png)
160
+
161
+ The image above is how the find request would look when doing it in a FileMaker script. This should hopefully help you
162
+ understand how the find request process works.
163
+
51
164
  ```javascript
52
165
  let find = layout.newFind() // Create a new find operation
53
166
 
54
167
  find.addRequests( // Specify the find criteria
55
- {"PrimaryKey": "AAAAA", "ModifiedBy": "BBBB"},
168
+ {"PrimaryKey": "AAAAA", "ModifiedBy": "BBBB"},
56
169
  {"CreatedBy": "BBBB"}
57
170
  )
58
171
 
@@ -60,5 +173,21 @@ find.addSort("CratedBy", "ascend") // Sort the results in ascending order
60
173
  let records = await find.find() // Perform the find
61
174
  console.log(records)
62
175
  ```
63
- This is the same as the following find request in FileMaker:
64
- ![img.png](img.png)
176
+
177
+ ### Scripts
178
+
179
+ Running scripts is another operation you may need to do regularly. This one is fairly straight-forward in how it works
180
+
181
+ ```javascript
182
+ let layout = connection.getLayout("layout1")
183
+ let script = connection.script("MyFileMakerScript", "This is a parameter")
184
+ let result = await layout.runScript(script)
185
+ console.log(result)
186
+ ```
187
+
188
+ ## Index
189
+
190
+ ### RecordID
191
+
192
+ This is not a custom field that can be set and/or changed. You can get a record's ID from within FileMaker by
193
+ using `Get(RecordID)`
package/decs.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  declare module "fs"
2
2
  declare module "events"
3
3
  declare module "path"
4
- declare module "url"
4
+ declare module "url"
5
+ declare module "node-fetch"
6
+ declare module "btoa"
7
+ declare module "buffer"
package/index.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
2
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
3
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -8,21 +7,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
8
  });
10
9
  };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.FMError = void 0;
13
10
  // const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
14
- const node_fetch_1 = require("node-fetch");
15
- const events_1 = require("events");
11
+ import fetch, { File, FormData } from 'node-fetch';
12
+ import { EventEmitter } from "events";
16
13
  // @ts-ignore
17
- const fs_1 = require("fs");
14
+ import fs from "fs";
18
15
  // @ts-ignore
19
- const path_1 = require("path");
16
+ import path from "path";
20
17
  // @ts-ignore
21
- const url_1 = require("url");
22
- const btoa = require("btoa");
18
+ import { fileURLToPath } from "url";
19
+ import * as https from "https";
20
+ // import * as btoa from "btoa";
23
21
  // @ts-ignore
24
- const errs = JSON.parse(fs_1.default.readFileSync(path_1.default.join(path_1.default.dirname((0, url_1.fileURLToPath)(import.meta.url)), 'fmErrors.json')).toString());
25
- class FileMakerConnection {
22
+ const errs = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'fmErrors.json')).toString());
23
+ export default class FileMakerConnection {
26
24
  constructor() {
27
25
  }
28
26
  get endpoint() {
@@ -44,7 +42,7 @@ class FileMakerConnection {
44
42
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
45
43
  if (!this.token)
46
44
  reject(new Error("Not logged in"));
47
- let _fetch = yield (0, node_fetch_1.default)(`${this.endpoint}/sessions/${this.token}`, {
45
+ let _fetch = yield fetch(`${this.endpoint}/sessions/${this.token}`, {
48
46
  method: "DELETE",
49
47
  headers: {
50
48
  "content-type": "application/json"
@@ -66,13 +64,13 @@ class FileMakerConnection {
66
64
  }
67
65
  createSession() {
68
66
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
69
- (0, node_fetch_1.default)(`${this.endpoint}/sessions`, {
67
+ fetch(`${this.endpoint}/sessions`, {
70
68
  hostname: this.hostname,
71
69
  port: 443,
72
70
  method: "POST",
73
71
  headers: {
74
72
  "Content-Type": "application/json",
75
- "Authorization": "Basic " + btoa(this.username + ":" + this.password)
73
+ "Authorization": "Basic " + Buffer.from(this.username + ":" + this.password).toString("base64")
76
74
  }
77
75
  }).then(res => {
78
76
  console.log(res);
@@ -97,14 +95,14 @@ class FileMakerConnection {
97
95
  getLayout(name) {
98
96
  return new layout(this, name);
99
97
  }
100
- apiRequest(url, options) {
98
+ apiRequest(url, options = {}) {
101
99
  return __awaiter(this, void 0, void 0, function* () {
102
100
  if (!options.headers)
103
101
  options.headers = {};
104
102
  options.headers["content-type"] = options.headers["content-type"] ? options.headers["content-type"] : "application/json";
105
103
  options.headers["authorization"] = "Bearer " + this.token;
106
104
  options.rejectUnauthorized = this.rejectUnauthroized;
107
- let _fetch = yield (0, node_fetch_1.default)(url, options);
105
+ let _fetch = yield fetch(url, options);
108
106
  let data = yield _fetch.json();
109
107
  return data;
110
108
  });
@@ -133,7 +131,6 @@ class FileMakerConnection {
133
131
  return { name, parameter };
134
132
  }
135
133
  }
136
- exports.default = FileMakerConnection;
137
134
  class layout {
138
135
  constructor(conn, name) {
139
136
  this.conn = conn;
@@ -145,26 +142,17 @@ class layout {
145
142
  getScript(script) {
146
143
  return new script(this, script);
147
144
  }
148
- createRecord(body = {}) {
149
- // console.log(fieldData)
150
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
151
- this.conn.apiRequest(`${this.endpoint}/records`, {
152
- port: 443,
153
- method: "POST",
154
- body: JSON.stringify(body)
155
- })
156
- .then(res => {
157
- if (res.messages[0].code === "0") {
158
- resolve(new record(this, res.response.recordId, res.response.modId));
159
- }
160
- else {
161
- reject(new FMError(res.messages[0].code, res.status, res));
145
+ createRecord() {
146
+ return new Promise((resolve, reject) => {
147
+ // Get the layout's metadata
148
+ this.conn.apiRequest(`${this.endpoint}`).then(res => {
149
+ let fields = {};
150
+ for (let _field of res.response.fieldMetaData) {
151
+ fields[_field.name] = "";
162
152
  }
163
- })
164
- .catch(e => {
165
- reject(e);
153
+ resolve(new record(this, -1, 0, fields));
166
154
  });
167
- }));
155
+ });
168
156
  }
169
157
  getRecord(recordId) {
170
158
  return new record(this, recordId);
@@ -195,8 +183,17 @@ class layout {
195
183
  });
196
184
  }));
197
185
  }
186
+ getLayoutMeta() {
187
+ return new Promise((resolve, reject) => {
188
+ this.conn.apiRequest(this.endpoint).then(res => {
189
+ this.metadata = res.response;
190
+ resolve(this);
191
+ })
192
+ .catch(e => reject(e));
193
+ });
194
+ }
198
195
  }
199
- class record extends events_1.EventEmitter {
196
+ class record extends EventEmitter {
200
197
  constructor(layout, recordId, modId = recordId, fieldData = {}, portalData = null) {
201
198
  super();
202
199
  this.layout = layout;
@@ -235,6 +232,8 @@ class record extends events_1.EventEmitter {
235
232
  }
236
233
  get() {
237
234
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
235
+ if (!this.layout.metadata)
236
+ yield this.layout.getLayoutMeta();
238
237
  this.layout.conn.apiRequest(this.endpoint, {
239
238
  port: 443,
240
239
  method: "GET"
@@ -258,11 +257,35 @@ class record extends events_1.EventEmitter {
258
257
  });
259
258
  }));
260
259
  }
261
- save(extraBody = {}) {
260
+ commit(extraBody = {}) {
262
261
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
263
262
  let data = this.toObject();
264
263
  delete data.recordId;
265
264
  delete data.modId;
265
+ if (this.recordId === -1) {
266
+ // This is a new record
267
+ this.layout.conn.apiRequest(`${this.layout.endpoint}/records`, {
268
+ port: 443,
269
+ method: "POST",
270
+ body: JSON.stringify({
271
+ fieldData: data.fieldData
272
+ })
273
+ })
274
+ .then(res => {
275
+ if (res.messages[0].code === "0") {
276
+ this.recordId = res.response.recordId;
277
+ this.modId = res.response.modId;
278
+ resolve(this);
279
+ }
280
+ else {
281
+ reject(new FMError(res.messages[0].code, res.status, res));
282
+ }
283
+ })
284
+ .catch(e => {
285
+ reject(e);
286
+ });
287
+ return;
288
+ }
266
289
  for (let item of Object.keys(extraBody))
267
290
  data[item] = extraBody[item];
268
291
  this.layout.conn.apiRequest(this.endpoint, {
@@ -322,14 +345,26 @@ class field {
322
345
  this.edited = false;
323
346
  }
324
347
  set(content) {
348
+ if (this.dataType === "container")
349
+ throw "Cannot set container value using set(). Use upload() instead.";
325
350
  this.value = content;
326
351
  this.edited = true;
327
352
  }
328
- containerUpload(buffer, filename, mime) {
353
+ get dataType() {
354
+ if (this.record instanceof portalItem) {
355
+ return this.record.layout.metadata.portalMetaData.find(name => name === this.id).result;
356
+ }
357
+ else {
358
+ return this.record.layout.metadata.fieldMetaData.find(name => name === this.id).result;
359
+ }
360
+ }
361
+ upload(buffer, filename, mime) {
362
+ if (this.dataType !== "container")
363
+ throw "Cannot upload a file to the field; " + this.id + " (not a container field)";
329
364
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
330
- let form = new node_fetch_1.FormData();
331
- form.append("upload", new node_fetch_1.File([buffer], filename, { type: mime }));
332
- let _fetch = yield (0, node_fetch_1.default)(`${this.record.endpoint}/containers/${this.id}/1`, {
365
+ let form = new FormData();
366
+ form.append("upload", new File([buffer], filename, { type: mime }));
367
+ let _fetch = yield fetch(`${this.record.endpoint}/containers/${this.id}/1`, {
333
368
  method: "POST",
334
369
  headers: { "Authorization": "Bearer " + this.record.layout.conn.token },
335
370
  body: form
@@ -346,6 +381,13 @@ class field {
346
381
  .catch(e => { reject(e); });
347
382
  }));
348
383
  }
384
+ download() {
385
+ return new Promise((resolve, reject) => {
386
+ https.get(this.value.toString(), (res) => {
387
+ resolve(res);
388
+ });
389
+ });
390
+ }
349
391
  }
350
392
  class portal {
351
393
  constructor(record, name, records = []) {
@@ -366,8 +408,8 @@ class portalItem extends record {
366
408
  attachPortal(portal) {
367
409
  this.portal = portal;
368
410
  }
369
- save(extraBody = {}) {
370
- return this.portal.record.save(extraBody);
411
+ commit(extraBody = {}) {
412
+ return this.portal.record.commit(extraBody);
371
413
  }
372
414
  toObject(fieldFilter) {
373
415
  super.toObject();
@@ -439,7 +481,7 @@ class find {
439
481
  });
440
482
  }
441
483
  }
442
- class FMError extends Error {
484
+ export class FMError extends Error {
443
485
  constructor(code, httpStatus, res) {
444
486
  super(code);
445
487
  this.httpStatus = httpStatus;
@@ -448,7 +490,6 @@ class FMError extends Error {
448
490
  this.message = errs.find(err => err.e === this.code) || "Unknown error";
449
491
  }
450
492
  }
451
- exports.FMError = FMError;
452
493
  //
453
494
  // module.exports = {
454
495
  // default: {FileMakerConnection}
package/index.ts CHANGED
@@ -4,7 +4,7 @@ import fetch, {
4
4
  blobFrom,
5
5
  blobFromSync,
6
6
  File,
7
- fileFrom,
7
+ fileFrom,ublish
8
8
  fileFromSync,
9
9
  FormData,
10
10
  Headers,
@@ -18,7 +18,8 @@ import fs from "fs"
18
18
  import path from "path"
19
19
  // @ts-ignore
20
20
  import { fileURLToPath } from "url"
21
- import btoa = require("btoa");
21
+ import * as https from "https";
22
+ // import * as btoa from "btoa";
22
23
 
23
24
  // @ts-ignore
24
25
  const errs = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'fmErrors.json')).toString())
@@ -41,7 +42,7 @@ export default class FileMakerConnection {
41
42
  private username: any;
42
43
  private password: any;
43
44
  private rejectUnauthroized: boolean;
44
-
45
+
45
46
  constructor() {
46
47
  }
47
48
 
@@ -95,7 +96,7 @@ export default class FileMakerConnection {
95
96
  method: "POST",
96
97
  headers: {
97
98
  "Content-Type": "application/json",
98
- "Authorization": "Basic " + btoa(this.username + ":" + this.password)
99
+ "Authorization": "Basic " + Buffer.from(this.username + ":" + this.password).toString("base64")
99
100
  }
100
101
  }).then(res => {
101
102
  console.log(res)
@@ -117,11 +118,11 @@ export default class FileMakerConnection {
117
118
  })
118
119
  }
119
120
 
120
- getLayout(name) {
121
+ getLayout(name): layout {
121
122
  return new layout(this, name)
122
123
  }
123
124
 
124
- async apiRequest(url, options): Promise<any> {
125
+ async apiRequest(url: string | Request, options: any = {}): Promise<any> {
125
126
  if (!options.headers) options.headers = {}
126
127
  options.headers["content-type"] = options.headers["content-type"] ? options.headers["content-type"] : "application/json"
127
128
  options.headers["authorization"] = "Bearer " + this.token
@@ -160,6 +161,7 @@ export default class FileMakerConnection {
160
161
  class layout {
161
162
  readonly conn: FileMakerConnection;
162
163
  protected name: string;
164
+ metadata: any;
163
165
  constructor(conn: FileMakerConnection, name: string) {
164
166
  this.conn = conn
165
167
  this.name = name
@@ -173,26 +175,16 @@ class layout {
173
175
  return new script(this, script)
174
176
  }
175
177
 
176
- createRecord(body = {}): Promise<record | Error> {
177
- // console.log(fieldData)
178
- return new Promise(async (resolve, reject) => {
179
- this.conn.apiRequest(`${this.endpoint}/records`, {
180
- port: 443,
181
- method: "POST",
182
- body: JSON.stringify(body)
178
+ createRecord(): Promise<record | Error | void> {
179
+ return new Promise((resolve, reject) => {
180
+ // Get the layout's metadata
181
+ this.conn.apiRequest(`${this.endpoint}`).then(res => {
182
+ let fields = {}
183
+ for (let _field of res.response.fieldMetaData) {
184
+ fields[_field.name] = ""
185
+ }
186
+ resolve(new record(this, -1, 0, fields))
183
187
  })
184
- .then(res => {
185
- if (res.messages[0].code === "0") {
186
- resolve(
187
- new record(this, res.response.recordId, res.response.modId)
188
- )
189
- } else {
190
- reject(new FMError(res.messages[0].code, res.status, res))
191
- }
192
- })
193
- .catch(e => {
194
- reject(e)
195
- })
196
188
  })
197
189
  }
198
190
 
@@ -225,11 +217,21 @@ class layout {
225
217
  })
226
218
  })
227
219
  }
220
+
221
+ public getLayoutMeta(): Promise<layout | FMError> {
222
+ return new Promise((resolve, reject) => {
223
+ this.conn.apiRequest(this.endpoint).then(res => {
224
+ this.metadata = res.response
225
+ resolve(this)
226
+ })
227
+ .catch(e => reject(e))
228
+ })
229
+ }
228
230
  }
229
231
 
230
232
  class record extends EventEmitter {
231
233
  readonly layout: layout;
232
- readonly recordId: number;
234
+ public recordId: number;
233
235
  modId: number;
234
236
  fields: field[];
235
237
  readonly portals: portal[];
@@ -277,6 +279,8 @@ class record extends EventEmitter {
277
279
 
278
280
  get() {
279
281
  return new Promise(async (resolve, reject) => {
282
+ if (!this.layout.metadata) await this.layout.getLayoutMeta()
283
+
280
284
  this.layout.conn.apiRequest(this.endpoint, {
281
285
  port: 443,
282
286
  method: "GET"
@@ -299,12 +303,37 @@ class record extends EventEmitter {
299
303
  })
300
304
  }
301
305
 
302
- save(extraBody = {}) {
306
+ commit(extraBody = {}): Promise<record | FMError> {
303
307
  return new Promise(async (resolve, reject) => {
304
308
  let data = this.toObject()
305
309
  delete data.recordId
306
310
  delete data.modId
307
311
 
312
+ if (this.recordId === -1) {
313
+ // This is a new record
314
+ this.layout.conn.apiRequest(`${this.layout.endpoint}/records`, {
315
+ port: 443,
316
+ method: "POST",
317
+ body: JSON.stringify({
318
+ fieldData: data.fieldData
319
+ })
320
+ })
321
+ .then(res => {
322
+ if (res.messages[0].code === "0") {
323
+ this.recordId = res.response.recordId
324
+ this.modId = res.response.modId
325
+ resolve(this)
326
+ } else {
327
+ reject(new FMError(res.messages[0].code, res.status, res))
328
+ }
329
+ })
330
+ .catch(e => {
331
+ reject(e)
332
+ })
333
+
334
+ return
335
+ }
336
+
308
337
  for (let item of Object.keys(extraBody)) data[item] = extraBody[item]
309
338
  this.layout.conn.apiRequest(this.endpoint, {
310
339
  port: 443,
@@ -376,11 +405,21 @@ class field {
376
405
  }
377
406
 
378
407
  set(content) {
408
+ if (this.dataType === "container") throw "Cannot set container value using set(). Use upload() instead."
379
409
  this.value = content
380
410
  this.edited = true
381
411
  }
382
412
 
383
- containerUpload(buffer, filename, mime): Promise<void | FMError> {
413
+ get dataType() {
414
+ if (this.record instanceof portalItem) {
415
+ return this.record.layout.metadata.portalMetaData.find(name => name === this.id).result
416
+ } else {
417
+ return this.record.layout.metadata.fieldMetaData.find(name => name === this.id).result
418
+ }
419
+ }
420
+
421
+ upload(buffer: Buffer, filename: string, mime: string): Promise<void | FMError> {
422
+ if (this.dataType !== "container") throw "Cannot upload a file to the field; " + this.id + " (not a container field)"
384
423
  return new Promise(async (resolve, reject) => {
385
424
  let form = new FormData()
386
425
  form.append("upload", new File([buffer], filename, {type: mime}))
@@ -401,6 +440,13 @@ class field {
401
440
  .catch(e => {reject(e)})
402
441
  })
403
442
  }
443
+ download() {
444
+ return new Promise((resolve, reject) => {
445
+ https.get(this.value.toString(), (res) => {
446
+ resolve(res)
447
+ })
448
+ })
449
+ }
404
450
  }
405
451
 
406
452
  class portal {
@@ -430,8 +476,8 @@ class portalItem extends record {
430
476
  this.portal = portal
431
477
  }
432
478
 
433
- save(extraBody = {}) {
434
- return this.portal.record.save(extraBody)
479
+ commit(extraBody = {}) {
480
+ return this.portal.record.commit(extraBody)
435
481
  }
436
482
 
437
483
  toObject(fieldFilter): any {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jd-data-limited/easy-fm",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "dependencies": {
5
5
  "@types/btoa": "^1.2.3",
6
6
  "@types/events": "^3.0.0",
package/tsconfig.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "es2015",
4
- "module": "commonjs",
4
+ "module": "es2022",
5
5
  "lib": ["es2021.intl", "es2015"],
6
+ "moduleResolution": "Node"
6
7
  },
7
8
  "files": ["index.ts"]
8
9
  }