@jd-data-limited/easy-fm 1.1.6-alpha1 → 1.2.2-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/README.md +61 -235
- package/TEMP/FILEMAKER.txt +218 -0
- package/TEMP/WEBAPP.txt +92 -0
- package/TEMP/config.yaml +40 -0
- package/TEMP/data.json +19837 -0
- package/index.js +297 -119
- package/index.ts +409 -171
- package/package.json +2 -2
- package/test.js +32 -0
package/index.js
CHANGED
|
@@ -20,21 +20,73 @@ import path from "path";
|
|
|
20
20
|
// @ts-ignore
|
|
21
21
|
import { fileURLToPath } from "url";
|
|
22
22
|
import * as https from "https";
|
|
23
|
+
import * as moment from "moment";
|
|
23
24
|
// @ts-ignore
|
|
24
25
|
const errs = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'fmErrors.json')).toString());
|
|
25
|
-
export default class
|
|
26
|
-
constructor(
|
|
26
|
+
export default class FMHost {
|
|
27
|
+
constructor(_hostname, timezoneOffset = 0 - (new Date()).getTimezoneOffset(), verify = true) {
|
|
28
|
+
if (!(/^https?:\/\//).test(_hostname))
|
|
29
|
+
throw "hostname MUST begin with either http:// or https://";
|
|
30
|
+
this.hostname = _hostname;
|
|
31
|
+
this.timezoneOffset = timezoneOffset;
|
|
32
|
+
this.verify = verify;
|
|
33
|
+
}
|
|
34
|
+
listDatabases(credentials) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
let headers = {};
|
|
37
|
+
if (credentials) {
|
|
38
|
+
headers = generateAuthorizationHeaders(credentials);
|
|
39
|
+
}
|
|
40
|
+
let _fetch = yield fetch(`${this.hostname}/fmi/data/v2/databases`, {
|
|
41
|
+
method: "GET",
|
|
42
|
+
headers
|
|
43
|
+
});
|
|
44
|
+
let data = yield _fetch.json();
|
|
45
|
+
// console.log(data.messages[0])
|
|
46
|
+
if (data.messages[0].code === "0") {
|
|
47
|
+
return data.response.databases;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
throw new FMError(data.messages[0].code, data.status, data);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
database(data) {
|
|
56
|
+
return new Database(this, data);
|
|
57
|
+
}
|
|
58
|
+
getMetadata() {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
if (this.metadata)
|
|
61
|
+
return this.metadata;
|
|
62
|
+
let _fetch = yield fetch(`${this.hostname}/fmi/data/v2/productInfo`, {
|
|
63
|
+
method: "GET",
|
|
64
|
+
});
|
|
65
|
+
let data = yield _fetch.json();
|
|
66
|
+
// console.log(data.messages[0])
|
|
67
|
+
if (data.messages[0].code === "0") {
|
|
68
|
+
this.metadata = data.response;
|
|
69
|
+
return data.response;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
throw new FMError(data.messages[0].code, data.status, data);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export class Database extends EventEmitter {
|
|
79
|
+
constructor(host, conn) {
|
|
27
80
|
super();
|
|
28
|
-
this.
|
|
29
|
-
this.name = conn.database
|
|
30
|
-
this.
|
|
31
|
-
this.rejectUnauthroized = rejectUnauthorized;
|
|
81
|
+
this.host = host;
|
|
82
|
+
this.name = conn.database;
|
|
83
|
+
this.connection_details = conn;
|
|
32
84
|
}
|
|
33
85
|
generateExternalSourceLogin(data) {
|
|
34
|
-
if (data.method === "filemaker") {
|
|
35
|
-
let _data = data;
|
|
86
|
+
if (data.credentials.method === "filemaker") {
|
|
87
|
+
let _data = data.credentials;
|
|
36
88
|
return {
|
|
37
|
-
database:
|
|
89
|
+
database: data.database,
|
|
38
90
|
username: _data.username,
|
|
39
91
|
password: _data.password
|
|
40
92
|
};
|
|
@@ -56,36 +108,43 @@ export default class FileMakerConnection extends EventEmitter {
|
|
|
56
108
|
let data = yield _fetch.json();
|
|
57
109
|
// console.log(data)
|
|
58
110
|
this._token = null;
|
|
59
|
-
this.hostname = null;
|
|
60
111
|
resolve();
|
|
61
112
|
}));
|
|
62
113
|
}
|
|
63
114
|
login() {
|
|
64
|
-
return new Promise((resolve, reject) => {
|
|
115
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
try {
|
|
117
|
+
yield this.host.getMetadata();
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
reject(e);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
65
123
|
if (this.token)
|
|
66
124
|
throw new Error("Already logged in. Run logout() first");
|
|
67
|
-
if (this.
|
|
125
|
+
if (this.connection_details.credentials.method === "token") {
|
|
126
|
+
this._token = this.connection_details.credentials.token;
|
|
127
|
+
resolve(this.token);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
68
130
|
fetch(`${this.endpoint}/sessions`, {
|
|
69
|
-
hostname: this.hostname,
|
|
131
|
+
hostname: this.host.hostname,
|
|
70
132
|
port: 443,
|
|
71
133
|
method: "POST",
|
|
72
|
-
headers:
|
|
73
|
-
"Content-Type": "application/json",
|
|
74
|
-
"Authorization": "Basic " + Buffer.from(this.databaseConDetails.database.username + ":" + this.databaseConDetails.database.password).toString("base64")
|
|
75
|
-
},
|
|
134
|
+
headers: generateAuthorizationHeaders(this.connection_details.credentials),
|
|
76
135
|
body: JSON.stringify({
|
|
77
|
-
fmDataSource: this.
|
|
136
|
+
fmDataSource: this.connection_details.externalSources.map(i => {
|
|
78
137
|
let _i = i;
|
|
79
138
|
return this.generateExternalSourceLogin(_i);
|
|
80
139
|
})
|
|
81
140
|
})
|
|
82
141
|
}).then((res) => __awaiter(this, void 0, void 0, function* () {
|
|
142
|
+
let _res = (yield res.json());
|
|
83
143
|
if (res.status === 200) {
|
|
84
144
|
this._token = res.headers.get('x-fm-data-access-token');
|
|
85
145
|
resolve(this._token);
|
|
86
146
|
}
|
|
87
147
|
else {
|
|
88
|
-
let _res = (yield res.json());
|
|
89
148
|
reject(new FMError(_res.messages[0].code, _res.status, res));
|
|
90
149
|
}
|
|
91
150
|
}))
|
|
@@ -93,55 +152,13 @@ export default class FileMakerConnection extends EventEmitter {
|
|
|
93
152
|
reject(e);
|
|
94
153
|
});
|
|
95
154
|
}
|
|
96
|
-
|
|
97
|
-
this._token = this.databaseConDetails.database.token;
|
|
98
|
-
resolve(this.token);
|
|
99
|
-
}
|
|
100
|
-
else if (this.databaseConDetails.database.method === "oauth") {
|
|
101
|
-
fetch(`${this.endpoint}/sessions`, {
|
|
102
|
-
method: "POST",
|
|
103
|
-
headers: {
|
|
104
|
-
"Content-Type": "application/json",
|
|
105
|
-
"X-FM-Data-OAuth-RequestId": this.databaseConDetails.database.oauth.requestId,
|
|
106
|
-
"X-FM-Data-OAuth-Identifier": this.databaseConDetails.database.oauth.requestIdentifier
|
|
107
|
-
},
|
|
108
|
-
body: JSON.stringify({
|
|
109
|
-
fmDataSource: this.databaseConDetails.externalSources.map(i => {
|
|
110
|
-
let _i = i;
|
|
111
|
-
return this.generateExternalSourceLogin(_i);
|
|
112
|
-
})
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
.then(res => res.json())
|
|
116
|
-
.then(res => {
|
|
117
|
-
let _res = res;
|
|
118
|
-
this._token = _res.headers["x-fm-data-access-token"];
|
|
119
|
-
resolve(this.token);
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
else if (this.databaseConDetails.database.method === "claris") {
|
|
123
|
-
fetch(`${this.endpoint}/sessions`, {
|
|
124
|
-
method: "POST",
|
|
125
|
-
headers: {
|
|
126
|
-
"Content-Type": "application/json",
|
|
127
|
-
"Authorization": this.databaseConDetails.database.claris.fmid,
|
|
128
|
-
},
|
|
129
|
-
body: "{}"
|
|
130
|
-
})
|
|
131
|
-
.then(res => res.json())
|
|
132
|
-
.then(res => {
|
|
133
|
-
let _res = res;
|
|
134
|
-
this._token = _res.headers["x-fm-data-access-token"];
|
|
135
|
-
resolve(this.token);
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
});
|
|
155
|
+
}));
|
|
139
156
|
}
|
|
140
157
|
get token() {
|
|
141
158
|
return this._token;
|
|
142
159
|
}
|
|
143
160
|
get endpoint() {
|
|
144
|
-
return
|
|
161
|
+
return `${this.host.hostname}/fmi/data/v2/databases/${this.name}`;
|
|
145
162
|
}
|
|
146
163
|
apiRequest(url, options = {}, autoRelogin = true) {
|
|
147
164
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -149,10 +166,10 @@ export default class FileMakerConnection extends EventEmitter {
|
|
|
149
166
|
options.headers = {};
|
|
150
167
|
options.headers["content-type"] = options.headers["content-type"] ? options.headers["content-type"] : "application/json";
|
|
151
168
|
options.headers["authorization"] = "Bearer " + this._token;
|
|
152
|
-
options.rejectUnauthorized = this.
|
|
169
|
+
options.rejectUnauthorized = this.host.verify;
|
|
153
170
|
let _fetch = yield fetch(url, options);
|
|
154
171
|
let data = yield _fetch.json();
|
|
155
|
-
console.log(data.messages[0])
|
|
172
|
+
// console.log(data.messages[0])
|
|
156
173
|
if (data.messages[0].code == 952 && autoRelogin) {
|
|
157
174
|
this._token = null;
|
|
158
175
|
yield this.login();
|
|
@@ -193,32 +210,30 @@ export default class FileMakerConnection extends EventEmitter {
|
|
|
193
210
|
}
|
|
194
211
|
class layout {
|
|
195
212
|
constructor(database, name) {
|
|
213
|
+
this.records = new layoutRecordManager(this);
|
|
196
214
|
this.database = database;
|
|
197
215
|
this.name = name;
|
|
198
216
|
}
|
|
199
217
|
get endpoint() {
|
|
200
218
|
return `${this.database.endpoint}/layouts/${this.name}`;
|
|
201
219
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
220
|
+
/**
|
|
221
|
+
* @deprecated use layout.records.create() instead
|
|
222
|
+
*/
|
|
205
223
|
createRecord() {
|
|
206
|
-
return
|
|
207
|
-
// Get the layout's metadata
|
|
208
|
-
this.getLayoutMeta().then(layout => {
|
|
209
|
-
let fields = {};
|
|
210
|
-
for (let _field of this.metadata.fieldMetaData) {
|
|
211
|
-
fields[_field.name] = "";
|
|
212
|
-
}
|
|
213
|
-
resolve(new record(this, -1, 0, fields));
|
|
214
|
-
}).catch(e => { reject(e); });
|
|
215
|
-
});
|
|
224
|
+
return this.records.create();
|
|
216
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* @deprecated use layout.records.get() instead
|
|
228
|
+
*/
|
|
217
229
|
getRecord(recordId) {
|
|
218
|
-
return
|
|
230
|
+
return this.records.get(recordId);
|
|
219
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* @deprecated use layout.records.find() instead
|
|
234
|
+
*/
|
|
220
235
|
newFind() {
|
|
221
|
-
return
|
|
236
|
+
return this.records.find();
|
|
222
237
|
}
|
|
223
238
|
runScript(script) {
|
|
224
239
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -245,6 +260,10 @@ class layout {
|
|
|
245
260
|
}
|
|
246
261
|
getLayoutMeta() {
|
|
247
262
|
return new Promise((resolve, reject) => {
|
|
263
|
+
if (this.metadata) {
|
|
264
|
+
resolve(this.metadata);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
248
267
|
this.database.apiRequest(this.endpoint).then(res => {
|
|
249
268
|
this.metadata = res.response;
|
|
250
269
|
resolve(this);
|
|
@@ -253,6 +272,47 @@ class layout {
|
|
|
253
272
|
});
|
|
254
273
|
}
|
|
255
274
|
}
|
|
275
|
+
class layoutRecordManager {
|
|
276
|
+
constructor(layout) {
|
|
277
|
+
this.layout = layout;
|
|
278
|
+
}
|
|
279
|
+
create() {
|
|
280
|
+
return new Promise((resolve, reject) => {
|
|
281
|
+
// Get the layout's metadata
|
|
282
|
+
this.layout.getLayoutMeta().then(layout => {
|
|
283
|
+
let fields = {};
|
|
284
|
+
for (let _field of this.layout.metadata.fieldMetaData) {
|
|
285
|
+
fields[_field.name] = "";
|
|
286
|
+
}
|
|
287
|
+
resolve(new record(this, -1, 0, fields));
|
|
288
|
+
}).catch(e => {
|
|
289
|
+
reject(e);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
get(recordId) {
|
|
294
|
+
return new Promise((resolve, reject) => {
|
|
295
|
+
let record;
|
|
296
|
+
this.layout.getLayoutMeta()
|
|
297
|
+
.then(layout => {
|
|
298
|
+
record = new record(this.layout, recordId);
|
|
299
|
+
return record.get();
|
|
300
|
+
})
|
|
301
|
+
.then(() => {
|
|
302
|
+
resolve(record);
|
|
303
|
+
})
|
|
304
|
+
.catch(e => {
|
|
305
|
+
reject(e);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
range() {
|
|
310
|
+
return new recordGetRange(this.layout);
|
|
311
|
+
}
|
|
312
|
+
find() {
|
|
313
|
+
return new find(this.layout);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
256
316
|
class record extends EventEmitter {
|
|
257
317
|
constructor(layout, recordId, modId = recordId, fieldData = {}, portalData = null) {
|
|
258
318
|
super();
|
|
@@ -277,17 +337,46 @@ class record extends EventEmitter {
|
|
|
277
337
|
}
|
|
278
338
|
processPortalData(portalData) {
|
|
279
339
|
for (let item of Object.keys(portalData)) {
|
|
280
|
-
|
|
340
|
+
let _portal = new portal(this, item);
|
|
341
|
+
_portal.records = portalData[item].map(item => {
|
|
281
342
|
let fieldData = item;
|
|
282
343
|
delete fieldData.recordId;
|
|
283
344
|
delete fieldData.modId;
|
|
284
|
-
return new portalItem(this, item.recordId, item.modId, fieldData);
|
|
285
|
-
})
|
|
345
|
+
return new portalItem(this, _portal, item.recordId, item.modId, fieldData);
|
|
346
|
+
});
|
|
347
|
+
this.portals.push();
|
|
286
348
|
}
|
|
287
349
|
}
|
|
288
350
|
processFieldData(fieldData) {
|
|
289
351
|
return Object.keys(fieldData).map(item => {
|
|
290
|
-
|
|
352
|
+
let _field = new field(this, item, fieldData[item]);
|
|
353
|
+
if (!!fieldData[item]) {
|
|
354
|
+
if (_field.metadata.result === "timeStamp") {
|
|
355
|
+
// @ts-ignore
|
|
356
|
+
let date = moment.default(fieldData[item], this.layout.database.host.metadata.productInfo.timeStampFormat)
|
|
357
|
+
.utcOffset(this.layout.database.host.timezoneOffset, true)
|
|
358
|
+
.local();
|
|
359
|
+
_field.set(date.toDate());
|
|
360
|
+
_field.edited = false;
|
|
361
|
+
}
|
|
362
|
+
else if (_field.metadata.result === "time") {
|
|
363
|
+
// @ts-ignore
|
|
364
|
+
let date = moment.default(fieldData[item], this.layout.database.host.metadata.productInfo.timeFormat)
|
|
365
|
+
.utcOffset(this.layout.database.host.timezoneOffset, true)
|
|
366
|
+
.local();
|
|
367
|
+
_field.set(date.toDate());
|
|
368
|
+
_field.edited = false;
|
|
369
|
+
}
|
|
370
|
+
else if (_field.metadata.result === "date") {
|
|
371
|
+
// @ts-ignore
|
|
372
|
+
let date = moment.default(fieldData[item], this.layout.database.host.metadata.productInfo.dateFormat)
|
|
373
|
+
.utcOffset(this.layout.database.host.timezoneOffset, true)
|
|
374
|
+
.local();
|
|
375
|
+
_field.set(date.toDate());
|
|
376
|
+
_field.edited = false;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return _field;
|
|
291
380
|
});
|
|
292
381
|
}
|
|
293
382
|
get() {
|
|
@@ -340,7 +429,6 @@ class record extends EventEmitter {
|
|
|
340
429
|
reject(new FMError(res.response.scriptError, res.status, res));
|
|
341
430
|
}
|
|
342
431
|
else if (res.messages[0].code === "0") {
|
|
343
|
-
console.log(res);
|
|
344
432
|
this.recordId = parseInt(res.response.recordId);
|
|
345
433
|
this.modId = parseInt(res.response.modId);
|
|
346
434
|
resolve(this);
|
|
@@ -354,19 +442,18 @@ class record extends EventEmitter {
|
|
|
354
442
|
});
|
|
355
443
|
return;
|
|
356
444
|
}
|
|
357
|
-
for (let item of Object.keys(
|
|
358
|
-
|
|
445
|
+
for (let item of Object.keys(data))
|
|
446
|
+
extraBody[item] = data[item];
|
|
359
447
|
this.layout.database.apiRequest(this.endpoint, {
|
|
360
448
|
port: 443,
|
|
361
449
|
method: "PATCH",
|
|
362
|
-
body: JSON.stringify(
|
|
450
|
+
body: JSON.stringify(extraBody)
|
|
363
451
|
})
|
|
364
452
|
.then(res => {
|
|
365
453
|
if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
|
|
366
454
|
reject(new FMError(res.response.scriptError, res.status, res));
|
|
367
455
|
}
|
|
368
456
|
else if (res.messages[0].code === "0") {
|
|
369
|
-
console.log(res);
|
|
370
457
|
this.modId = res.response.modId;
|
|
371
458
|
this.emit("saved");
|
|
372
459
|
resolve(this);
|
|
@@ -437,7 +524,24 @@ class record extends EventEmitter {
|
|
|
437
524
|
toObject(filter = (a) => a.edited, portalFilter = (a) => a.records.find(record => record.edited), portalRowFilter = (a) => a.edited, portalFieldFilter = (a) => a.edited) {
|
|
438
525
|
let fields_processed = {};
|
|
439
526
|
for (let field of this.fields.filter(field => filter(field))) {
|
|
440
|
-
|
|
527
|
+
let value = field.value;
|
|
528
|
+
if (value instanceof Date) {
|
|
529
|
+
// @ts-ignore
|
|
530
|
+
let _value = moment.default(value)
|
|
531
|
+
.utcOffset(this.layout.database.host.timezoneOffset);
|
|
532
|
+
// @ts-ignore
|
|
533
|
+
switch (field.metadata.result) {
|
|
534
|
+
case "time":
|
|
535
|
+
value = _value.format(this.layout.database.host.metadata.productInfo.timeFormat.replace("dd", "DD"));
|
|
536
|
+
break;
|
|
537
|
+
case "date":
|
|
538
|
+
value = _value.format(this.layout.database.host.metadata.productInfo.dateFormat.replace("dd", "DD"));
|
|
539
|
+
break;
|
|
540
|
+
default:
|
|
541
|
+
value = _value.format(this.layout.database.host.metadata.productInfo.timeStampFormat.replace("dd", "DD"));
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
fields_processed[field.id] = value;
|
|
441
545
|
}
|
|
442
546
|
let obj = {
|
|
443
547
|
"recordId": this.recordId,
|
|
@@ -461,27 +565,83 @@ class field {
|
|
|
461
565
|
constructor(record, id, contents) {
|
|
462
566
|
this.record = record;
|
|
463
567
|
this.id = id;
|
|
464
|
-
this.
|
|
568
|
+
this._value = contents;
|
|
465
569
|
this.edited = false;
|
|
466
570
|
}
|
|
467
571
|
set(content) {
|
|
468
|
-
if (this.
|
|
572
|
+
if (this.metadata.result === "container")
|
|
469
573
|
throw "Cannot set container value using set(). Use upload() instead.";
|
|
470
|
-
this.
|
|
574
|
+
if ((this.metadata.result === "timeStamp" ||
|
|
575
|
+
this.metadata.result === "date" ||
|
|
576
|
+
this.metadata.result === "time")
|
|
577
|
+
&& !(content instanceof Date) && !!content) {
|
|
578
|
+
throw "Value was not an instance of Date: " + content;
|
|
579
|
+
}
|
|
580
|
+
this._value = content;
|
|
471
581
|
this.edited = true;
|
|
472
582
|
}
|
|
473
|
-
get
|
|
474
|
-
if (!this.record.layout.metadata)
|
|
475
|
-
|
|
583
|
+
get metadata() {
|
|
584
|
+
if (!this.record.layout.metadata) {
|
|
585
|
+
// Default to a regular text field
|
|
586
|
+
return {
|
|
587
|
+
name: this.id.toString(),
|
|
588
|
+
type: 'normal',
|
|
589
|
+
displayType: 'editText',
|
|
590
|
+
result: 'text',
|
|
591
|
+
global: false,
|
|
592
|
+
autoEnter: true,
|
|
593
|
+
fourDigitYear: false,
|
|
594
|
+
maxRepeat: 1,
|
|
595
|
+
maxCharacters: 0,
|
|
596
|
+
notEmpty: false,
|
|
597
|
+
numeric: false,
|
|
598
|
+
timeOfDay: false,
|
|
599
|
+
repetitionStart: 1,
|
|
600
|
+
repetitionEnd: 1
|
|
601
|
+
};
|
|
602
|
+
}
|
|
476
603
|
if (this.record instanceof portalItem) {
|
|
477
|
-
return this.record.layout.metadata.portalMetaData.find(i => i.name === this.id)
|
|
604
|
+
return this.record.layout.metadata.portalMetaData[this.record.portal.name || "portal not attached"].find(i => i.name === this.id) || {
|
|
605
|
+
name: this.id.toString(),
|
|
606
|
+
type: 'normal',
|
|
607
|
+
displayType: 'editText',
|
|
608
|
+
result: 'text',
|
|
609
|
+
global: false,
|
|
610
|
+
autoEnter: true,
|
|
611
|
+
fourDigitYear: false,
|
|
612
|
+
maxRepeat: 1,
|
|
613
|
+
maxCharacters: 0,
|
|
614
|
+
notEmpty: false,
|
|
615
|
+
numeric: false,
|
|
616
|
+
timeOfDay: false,
|
|
617
|
+
repetitionStart: 1,
|
|
618
|
+
repetitionEnd: 1
|
|
619
|
+
};
|
|
478
620
|
}
|
|
479
621
|
else {
|
|
480
|
-
return this.record.layout.metadata.fieldMetaData.find(i => i.name === this.id)
|
|
622
|
+
return this.record.layout.metadata.fieldMetaData.find(i => i.name === this.id) || {
|
|
623
|
+
name: this.id.toString(),
|
|
624
|
+
type: 'normal',
|
|
625
|
+
displayType: 'editText',
|
|
626
|
+
result: 'text',
|
|
627
|
+
global: false,
|
|
628
|
+
autoEnter: true,
|
|
629
|
+
fourDigitYear: false,
|
|
630
|
+
maxRepeat: 1,
|
|
631
|
+
maxCharacters: 0,
|
|
632
|
+
notEmpty: false,
|
|
633
|
+
numeric: false,
|
|
634
|
+
timeOfDay: false,
|
|
635
|
+
repetitionStart: 1,
|
|
636
|
+
repetitionEnd: 1
|
|
637
|
+
};
|
|
481
638
|
}
|
|
482
639
|
}
|
|
640
|
+
get value() {
|
|
641
|
+
return this._value;
|
|
642
|
+
}
|
|
483
643
|
upload(buffer, filename, mime) {
|
|
484
|
-
if (this.
|
|
644
|
+
if (this.metadata.result !== "container")
|
|
485
645
|
throw "Cannot upload a file to the field; " + this.id + " (not a container field)";
|
|
486
646
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
487
647
|
let form = new FormData();
|
|
@@ -514,24 +674,19 @@ class field {
|
|
|
514
674
|
}
|
|
515
675
|
}
|
|
516
676
|
class portal {
|
|
517
|
-
constructor(record, name
|
|
677
|
+
constructor(record, name) {
|
|
518
678
|
this.record = record;
|
|
519
679
|
this.name = name;
|
|
520
|
-
this.records = records;
|
|
521
|
-
for (let item of this.records)
|
|
522
|
-
item.attachPortal(this);
|
|
523
680
|
}
|
|
524
681
|
}
|
|
525
682
|
class portalItem extends record {
|
|
526
|
-
constructor(record, recordId, modId = recordId, fieldData = {}) {
|
|
683
|
+
constructor(record, portal, recordId, modId = recordId, fieldData = {}) {
|
|
527
684
|
super(record.layout, recordId, modId, fieldData);
|
|
685
|
+
this.portal = portal;
|
|
528
686
|
record.on("saved", () => {
|
|
529
687
|
this.emit("saved");
|
|
530
688
|
});
|
|
531
689
|
}
|
|
532
|
-
attachPortal(portal) {
|
|
533
|
-
this.portal = portal;
|
|
534
|
-
}
|
|
535
690
|
commit(extraBody = { fieldData: undefined }) {
|
|
536
691
|
return this.portal.record.commit(extraBody);
|
|
537
692
|
}
|
|
@@ -611,9 +766,12 @@ class recordGetRange extends recordGetOperation {
|
|
|
611
766
|
run() {
|
|
612
767
|
return new Promise((resolve, reject) => {
|
|
613
768
|
// console.log(this.#toObject())
|
|
614
|
-
this.layout.
|
|
615
|
-
|
|
616
|
-
|
|
769
|
+
this.layout.getLayoutMeta().then(() => {
|
|
770
|
+
return this.layout.database.apiRequest(`${this.layout.endpoint}/records${this.generateQueryParams()}`, {
|
|
771
|
+
method: "GET"
|
|
772
|
+
});
|
|
773
|
+
})
|
|
774
|
+
.then((res) => __awaiter(this, void 0, void 0, function* () {
|
|
617
775
|
// // console.log(res)
|
|
618
776
|
if (res.messages[0].code === "0") {
|
|
619
777
|
// console.log("RESOLVING")
|
|
@@ -674,11 +832,15 @@ class find extends recordGetOperation {
|
|
|
674
832
|
run() {
|
|
675
833
|
return new Promise((resolve, reject) => {
|
|
676
834
|
// console.log(this.#toObject())
|
|
677
|
-
this.layout.
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
835
|
+
this.layout.getLayoutMeta()
|
|
836
|
+
.then(() => {
|
|
837
|
+
return this.layout.database.apiRequest(`${this.layout.endpoint}/_find`, {
|
|
838
|
+
port: 443,
|
|
839
|
+
method: "POST",
|
|
840
|
+
body: JSON.stringify(this.toObject())
|
|
841
|
+
});
|
|
842
|
+
})
|
|
843
|
+
.then((res) => __awaiter(this, void 0, void 0, function* () {
|
|
682
844
|
// // console.log(res)
|
|
683
845
|
if (res.messages[0].code === "0") {
|
|
684
846
|
// console.log("RESOLVING")
|
|
@@ -711,7 +873,23 @@ export class FMError extends Error {
|
|
|
711
873
|
Error.captureStackTrace(this, FMError);
|
|
712
874
|
}
|
|
713
875
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
876
|
+
function generateAuthorizationHeaders(credentials) {
|
|
877
|
+
switch (credentials.method) {
|
|
878
|
+
case "filemaker":
|
|
879
|
+
return {
|
|
880
|
+
"Content-Type": "application/json",
|
|
881
|
+
"Authorization": "Basic " + Buffer.from(credentials.username + ":" + credentials.password).toString("base64")
|
|
882
|
+
};
|
|
883
|
+
case "claris":
|
|
884
|
+
return {
|
|
885
|
+
"Content-Type": "application/json",
|
|
886
|
+
"Authorization": credentials.claris.fmid,
|
|
887
|
+
};
|
|
888
|
+
case "oauth":
|
|
889
|
+
return {
|
|
890
|
+
"Content-Type": "application/json",
|
|
891
|
+
"X-FM-Data-OAuth-RequestId": credentials.oauth.requestId,
|
|
892
|
+
"X-FM-Data-OAuth-Identifier": credentials.oauth.requestIdentifier
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
}
|