@jd-data-limited/easy-fm 1.1.4-alpha1 → 1.1.6-alpha1
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/.idea/php.xml +18 -0
- package/README.md +110 -14
- package/index.js +51 -2
- package/index.ts +57 -3
- package/package.json +1 -1
package/.idea/php.xml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="MessDetectorOptionsConfiguration">
|
|
4
|
+
<option name="transferred" value="true" />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="PHPCSFixerOptionsConfiguration">
|
|
7
|
+
<option name="transferred" value="true" />
|
|
8
|
+
</component>
|
|
9
|
+
<component name="PHPCodeSnifferOptionsConfiguration">
|
|
10
|
+
<option name="transferred" value="true" />
|
|
11
|
+
</component>
|
|
12
|
+
<component name="PhpStanOptionsConfiguration">
|
|
13
|
+
<option name="transferred" value="true" />
|
|
14
|
+
</component>
|
|
15
|
+
<component name="PsalmOptionsConfiguration">
|
|
16
|
+
<option name="transferred" value="true" />
|
|
17
|
+
</component>
|
|
18
|
+
</project>
|
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# easy-fm
|
|
2
2
|
|
|
3
|
+
Making NodeJS + FileMaker easier than ever
|
|
4
|
+
|
|
3
5
|
easy-fm is a Node.js module that allows you to interact with
|
|
4
6
|
a [FileMaker database](https://www.claris.com/filemaker/) stored on
|
|
5
|
-
a [FileMaker server](https://www.claris.com/filemaker/server/)
|
|
7
|
+
a [FileMaker server](https://www.claris.com/filemaker/server/)
|
|
8
|
+
or [FileMaker Cloud](https://store.claris.com/filemaker-cloud). This module interacts with your server using the
|
|
6
9
|
[FileMaker Data API](https://help.claris.com/en/data-api-guide/content/index.html).
|
|
7
10
|
|
|
8
11
|
## FileMaker setup instructions
|
|
@@ -17,6 +20,10 @@ a [FileMaker server](https://www.claris.com/filemaker/server/). This module inte
|
|
|
17
20
|
## Table of contents
|
|
18
21
|
|
|
19
22
|
1. [Connecting to a database](#connecting-to-a-database)
|
|
23
|
+
1. [Username and password](#username-and-password)
|
|
24
|
+
2. [Token](#token)
|
|
25
|
+
3. [OAuth](#oauth)
|
|
26
|
+
4. [Claris Account (FileMaker Cloud)](#claris-account--filemaker-cloud-)
|
|
20
27
|
2. [Working with records](#working-with-records)
|
|
21
28
|
3. [Performing find requests](#perform-find-requests)
|
|
22
29
|
4. [Scripts](#scripts)
|
|
@@ -31,13 +38,101 @@ FileMaker authentication.
|
|
|
31
38
|
|
|
32
39
|
```javascript
|
|
33
40
|
import fm, {FMError} from "easy-fm"; // Import the module
|
|
34
|
-
const connection = new fm(
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
const connection = new fm(
|
|
42
|
+
// Connection options (see below)
|
|
43
|
+
);
|
|
37
44
|
|
|
45
|
+
connection.login().then(token => {
|
|
46
|
+
// Record operations can only be performed after a successful login
|
|
38
47
|
})
|
|
39
48
|
```
|
|
40
49
|
|
|
50
|
+
> **NOTE:** A connection will only give you access to the layouts in the database you are connected to, and not the
|
|
51
|
+
> layouts
|
|
52
|
+
> in
|
|
53
|
+
> the external sources that you have specified.
|
|
54
|
+
>
|
|
55
|
+
> If you need to interact with layouts on multiple databases, you need to open one connection per database.
|
|
56
|
+
|
|
57
|
+
## Username and password
|
|
58
|
+
|
|
59
|
+
This method allows you to use a generic FileMaker account to connect to the database.
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
new fm({
|
|
63
|
+
hostname: "localhost",
|
|
64
|
+
database: {
|
|
65
|
+
database: "MyDatabase", // Do not include the .fmp12 file extension
|
|
66
|
+
method: "filemaker",
|
|
67
|
+
username: "node",
|
|
68
|
+
password: "node123"
|
|
69
|
+
},
|
|
70
|
+
externalSources: []
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Supports auto relogin?** Yes
|
|
75
|
+
|
|
76
|
+
## Token
|
|
77
|
+
|
|
78
|
+
If you have already created a session with the FileMaker Data API, you can use this to import your session.
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
new fm({
|
|
82
|
+
hostname: "localhost",
|
|
83
|
+
database: {
|
|
84
|
+
database: "MyDatabase", // Do not include the .fmp12 file extension
|
|
85
|
+
method: "token",
|
|
86
|
+
token: "API token goes here"
|
|
87
|
+
},
|
|
88
|
+
externalSources: []
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Supports auto relogin?** No
|
|
93
|
+
|
|
94
|
+
## OAuth
|
|
95
|
+
|
|
96
|
+
(untested) If your FileMaker server has OAuth configured, you can login using this method.
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
new fm({
|
|
100
|
+
hostname: "localhost",
|
|
101
|
+
database: {
|
|
102
|
+
f
|
|
103
|
+
database: "MyDatabase", // Do not include the .fmp12 file extension
|
|
104
|
+
method: "oauth",
|
|
105
|
+
oauth: {
|
|
106
|
+
requestId: "oauth request ID",
|
|
107
|
+
requestIdentifier: "oatuh identifier"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
externalSources: []
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Supports auto relogin?** No
|
|
115
|
+
|
|
116
|
+
## Claris Account (FileMaker Cloud)
|
|
117
|
+
|
|
118
|
+
(untested) If you'd prefer to use a claris account to login, you can
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
new fm({
|
|
122
|
+
hostname: "localhost",
|
|
123
|
+
database: {
|
|
124
|
+
database: "MyDatabase", // Do not include the .fmp12 file extension
|
|
125
|
+
method: "claris",
|
|
126
|
+
fmid: "" // The FileMaker token provided by Claris
|
|
127
|
+
},
|
|
128
|
+
externalSources: []
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Read more [here](https://help.claris.com/en/data-api-guide/content/log-in-database-session-claris-id.html)
|
|
133
|
+
|
|
134
|
+
**Supports auto relogin?** No
|
|
135
|
+
|
|
41
136
|
---
|
|
42
137
|
|
|
43
138
|
## Working with records
|
|
@@ -49,7 +144,10 @@ use
|
|
|
49
144
|
let layout = connection.getLayout("layout1") // Get the layout known as 'layout1'
|
|
50
145
|
```
|
|
51
146
|
|
|
52
|
-
Once you have the layout, you can perform
|
|
147
|
+
Once you have the layout, you can perform tasks on that layout
|
|
148
|
+
|
|
149
|
+
> **Note:** You will only be able to get and modify fields that are on that layout. If a field is not on the layout, you
|
|
150
|
+
> cannot see or modify it's contents.
|
|
53
151
|
|
|
54
152
|
### Get a single record using its RecordID
|
|
55
153
|
|
|
@@ -78,11 +176,10 @@ record.getField("field1").set("This is a value")
|
|
|
78
176
|
record.getField("field2").set("This is also a value")
|
|
79
177
|
await record.commit()
|
|
80
178
|
```
|
|
179
|
+
> **NOTE:** A commit will also commit any changes made to portal records.
|
|
81
180
|
|
|
82
181
|
### Create a new record
|
|
83
182
|
|
|
84
|
-
WARNING: The record is not created on the database until a commit is done
|
|
85
|
-
|
|
86
183
|
```javascript
|
|
87
184
|
let record = await layout.createRecord()
|
|
88
185
|
record.getField("field1").set("ABC")
|
|
@@ -90,6 +187,8 @@ record.getField("field2").set("DEF")
|
|
|
90
187
|
await record.commit()
|
|
91
188
|
```
|
|
92
189
|
|
|
190
|
+
> **WARNING:** The record is *not* created on the database server until a `commit()` step is done.x
|
|
191
|
+
|
|
93
192
|
### Downloading container field files
|
|
94
193
|
|
|
95
194
|
```javascript
|
|
@@ -112,7 +211,6 @@ container.download().then(stream => {
|
|
|
112
211
|
When uploading files, they should be uploaded as a [Buffer](https://nodejs.org/api/buffer.html) object, along with a
|
|
113
212
|
filename (string) and MIME (also string)
|
|
114
213
|
|
|
115
|
-
MIME types are not currently automatically detected
|
|
116
214
|
|
|
117
215
|
```javascript
|
|
118
216
|
const fs = require("fs")
|
|
@@ -129,7 +227,8 @@ container.upload(buffer, filename, mime).then(() => {
|
|
|
129
227
|
console.log("UPLOAD SUCCESSFUL!")
|
|
130
228
|
})
|
|
131
229
|
```
|
|
132
|
-
|
|
230
|
+
|
|
231
|
+
> Mozilla has a list of common MIME types on their website; [(Mozilla) Common MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)
|
|
133
232
|
|
|
134
233
|
### Read and modify portal information
|
|
135
234
|
|
|
@@ -155,7 +254,7 @@ for (let _record of portal.records) {
|
|
|
155
254
|
}
|
|
156
255
|
```
|
|
157
256
|
|
|
158
|
-
**WARNING**: Commiting a related portal record will also commit any changes to the parent record as well as any other
|
|
257
|
+
> **WARNING**: Commiting a related portal record will also commit any changes to the parent record as well as any other
|
|
159
258
|
portal records.
|
|
160
259
|
|
|
161
260
|
---
|
|
@@ -178,7 +277,7 @@ find.addRequests( // Specify the find criteria
|
|
|
178
277
|
)
|
|
179
278
|
|
|
180
279
|
find.addSort("CreatedBy", "ascend") // Sort the results in ascending order
|
|
181
|
-
let records = await find.
|
|
280
|
+
let records = await find.run() // Perform the find
|
|
182
281
|
console.log(records)
|
|
183
282
|
```
|
|
184
283
|
|
|
@@ -199,9 +298,6 @@ console.log(result)
|
|
|
199
298
|
|
|
200
299
|
## Classes and methods
|
|
201
300
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
301
|
---
|
|
206
302
|
|
|
207
303
|
## Index
|
package/index.js
CHANGED
|
@@ -152,10 +152,11 @@ export default class FileMakerConnection extends EventEmitter {
|
|
|
152
152
|
options.rejectUnauthorized = this.rejectUnauthroized;
|
|
153
153
|
let _fetch = yield fetch(url, options);
|
|
154
154
|
let data = yield _fetch.json();
|
|
155
|
-
|
|
155
|
+
console.log(data.messages[0]);
|
|
156
|
+
if (data.messages[0].code == 952 && autoRelogin) {
|
|
156
157
|
this._token = null;
|
|
157
158
|
yield this.login();
|
|
158
|
-
yield this.apiRequest(url, options, false);
|
|
159
|
+
return yield this.apiRequest(url, options, false);
|
|
159
160
|
}
|
|
160
161
|
return data;
|
|
161
162
|
});
|
|
@@ -385,6 +386,54 @@ class record extends EventEmitter {
|
|
|
385
386
|
getPortal(portal) {
|
|
386
387
|
return this.portals.find(p => p.name === portal);
|
|
387
388
|
}
|
|
389
|
+
delete() {
|
|
390
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
391
|
+
this.layout.database.apiRequest(this.endpoint, {
|
|
392
|
+
port: 443,
|
|
393
|
+
method: "DELETE"
|
|
394
|
+
})
|
|
395
|
+
.then(res => {
|
|
396
|
+
if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
|
|
397
|
+
reject(new FMError(res.response.scriptError, res.status, res));
|
|
398
|
+
}
|
|
399
|
+
else if (res.messages[0].code === "0") {
|
|
400
|
+
this.emit("deleted");
|
|
401
|
+
resolve();
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
reject(new FMError(res.messages[0].code, res.status, res));
|
|
405
|
+
}
|
|
406
|
+
})
|
|
407
|
+
.catch(e => {
|
|
408
|
+
reject(e);
|
|
409
|
+
});
|
|
410
|
+
}));
|
|
411
|
+
}
|
|
412
|
+
duplicate() {
|
|
413
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
414
|
+
this.layout.database.apiRequest(this.endpoint, {
|
|
415
|
+
port: 443,
|
|
416
|
+
method: "POST"
|
|
417
|
+
})
|
|
418
|
+
.then(res => {
|
|
419
|
+
if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
|
|
420
|
+
reject(new FMError(res.response.scriptError, res.status, res));
|
|
421
|
+
}
|
|
422
|
+
else if (res.messages[0].code === "0") {
|
|
423
|
+
let data = this.toObject((a) => true, (a) => true, (a) => false, (a) => false);
|
|
424
|
+
let _res = new record(this.layout, res.response.recordId, res.response.modId, data.fieldData, data.portalData);
|
|
425
|
+
this.emit("duplicated");
|
|
426
|
+
resolve(_res);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
reject(new FMError(res.messages[0].code, res.status, res));
|
|
430
|
+
}
|
|
431
|
+
})
|
|
432
|
+
.catch(e => {
|
|
433
|
+
reject(e);
|
|
434
|
+
});
|
|
435
|
+
}));
|
|
436
|
+
}
|
|
388
437
|
toObject(filter = (a) => a.edited, portalFilter = (a) => a.records.find(record => record.edited), portalRowFilter = (a) => a.edited, portalFieldFilter = (a) => a.edited) {
|
|
389
438
|
let fields_processed = {};
|
|
390
439
|
for (let field of this.fields.filter(field => filter(field))) {
|
package/index.ts
CHANGED
|
@@ -85,7 +85,12 @@ interface Script {
|
|
|
85
85
|
interface recordObject {
|
|
86
86
|
recordId: number
|
|
87
87
|
modId: number,
|
|
88
|
-
fieldData: any
|
|
88
|
+
fieldData: any,
|
|
89
|
+
portalData: portalDataObject | undefined
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface portalDataObject {
|
|
93
|
+
[key: string]: recordObject
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
export default class FileMakerConnection extends EventEmitter {
|
|
@@ -224,10 +229,11 @@ export default class FileMakerConnection extends EventEmitter {
|
|
|
224
229
|
|
|
225
230
|
let _fetch = await fetch(url, options)
|
|
226
231
|
let data = await _fetch.json()
|
|
227
|
-
|
|
232
|
+
console.log(data.messages[0])
|
|
233
|
+
if (data.messages[0].code == 952 && autoRelogin) {
|
|
228
234
|
this._token = null
|
|
229
235
|
await this.login()
|
|
230
|
-
await this.apiRequest(url, options,false)
|
|
236
|
+
return await this.apiRequest(url, options,false)
|
|
231
237
|
}
|
|
232
238
|
return (data as any)
|
|
233
239
|
}
|
|
@@ -481,6 +487,54 @@ class record extends EventEmitter {
|
|
|
481
487
|
getPortal(portal) {
|
|
482
488
|
return this.portals.find(p => p.name === portal)
|
|
483
489
|
}
|
|
490
|
+
|
|
491
|
+
delete(): Promise<void> {
|
|
492
|
+
return new Promise(async (resolve, reject) => {
|
|
493
|
+
this.layout.database.apiRequest(this.endpoint, {
|
|
494
|
+
port: 443,
|
|
495
|
+
method: "DELETE"
|
|
496
|
+
})
|
|
497
|
+
.then(res => {
|
|
498
|
+
if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
|
|
499
|
+
reject(new FMError(res.response.scriptError, res.status, res))
|
|
500
|
+
} else if (res.messages[0].code === "0") {
|
|
501
|
+
this.emit("deleted")
|
|
502
|
+
resolve()
|
|
503
|
+
} else {
|
|
504
|
+
reject(new FMError(res.messages[0].code, res.status, res))
|
|
505
|
+
}
|
|
506
|
+
})
|
|
507
|
+
.catch(e => {
|
|
508
|
+
reject(e)
|
|
509
|
+
})
|
|
510
|
+
})
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
duplicate(): Promise<record> {
|
|
514
|
+
return new Promise(async (resolve, reject) => {
|
|
515
|
+
this.layout.database.apiRequest(this.endpoint, {
|
|
516
|
+
port: 443,
|
|
517
|
+
method: "POST"
|
|
518
|
+
})
|
|
519
|
+
.then(res => {
|
|
520
|
+
if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
|
|
521
|
+
reject(new FMError(res.response.scriptError, res.status, res))
|
|
522
|
+
} else if (res.messages[0].code === "0") {
|
|
523
|
+
let data = this.toObject((a) => true, (a) => true, (a) => false, (a) => false)
|
|
524
|
+
let _res = new record(this.layout, res.response.recordId, res.response.modId, data.fieldData, data.portalData)
|
|
525
|
+
|
|
526
|
+
this.emit("duplicated")
|
|
527
|
+
resolve(_res)
|
|
528
|
+
} else {
|
|
529
|
+
reject(new FMError(res.messages[0].code, res.status, res))
|
|
530
|
+
}
|
|
531
|
+
})
|
|
532
|
+
.catch(e => {
|
|
533
|
+
reject(e)
|
|
534
|
+
})
|
|
535
|
+
})
|
|
536
|
+
}
|
|
537
|
+
|
|
484
538
|
|
|
485
539
|
toObject(filter = (a) => a.edited,
|
|
486
540
|
portalFilter = (a) => a.records.find(record => record.edited),
|