@jd-data-limited/easy-fm 1.1.5-alpha1 → 1.2.0-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 +337 -108
- package/index.ts +449 -155
- 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.layout, -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();
|
|
@@ -287,7 +347,34 @@ class record extends EventEmitter {
|
|
|
287
347
|
}
|
|
288
348
|
processFieldData(fieldData) {
|
|
289
349
|
return Object.keys(fieldData).map(item => {
|
|
290
|
-
|
|
350
|
+
let _field = new field(this, item, fieldData[item]);
|
|
351
|
+
if (!!fieldData[item]) {
|
|
352
|
+
if (_field.metadata.result === "timeStamp") {
|
|
353
|
+
// @ts-ignore
|
|
354
|
+
let date = moment.default(fieldData[item], this.layout.database.host.metadata.productInfo.timeStampFormat)
|
|
355
|
+
.utcOffset(this.layout.database.host.timezoneOffset, true)
|
|
356
|
+
.local();
|
|
357
|
+
_field.set(date.toDate());
|
|
358
|
+
_field.edited = false;
|
|
359
|
+
}
|
|
360
|
+
else if (_field.metadata.result === "time") {
|
|
361
|
+
// @ts-ignore
|
|
362
|
+
let date = moment.default(fieldData[item], this.layout.database.host.metadata.productInfo.timeFormat)
|
|
363
|
+
.utcOffset(this.layout.database.host.timezoneOffset, true)
|
|
364
|
+
.local();
|
|
365
|
+
_field.set(date.toDate());
|
|
366
|
+
_field.edited = false;
|
|
367
|
+
}
|
|
368
|
+
else if (_field.metadata.result === "date") {
|
|
369
|
+
// @ts-ignore
|
|
370
|
+
let date = moment.default(fieldData[item], this.layout.database.host.metadata.productInfo.dateFormat)
|
|
371
|
+
.utcOffset(this.layout.database.host.timezoneOffset, true)
|
|
372
|
+
.local();
|
|
373
|
+
_field.set(date.toDate());
|
|
374
|
+
_field.edited = false;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return _field;
|
|
291
378
|
});
|
|
292
379
|
}
|
|
293
380
|
get() {
|
|
@@ -340,7 +427,6 @@ class record extends EventEmitter {
|
|
|
340
427
|
reject(new FMError(res.response.scriptError, res.status, res));
|
|
341
428
|
}
|
|
342
429
|
else if (res.messages[0].code === "0") {
|
|
343
|
-
console.log(res);
|
|
344
430
|
this.recordId = parseInt(res.response.recordId);
|
|
345
431
|
this.modId = parseInt(res.response.modId);
|
|
346
432
|
resolve(this);
|
|
@@ -354,19 +440,18 @@ class record extends EventEmitter {
|
|
|
354
440
|
});
|
|
355
441
|
return;
|
|
356
442
|
}
|
|
357
|
-
for (let item of Object.keys(
|
|
358
|
-
|
|
443
|
+
for (let item of Object.keys(data))
|
|
444
|
+
extraBody[item] = data[item];
|
|
359
445
|
this.layout.database.apiRequest(this.endpoint, {
|
|
360
446
|
port: 443,
|
|
361
447
|
method: "PATCH",
|
|
362
|
-
body: JSON.stringify(
|
|
448
|
+
body: JSON.stringify(extraBody)
|
|
363
449
|
})
|
|
364
450
|
.then(res => {
|
|
365
451
|
if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
|
|
366
452
|
reject(new FMError(res.response.scriptError, res.status, res));
|
|
367
453
|
}
|
|
368
454
|
else if (res.messages[0].code === "0") {
|
|
369
|
-
console.log(res);
|
|
370
455
|
this.modId = res.response.modId;
|
|
371
456
|
this.emit("saved");
|
|
372
457
|
resolve(this);
|
|
@@ -386,10 +471,75 @@ class record extends EventEmitter {
|
|
|
386
471
|
getPortal(portal) {
|
|
387
472
|
return this.portals.find(p => p.name === portal);
|
|
388
473
|
}
|
|
474
|
+
delete() {
|
|
475
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
476
|
+
this.layout.database.apiRequest(this.endpoint, {
|
|
477
|
+
port: 443,
|
|
478
|
+
method: "DELETE"
|
|
479
|
+
})
|
|
480
|
+
.then(res => {
|
|
481
|
+
if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
|
|
482
|
+
reject(new FMError(res.response.scriptError, res.status, res));
|
|
483
|
+
}
|
|
484
|
+
else if (res.messages[0].code === "0") {
|
|
485
|
+
this.emit("deleted");
|
|
486
|
+
resolve();
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
reject(new FMError(res.messages[0].code, res.status, res));
|
|
490
|
+
}
|
|
491
|
+
})
|
|
492
|
+
.catch(e => {
|
|
493
|
+
reject(e);
|
|
494
|
+
});
|
|
495
|
+
}));
|
|
496
|
+
}
|
|
497
|
+
duplicate() {
|
|
498
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
499
|
+
this.layout.database.apiRequest(this.endpoint, {
|
|
500
|
+
port: 443,
|
|
501
|
+
method: "POST"
|
|
502
|
+
})
|
|
503
|
+
.then(res => {
|
|
504
|
+
if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
|
|
505
|
+
reject(new FMError(res.response.scriptError, res.status, res));
|
|
506
|
+
}
|
|
507
|
+
else if (res.messages[0].code === "0") {
|
|
508
|
+
let data = this.toObject((a) => true, (a) => true, (a) => false, (a) => false);
|
|
509
|
+
let _res = new record(this.layout, res.response.recordId, res.response.modId, data.fieldData, data.portalData);
|
|
510
|
+
this.emit("duplicated");
|
|
511
|
+
resolve(_res);
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
reject(new FMError(res.messages[0].code, res.status, res));
|
|
515
|
+
}
|
|
516
|
+
})
|
|
517
|
+
.catch(e => {
|
|
518
|
+
reject(e);
|
|
519
|
+
});
|
|
520
|
+
}));
|
|
521
|
+
}
|
|
389
522
|
toObject(filter = (a) => a.edited, portalFilter = (a) => a.records.find(record => record.edited), portalRowFilter = (a) => a.edited, portalFieldFilter = (a) => a.edited) {
|
|
390
523
|
let fields_processed = {};
|
|
391
524
|
for (let field of this.fields.filter(field => filter(field))) {
|
|
392
|
-
|
|
525
|
+
let value = field.value;
|
|
526
|
+
if (value instanceof Date) {
|
|
527
|
+
// @ts-ignore
|
|
528
|
+
let _value = moment.default(value)
|
|
529
|
+
.utcOffset(this.layout.database.host.timezoneOffset);
|
|
530
|
+
// @ts-ignore
|
|
531
|
+
switch (field.metadata.result) {
|
|
532
|
+
case "time":
|
|
533
|
+
value = _value.format(this.layout.database.host.metadata.productInfo.timeFormat.replace("dd", "DD"));
|
|
534
|
+
break;
|
|
535
|
+
case "date":
|
|
536
|
+
value = _value.format(this.layout.database.host.metadata.productInfo.dateFormat.replace("dd", "DD"));
|
|
537
|
+
break;
|
|
538
|
+
default:
|
|
539
|
+
value = _value.format(this.layout.database.host.metadata.productInfo.timeStampFormat.replace("dd", "DD"));
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
fields_processed[field.id] = value;
|
|
393
543
|
}
|
|
394
544
|
let obj = {
|
|
395
545
|
"recordId": this.recordId,
|
|
@@ -413,27 +563,83 @@ class field {
|
|
|
413
563
|
constructor(record, id, contents) {
|
|
414
564
|
this.record = record;
|
|
415
565
|
this.id = id;
|
|
416
|
-
this.
|
|
566
|
+
this._value = contents;
|
|
417
567
|
this.edited = false;
|
|
418
568
|
}
|
|
419
569
|
set(content) {
|
|
420
|
-
if (this.
|
|
570
|
+
if (this.metadata.result === "container")
|
|
421
571
|
throw "Cannot set container value using set(). Use upload() instead.";
|
|
422
|
-
this.
|
|
572
|
+
if ((this.metadata.result === "timeStamp" ||
|
|
573
|
+
this.metadata.result === "date" ||
|
|
574
|
+
this.metadata.result === "time")
|
|
575
|
+
&& !(content instanceof Date) && !!content) {
|
|
576
|
+
throw "Value was not an instance of Date: " + content;
|
|
577
|
+
}
|
|
578
|
+
this._value = content;
|
|
423
579
|
this.edited = true;
|
|
424
580
|
}
|
|
425
|
-
get
|
|
426
|
-
if (!this.record.layout.metadata)
|
|
427
|
-
|
|
581
|
+
get metadata() {
|
|
582
|
+
if (!this.record.layout.metadata) {
|
|
583
|
+
// Default to a regular text field
|
|
584
|
+
return {
|
|
585
|
+
name: this.id.toString(),
|
|
586
|
+
type: 'normal',
|
|
587
|
+
displayType: 'editText',
|
|
588
|
+
result: 'text',
|
|
589
|
+
global: false,
|
|
590
|
+
autoEnter: true,
|
|
591
|
+
fourDigitYear: false,
|
|
592
|
+
maxRepeat: 1,
|
|
593
|
+
maxCharacters: 0,
|
|
594
|
+
notEmpty: false,
|
|
595
|
+
numeric: false,
|
|
596
|
+
timeOfDay: false,
|
|
597
|
+
repetitionStart: 1,
|
|
598
|
+
repetitionEnd: 1
|
|
599
|
+
};
|
|
600
|
+
}
|
|
428
601
|
if (this.record instanceof portalItem) {
|
|
429
|
-
return this.record.layout.metadata.portalMetaData.find(i => i.name === this.id)
|
|
602
|
+
return this.record.layout.metadata.portalMetaData.find(i => i.name === this.id) || {
|
|
603
|
+
name: this.id.toString(),
|
|
604
|
+
type: 'normal',
|
|
605
|
+
displayType: 'editText',
|
|
606
|
+
result: 'text',
|
|
607
|
+
global: false,
|
|
608
|
+
autoEnter: true,
|
|
609
|
+
fourDigitYear: false,
|
|
610
|
+
maxRepeat: 1,
|
|
611
|
+
maxCharacters: 0,
|
|
612
|
+
notEmpty: false,
|
|
613
|
+
numeric: false,
|
|
614
|
+
timeOfDay: false,
|
|
615
|
+
repetitionStart: 1,
|
|
616
|
+
repetitionEnd: 1
|
|
617
|
+
};
|
|
430
618
|
}
|
|
431
619
|
else {
|
|
432
|
-
return this.record.layout.metadata.fieldMetaData.find(i => i.name === this.id)
|
|
620
|
+
return this.record.layout.metadata.fieldMetaData.find(i => i.name === this.id) || {
|
|
621
|
+
name: this.id.toString(),
|
|
622
|
+
type: 'normal',
|
|
623
|
+
displayType: 'editText',
|
|
624
|
+
result: 'text',
|
|
625
|
+
global: false,
|
|
626
|
+
autoEnter: true,
|
|
627
|
+
fourDigitYear: false,
|
|
628
|
+
maxRepeat: 1,
|
|
629
|
+
maxCharacters: 0,
|
|
630
|
+
notEmpty: false,
|
|
631
|
+
numeric: false,
|
|
632
|
+
timeOfDay: false,
|
|
633
|
+
repetitionStart: 1,
|
|
634
|
+
repetitionEnd: 1
|
|
635
|
+
};
|
|
433
636
|
}
|
|
434
637
|
}
|
|
638
|
+
get value() {
|
|
639
|
+
return this._value;
|
|
640
|
+
}
|
|
435
641
|
upload(buffer, filename, mime) {
|
|
436
|
-
if (this.
|
|
642
|
+
if (this.metadata.result !== "container")
|
|
437
643
|
throw "Cannot upload a file to the field; " + this.id + " (not a container field)";
|
|
438
644
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
439
645
|
let form = new FormData();
|
|
@@ -563,9 +769,12 @@ class recordGetRange extends recordGetOperation {
|
|
|
563
769
|
run() {
|
|
564
770
|
return new Promise((resolve, reject) => {
|
|
565
771
|
// console.log(this.#toObject())
|
|
566
|
-
this.layout.
|
|
567
|
-
|
|
568
|
-
|
|
772
|
+
this.layout.getLayoutMeta().then(() => {
|
|
773
|
+
return this.layout.database.apiRequest(`${this.layout.endpoint}/records${this.generateQueryParams()}`, {
|
|
774
|
+
method: "GET"
|
|
775
|
+
});
|
|
776
|
+
})
|
|
777
|
+
.then((res) => __awaiter(this, void 0, void 0, function* () {
|
|
569
778
|
// // console.log(res)
|
|
570
779
|
if (res.messages[0].code === "0") {
|
|
571
780
|
// console.log("RESOLVING")
|
|
@@ -626,11 +835,15 @@ class find extends recordGetOperation {
|
|
|
626
835
|
run() {
|
|
627
836
|
return new Promise((resolve, reject) => {
|
|
628
837
|
// console.log(this.#toObject())
|
|
629
|
-
this.layout.
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
838
|
+
this.layout.getLayoutMeta()
|
|
839
|
+
.then(() => {
|
|
840
|
+
return this.layout.database.apiRequest(`${this.layout.endpoint}/_find`, {
|
|
841
|
+
port: 443,
|
|
842
|
+
method: "POST",
|
|
843
|
+
body: JSON.stringify(this.toObject())
|
|
844
|
+
});
|
|
845
|
+
})
|
|
846
|
+
.then((res) => __awaiter(this, void 0, void 0, function* () {
|
|
634
847
|
// // console.log(res)
|
|
635
848
|
if (res.messages[0].code === "0") {
|
|
636
849
|
// console.log("RESOLVING")
|
|
@@ -663,7 +876,23 @@ export class FMError extends Error {
|
|
|
663
876
|
Error.captureStackTrace(this, FMError);
|
|
664
877
|
}
|
|
665
878
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
879
|
+
function generateAuthorizationHeaders(credentials) {
|
|
880
|
+
switch (credentials.method) {
|
|
881
|
+
case "filemaker":
|
|
882
|
+
return {
|
|
883
|
+
"Content-Type": "application/json",
|
|
884
|
+
"Authorization": "Basic " + Buffer.from(credentials.username + ":" + credentials.password).toString("base64")
|
|
885
|
+
};
|
|
886
|
+
case "claris":
|
|
887
|
+
return {
|
|
888
|
+
"Content-Type": "application/json",
|
|
889
|
+
"Authorization": credentials.claris.fmid,
|
|
890
|
+
};
|
|
891
|
+
case "oauth":
|
|
892
|
+
return {
|
|
893
|
+
"Content-Type": "application/json",
|
|
894
|
+
"X-FM-Data-OAuth-RequestId": credentials.oauth.requestId,
|
|
895
|
+
"X-FM-Data-OAuth-Identifier": credentials.oauth.requestIdentifier
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
}
|