@jd-data-limited/easy-fm 0.0.11 → 1.0.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.
Files changed (3) hide show
  1. package/index.js +156 -90
  2. package/index.ts +217 -96
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -20,79 +20,17 @@ import path from "path";
20
20
  // @ts-ignore
21
21
  import { fileURLToPath } from "url";
22
22
  import * as https from "https";
23
- // import * as btoa from "btoa";
24
23
  // @ts-ignore
25
24
  const errs = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'fmErrors.json')).toString());
26
- export default class FileMakerConnection {
27
- constructor() { }
28
- get endpoint() {
29
- return `https://${this.hostname}/fmi/data/v2/databases/${encodeURI(this.database)}`;
25
+ class database {
26
+ constructor(props, host = null) {
27
+ this.props = props;
28
+ this.name = this.props.database;
29
+ if (host)
30
+ this.host = host;
30
31
  }
31
- login(hostname, database, username, password, rejectUnauthorized = true) {
32
- return __awaiter(this, void 0, void 0, function* () {
33
- if (this.token)
34
- throw new Error("Already logged in. Run logout() first");
35
- this.username = username;
36
- this.password = password;
37
- this.hostname = hostname;
38
- this.database = database;
39
- this.rejectUnauthroized = rejectUnauthorized;
40
- return yield this.createSession();
41
- });
42
- }
43
- logout() {
44
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
45
- if (!this.token)
46
- reject(new Error("Not logged in"));
47
- let _fetch = yield fetch(`${this.endpoint}/sessions/${this.token}`, {
48
- method: "DELETE",
49
- headers: {
50
- "content-type": "application/json"
51
- }
52
- });
53
- let data = yield _fetch.json();
54
- // console.log(data)
55
- this.token = null;
56
- this.database = null;
57
- this.hostname = null;
58
- resolve();
59
- }));
60
- }
61
- importSession(hostname, database, token, rejectUnauthorized = true) {
62
- this.token = token;
63
- this.database = database;
64
- this.hostname = hostname;
65
- this.rejectUnauthroized = rejectUnauthorized;
66
- }
67
- createSession() {
68
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
69
- fetch(`${this.endpoint}/sessions`, {
70
- hostname: this.hostname,
71
- port: 443,
72
- method: "POST",
73
- headers: {
74
- "Content-Type": "application/json",
75
- "Authorization": "Basic " + Buffer.from(this.username + ":" + this.password).toString("base64")
76
- }
77
- }).then(res => {
78
- console.log(res);
79
- return res.json();
80
- })
81
- .then(res => {
82
- let _res = res;
83
- if (_res.messages[0].code === "0") {
84
- this.token = _res.response.token;
85
- console.log(_res);
86
- resolve(this.token);
87
- }
88
- else {
89
- reject(new FMError(_res.messages[0].code, _res.status, res));
90
- }
91
- })
92
- .catch(e => {
93
- reject(e);
94
- });
95
- }));
32
+ get token() {
33
+ return this.host.token;
96
34
  }
97
35
  getLayout(name) {
98
36
  return new layout(this, name);
@@ -102,8 +40,8 @@ export default class FileMakerConnection {
102
40
  if (!options.headers)
103
41
  options.headers = {};
104
42
  options.headers["content-type"] = options.headers["content-type"] ? options.headers["content-type"] : "application/json";
105
- options.headers["authorization"] = "Bearer " + this.token;
106
- options.rejectUnauthorized = this.rejectUnauthroized;
43
+ options.headers["authorization"] = "Bearer " + this.host.token;
44
+ options.rejectUnauthorized = this.host.rejectUnauthroized;
107
45
  let _fetch = yield fetch(url, options);
108
46
  let data = yield _fetch.json();
109
47
  return data;
@@ -132,14 +70,141 @@ export default class FileMakerConnection {
132
70
  script(name, parameter) {
133
71
  return { name, parameter };
134
72
  }
73
+ get endpoint() {
74
+ return `https://${this.hostname || this.host.hostname}/fmi/data/v2/databases/${encodeURI(this.name)}`;
75
+ }
76
+ get externalLoginInfo() {
77
+ // Returns an object that can be used when using this database object as an external source
78
+ let out = {
79
+ database: this.name,
80
+ username: undefined,
81
+ password: undefined,
82
+ oauthRequestId: undefined,
83
+ oauthIdentifier: undefined
84
+ };
85
+ switch (this.props.method) {
86
+ case "filemaker":
87
+ out.username = this.props.username;
88
+ out.password = this.props.password;
89
+ case "token":
90
+ throw "Token logins cannot be used for connecting to external sources. Please either use no login method, or open a second connection.";
91
+ case "oauth":
92
+ out.oauthRequestId = this.props.oauth.requestId;
93
+ out.oauthIdentifier = this.props.oauth.requestIdentifier;
94
+ case "claris":
95
+ throw "Claris logins cannot be used for connecting to external sources. Please either use no login method, or open a second connection.";
96
+ }
97
+ return out;
98
+ }
99
+ }
100
+ export default class FileMakerConnection extends database {
101
+ constructor(conn, externalDataSources = [], rejectUnauthorized = true) {
102
+ super(conn.database);
103
+ this.host = this;
104
+ this.hostname = conn.hostname;
105
+ this.externalSources = externalDataSources.map(i => { let e = new database(i, this); e.external = true; return e; });
106
+ this.rejectUnauthroized = rejectUnauthorized;
107
+ }
108
+ logout() {
109
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
110
+ if (!this.token)
111
+ reject(new Error("Not logged in"));
112
+ let _fetch = yield fetch(`${this.endpoint}/sessions/${this.token}`, {
113
+ method: "DELETE",
114
+ headers: {
115
+ "content-type": "application/json"
116
+ }
117
+ });
118
+ let data = yield _fetch.json();
119
+ // console.log(data)
120
+ this._token = null;
121
+ this.name = null;
122
+ this.hostname = null;
123
+ resolve();
124
+ }));
125
+ }
126
+ login() {
127
+ return new Promise((resolve, reject) => {
128
+ if (this.token)
129
+ throw new Error("Already logged in. Run logout() first");
130
+ if (this.props.method === "filemaker") {
131
+ this.username = this.props.username;
132
+ this.name = this.props.database;
133
+ fetch(`${this.endpoint}/sessions`, {
134
+ hostname: this.hostname,
135
+ port: 443,
136
+ method: "POST",
137
+ headers: {
138
+ "Content-Type": "application/json",
139
+ "Authorization": "Basic " + Buffer.from(this.username + ":" + this.props.password).toString("base64")
140
+ }
141
+ }).then((res) => __awaiter(this, void 0, void 0, function* () {
142
+ if (res.status === 200) {
143
+ this._token = res.headers.get('x-fm-data-access-token');
144
+ resolve(this._token);
145
+ }
146
+ else {
147
+ let _res = (yield res.json());
148
+ reject(new FMError(_res.messages[0].code, _res.status, res));
149
+ }
150
+ }))
151
+ .catch(e => {
152
+ reject(e);
153
+ });
154
+ }
155
+ else if (this.props.method === "token") {
156
+ this._token = this.props.token;
157
+ this.name = this.props.database;
158
+ resolve(this.token);
159
+ }
160
+ else if (this.props.method === "oauth") {
161
+ this.name = this.props.database;
162
+ fetch(`${this.endpoint}/sessions`, {
163
+ method: "POST",
164
+ headers: {
165
+ "Content-Type": "application/json",
166
+ "X-FM-Data-OAuth-RequestId": this.props.oauth.requestId,
167
+ "X-FM-Data-OAuth-Identifier": this.props.oauth.requestIdentifier
168
+ },
169
+ body: "{}"
170
+ })
171
+ .then(res => res.json())
172
+ .then(res => {
173
+ let _res = res;
174
+ this._token = _res.headers["x-fm-data-access-token"];
175
+ resolve(this.token);
176
+ });
177
+ }
178
+ else if (this.props.method === "claris") {
179
+ this.name = this.props.database;
180
+ fetch(`${this.endpoint}/sessions`, {
181
+ method: "POST",
182
+ headers: {
183
+ "Content-Type": "application/json",
184
+ "Authorization": this.props.claris.fmid,
185
+ },
186
+ body: "{}"
187
+ })
188
+ .then(res => res.json())
189
+ .then(res => {
190
+ let _res = res;
191
+ this._token = _res.headers["x-fm-data-access-token"];
192
+ resolve(this.token);
193
+ });
194
+ }
195
+ });
196
+ }
197
+ get token() {
198
+ return this._token;
199
+ }
135
200
  }
136
201
  class layout {
137
- constructor(conn, name) {
138
- this.conn = conn;
202
+ constructor(database, name) {
203
+ this.database = database;
139
204
  this.name = name;
140
205
  }
141
206
  get endpoint() {
142
- return `${this.conn.endpoint}/layouts/${this.name}`;
207
+ return `${this.database.endpoint}/layouts/${this.name}`;
143
208
  }
144
209
  getScript(script) {
145
210
  return new script(this, script);
@@ -147,9 +212,9 @@ class layout {
147
212
  createRecord() {
148
213
  return new Promise((resolve, reject) => {
149
214
  // Get the layout's metadata
150
- this.conn.apiRequest(`${this.endpoint}`).then(res => {
215
+ this.getLayoutMeta().then(layout => {
151
216
  let fields = {};
152
- for (let _field of res.response.fieldMetaData) {
217
+ for (let _field of this.metadata.fieldMetaData) {
153
218
  fields[_field.name] = "";
154
219
  }
155
220
  resolve(new record(this, -1, 0, fields));
@@ -167,7 +232,7 @@ class layout {
167
232
  let url = `${this.endpoint}/script/${encodeURI(script.name)}`;
168
233
  if (script.parameter)
169
234
  url += "?" + encodeURI(script.parameter);
170
- this.conn.apiRequest(url, {
235
+ this.database.apiRequest(url, {
171
236
  port: 443,
172
237
  method: "GET"
173
238
  })
@@ -187,7 +252,7 @@ class layout {
187
252
  }
188
253
  getLayoutMeta() {
189
254
  return new Promise((resolve, reject) => {
190
- this.conn.apiRequest(this.endpoint).then(res => {
255
+ this.database.apiRequest(this.endpoint).then(res => {
191
256
  this.metadata = res.response;
192
257
  resolve(this);
193
258
  })
@@ -239,7 +304,7 @@ class record extends EventEmitter {
239
304
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
240
305
  if (!this.layout.metadata)
241
306
  yield this.layout.getLayoutMeta();
242
- this.layout.conn.apiRequest(this.endpoint, {
307
+ this.layout.database.apiRequest(this.endpoint, {
243
308
  port: 443,
244
309
  method: "GET"
245
310
  })
@@ -262,24 +327,24 @@ class record extends EventEmitter {
262
327
  });
263
328
  }));
264
329
  }
265
- commit(extraBody = {}) {
330
+ commit(extraBody = {
331
+ fieldData: undefined
332
+ }) {
266
333
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
267
334
  let data = this.toObject();
268
335
  delete data.recordId;
269
336
  delete data.modId;
270
337
  if (this.recordId === -1) {
271
338
  // This is a new record
272
- this.layout.conn.apiRequest(`${this.layout.endpoint}/records`, {
339
+ extraBody.fieldData = data.fieldData;
340
+ this.layout.database.apiRequest(`${this.layout.endpoint}/records`, {
273
341
  port: 443,
274
342
  method: "POST",
275
- body: JSON.stringify({
276
- fieldData: data.fieldData
277
- })
343
+ body: JSON.stringify(extraBody)
278
344
  })
279
345
  .then(res => {
280
346
  if (res.messages[0].code === "0") {
281
347
  this.recordId = parseInt(res.response.recordId);
282
- console.log(this.recordId);
283
348
  this.modId = parseInt(res.response.modId);
284
349
  resolve(this);
285
350
  }
@@ -294,7 +359,7 @@ class record extends EventEmitter {
294
359
  }
295
360
  for (let item of Object.keys(extraBody))
296
361
  data[item] = extraBody[item];
297
- this.layout.conn.apiRequest(this.endpoint, {
362
+ this.layout.database.apiRequest(this.endpoint, {
298
363
  port: 443,
299
364
  method: "PATCH",
300
365
  body: JSON.stringify(data)
@@ -374,7 +439,7 @@ class field {
374
439
  form.append("upload", new File([buffer], filename, { type: mime }));
375
440
  let _fetch = yield fetch(`${this.record.endpoint}/containers/${this.id}/1`, {
376
441
  method: "POST",
377
- headers: { "Authorization": "Bearer " + this.record.layout.conn.token },
442
+ headers: { "Authorization": "Bearer " + this.record.layout.database.token },
378
443
  body: form
379
444
  }).then(res => res.json())
380
445
  .then(data => {
@@ -416,7 +481,7 @@ class portalItem extends record {
416
481
  attachPortal(portal) {
417
482
  this.portal = portal;
418
483
  }
419
- commit(extraBody = {}) {
484
+ commit(extraBody = { fieldData: undefined }) {
420
485
  return this.portal.record.commit(extraBody);
421
486
  }
422
487
  toObject(fieldFilter) {
@@ -466,7 +531,7 @@ class find {
466
531
  find() {
467
532
  return new Promise((resolve, reject) => {
468
533
  // console.log(this.#toObject())
469
- this.layout.conn.apiRequest(`${this.layout.endpoint}/_find`, {
534
+ this.layout.database.apiRequest(`${this.layout.endpoint}/_find`, {
470
535
  port: 443,
471
536
  method: "POST",
472
537
  body: JSON.stringify(this.toObject())
@@ -498,6 +563,7 @@ export class FMError extends Error {
498
563
  super(errs.find(err => err.e === code).d || "Unknown error");
499
564
  this.httpStatus = httpStatus;
500
565
  this.res = res;
566
+ this.messages = res.messages;
501
567
  this.code = typeof code === "string" ? parseInt(code) : code;
502
568
  Error.captureStackTrace(this, FMError);
503
569
  }
package/index.ts CHANGED
@@ -25,6 +25,47 @@ import { fileURLToPath } from "url"
25
25
  import * as https from "https";
26
26
  // import * as btoa from "btoa";
27
27
 
28
+ interface connectionOptions {
29
+ hostname: string | undefined,
30
+ database: databaseOptions
31
+ }
32
+
33
+ interface hostConnectionOptions {
34
+ hostname: string
35
+ database: loginOptionsOAuth | loginOptionsFileMaker | loginOptionsClaris | loginOptionsToken
36
+ }
37
+
38
+ interface databaseOptions {
39
+ method: any
40
+ database: string
41
+ }
42
+
43
+ interface loginOptionsToken extends databaseOptions {
44
+ method: "token"
45
+ token: string
46
+ }
47
+
48
+ interface loginOptionsOAuth extends databaseOptions {
49
+ method: "oauth"
50
+ oauth: {
51
+ requestId: string,
52
+ requestIdentifier: string
53
+ }
54
+ }
55
+
56
+ interface loginOptionsFileMaker extends databaseOptions {
57
+ method: "filemaker"
58
+ username: string,
59
+ password: string,
60
+ }
61
+
62
+ interface loginOptionsClaris extends databaseOptions {
63
+ method: "claris"
64
+ claris: {
65
+ fmid: string
66
+ }
67
+ }
68
+
28
69
  // @ts-ignore
29
70
  const errs = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'fmErrors.json')).toString())
30
71
 
@@ -39,86 +80,23 @@ interface recordObject {
39
80
  fieldData: any
40
81
  }
41
82
 
42
- export default class FileMakerConnection {
43
- public hostname: string;
44
- public database: string;
45
- public token: any;
46
- private username: any;
47
- private password: any;
48
- private rejectUnauthroized: boolean;
49
-
50
- constructor() {}
51
-
52
- get endpoint(): string {
53
- return `https://${this.hostname}/fmi/data/v2/databases/${encodeURI(this.database)}`
54
- }
55
-
56
- async login(hostname, database, username, password, rejectUnauthorized = true) {
57
- if (this.token) throw new Error("Already logged in. Run logout() first")
58
-
59
- this.username = username
60
- this.password = password
61
- this.hostname = hostname
62
- this.database = database
63
- this.rejectUnauthroized = rejectUnauthorized
64
-
65
- return await this.createSession()
66
- }
83
+ class database {
84
+ external: boolean;
85
+ public name: string;
67
86
 
68
- logout(): Promise<void> {
69
- return new Promise(async (resolve, reject) => {
70
- if (!this.token) reject(new Error("Not logged in"))
87
+ protected host: FileMakerConnection;
88
+ protected props: databaseOptions;
71
89
 
72
- let _fetch = await fetch(`${this.endpoint}/sessions/${this.token}`, {
73
- method: "DELETE",
74
- headers: {
75
- "content-type": "application/json"
76
- }
77
- })
78
- let data = await _fetch.json()
79
- // console.log(data)
80
- this.token = null
81
- this.database = null
82
- this.hostname = null
83
- resolve()
84
- })
85
- }
90
+ public hostname: string;
86
91
 
87
- importSession(hostname, database, token, rejectUnauthorized = true) {
88
- this.token = token
89
- this.database = database
90
- this.hostname = hostname
91
- this.rejectUnauthroized = rejectUnauthorized
92
+ constructor(props: databaseOptions, host: FileMakerConnection = null) {
93
+ this.props = props
94
+ this.name = this.props.database
95
+ if (host) this.host = host
92
96
  }
93
97
 
94
- private createSession(): Promise<string> {
95
- return new Promise(async (resolve, reject) => {
96
- fetch(`${this.endpoint}/sessions`, {
97
- hostname: this.hostname,
98
- port: 443,
99
- method: "POST",
100
- headers: {
101
- "Content-Type": "application/json",
102
- "Authorization": "Basic " + Buffer.from(this.username + ":" + this.password).toString("base64")
103
- }
104
- }).then(res => {
105
- console.log(res)
106
- return res.json()
107
- })
108
- .then(res => {
109
- let _res = res as any
110
- if (_res.messages[0].code === "0") {
111
- this.token = _res.response.token
112
- console.log(_res)
113
- resolve(this.token)
114
- } else {
115
- reject(new FMError(_res.messages[0].code, _res.status, res))
116
- }
117
- })
118
- .catch(e => {
119
- reject(e)
120
- })
121
- })
98
+ get token() {
99
+ return this.host.token
122
100
  }
123
101
 
124
102
  getLayout(name): layout {
@@ -128,8 +106,8 @@ export default class FileMakerConnection {
128
106
  async apiRequest(url: string | Request, options: any = {}): Promise<any> {
129
107
  if (!options.headers) options.headers = {}
130
108
  options.headers["content-type"] = options.headers["content-type"] ? options.headers["content-type"] : "application/json"
131
- options.headers["authorization"] = "Bearer " + this.token
132
- options.rejectUnauthorized = this.rejectUnauthroized
109
+ options.headers["authorization"] = "Bearer " + this.host.token
110
+ options.rejectUnauthorized = this.host.rejectUnauthroized
133
111
 
134
112
  let _fetch = await fetch(url, options)
135
113
  let data = await _fetch.json()
@@ -159,19 +137,159 @@ export default class FileMakerConnection {
159
137
  script(name, parameter): Script {
160
138
  return ({name, parameter} as Script)
161
139
  }
140
+
141
+ get endpoint(): string {
142
+ return `https://${this.hostname || this.host.hostname}/fmi/data/v2/databases/${encodeURI(this.name)}`
143
+ }
144
+
145
+ get externalLoginInfo() {
146
+ // Returns an object that can be used when using this database object as an external source
147
+ let out = {
148
+ database: this.name,
149
+ username: undefined,
150
+ password: undefined,
151
+ oauthRequestId: undefined,
152
+ oauthIdentifier: undefined
153
+ }
154
+ switch (this.props.method) {
155
+ case "filemaker":
156
+ out.username = (<loginOptionsFileMaker>this.props).username
157
+ out.password = (<loginOptionsFileMaker>this.props).password
158
+ case "token":
159
+ throw "Token logins cannot be used for connecting to external sources. Please either use no login method, or open a second connection."
160
+ case "oauth":
161
+ out.oauthRequestId = (<loginOptionsOAuth>this.props).oauth.requestId
162
+ out.oauthIdentifier = (<loginOptionsOAuth>this.props).oauth.requestIdentifier
163
+
164
+ case "claris":
165
+ throw "Claris logins cannot be used for connecting to external sources. Please either use no login method, or open a second connection."
166
+ }
167
+ return out
168
+ }
169
+ }
170
+
171
+ export default class FileMakerConnection extends database{
172
+ private _token: any;
173
+ private username: any;
174
+ private password: any;
175
+ public readonly rejectUnauthroized: boolean;
176
+ externalSources: database[];
177
+
178
+ constructor(conn: hostConnectionOptions, externalDataSources:databaseOptions[] = [], rejectUnauthorized = true) {
179
+ super(conn.database);
180
+ this.host = this
181
+ this.hostname = conn.hostname
182
+ this.externalSources = externalDataSources.map(i => {let e = new database(i, this); e.external = true; return e;})
183
+ this.rejectUnauthroized = rejectUnauthorized
184
+ }
185
+
186
+ logout(): Promise<void> {
187
+ return new Promise(async (resolve, reject) => {
188
+ if (!this.token) reject(new Error("Not logged in"))
189
+
190
+ let _fetch = await fetch(`${this.endpoint}/sessions/${this.token}`, {
191
+ method: "DELETE",
192
+ headers: {
193
+ "content-type": "application/json"
194
+ }
195
+ })
196
+ let data = await _fetch.json()
197
+ // console.log(data)
198
+ this._token = null
199
+ this.name = null
200
+ this.hostname = null
201
+ resolve()
202
+ })
203
+ }
204
+
205
+ login() {
206
+ return new Promise<string>((resolve, reject) => {
207
+ if (this.token) throw new Error("Already logged in. Run logout() first")
208
+
209
+ if (this.props.method === "filemaker") {
210
+ this.username = (<loginOptionsFileMaker>this.props).username
211
+ this.name = this.props.database
212
+
213
+ fetch(`${this.endpoint}/sessions`, {
214
+ hostname: this.hostname,
215
+ port: 443,
216
+ method: "POST",
217
+ headers: {
218
+ "Content-Type": "application/json",
219
+ "Authorization": "Basic " + Buffer.from(this.username + ":" + (<loginOptionsFileMaker>this.props).password).toString("base64")
220
+ }
221
+ }).then(async res => {
222
+ if (res.status === 200) {
223
+ this._token = res.headers.get('x-fm-data-access-token')
224
+ resolve(this._token)
225
+ } else {
226
+ let _res = <any>(await res.json())
227
+ reject(new FMError(_res.messages[0].code, _res.status, res))
228
+ }
229
+ })
230
+ .catch(e => {
231
+ reject(e)
232
+ })
233
+ }
234
+ else if (this.props.method === "token") {
235
+ this._token = (<loginOptionsToken>this.props).token
236
+ this.name = this.props.database
237
+ resolve(this.token)
238
+ }
239
+ else if (this.props.method === "oauth") {
240
+ this.name = this.props.database
241
+ fetch(`${this.endpoint}/sessions`, {
242
+ method: "POST",
243
+ headers: {
244
+ "Content-Type": "application/json",
245
+ "X-FM-Data-OAuth-RequestId": (<loginOptionsOAuth>this.props).oauth.requestId,
246
+ "X-FM-Data-OAuth-Identifier": (<loginOptionsOAuth>this.props).oauth.requestIdentifier
247
+ },
248
+ body: "{}"
249
+ })
250
+ .then(res => res.json())
251
+ .then(res => {
252
+ let _res = <any>res
253
+ this._token = _res.headers["x-fm-data-access-token"]
254
+ resolve(this.token)
255
+ })
256
+ }
257
+ else if (this.props.method === "claris") {
258
+ this.name = this.props.database
259
+ fetch(`${this.endpoint}/sessions`, {
260
+ method: "POST",
261
+ headers: {
262
+ "Content-Type": "application/json",
263
+ "Authorization": (<loginOptionsClaris>this.props).claris.fmid,
264
+ },
265
+ body: "{}"
266
+ })
267
+ .then(res => res.json())
268
+ .then(res => {
269
+ let _res = <any>res
270
+ this._token = _res.headers["x-fm-data-access-token"]
271
+ resolve(this.token)
272
+ })
273
+ }
274
+ })
275
+ }
276
+
277
+ get token() {
278
+ return this._token
279
+ }
162
280
  }
163
281
 
164
282
  class layout {
165
- readonly conn: FileMakerConnection;
283
+ readonly database: database;
166
284
  protected name: string;
167
285
  metadata: any;
168
- constructor(conn: FileMakerConnection, name: string) {
169
- this.conn = conn
286
+ constructor(database: database, name: string) {
287
+ this.database = database
170
288
  this.name = name
171
289
  }
172
290
 
173
291
  get endpoint() {
174
- return `${this.conn.endpoint}/layouts/${this.name}`
292
+ return `${this.database.endpoint}/layouts/${this.name}`
175
293
  }
176
294
 
177
295
  getScript(script) {
@@ -181,9 +299,9 @@ class layout {
181
299
  createRecord(): Promise<record | Error | void> {
182
300
  return new Promise((resolve, reject) => {
183
301
  // Get the layout's metadata
184
- this.conn.apiRequest(`${this.endpoint}`).then(res => {
302
+ this.getLayoutMeta().then(layout => {
185
303
  let fields = {}
186
- for (let _field of res.response.fieldMetaData) {
304
+ for (let _field of this.metadata.fieldMetaData) {
187
305
  fields[_field.name] = ""
188
306
  }
189
307
  resolve(new record(this, -1, 0, fields))
@@ -203,7 +321,7 @@ class layout {
203
321
  return new Promise(async (resolve, reject) => {
204
322
  let url = `${this.endpoint}/script/${encodeURI(script.name)}`
205
323
  if (script.parameter) url += "?" + encodeURI(script.parameter)
206
- this.conn.apiRequest(url, {
324
+ this.database.apiRequest(url, {
207
325
  port: 443,
208
326
  method: "GET"
209
327
  })
@@ -223,7 +341,7 @@ class layout {
223
341
 
224
342
  public getLayoutMeta(): Promise<layout | FMError> {
225
343
  return new Promise((resolve, reject) => {
226
- this.conn.apiRequest(this.endpoint).then(res => {
344
+ this.database.apiRequest(this.endpoint).then(res => {
227
345
  this.metadata = res.response
228
346
  resolve(this)
229
347
  })
@@ -285,7 +403,7 @@ class record extends EventEmitter {
285
403
  return new Promise(async (resolve, reject) => {
286
404
  if (!this.layout.metadata) await this.layout.getLayoutMeta()
287
405
 
288
- this.layout.conn.apiRequest(this.endpoint, {
406
+ this.layout.database.apiRequest(this.endpoint, {
289
407
  port: 443,
290
408
  method: "GET"
291
409
  })
@@ -307,7 +425,9 @@ class record extends EventEmitter {
307
425
  })
308
426
  }
309
427
 
310
- commit(extraBody = {}): Promise<record | FMError> {
428
+ commit(extraBody = {
429
+ fieldData: undefined
430
+ }): Promise<record | FMError> {
311
431
  return new Promise(async (resolve, reject) => {
312
432
  let data = this.toObject()
313
433
  delete data.recordId
@@ -315,17 +435,16 @@ class record extends EventEmitter {
315
435
 
316
436
  if (this.recordId === -1) {
317
437
  // This is a new record
318
- this.layout.conn.apiRequest(`${this.layout.endpoint}/records`, {
438
+ extraBody.fieldData = data.fieldData
439
+
440
+ this.layout.database.apiRequest(`${this.layout.endpoint}/records`, {
319
441
  port: 443,
320
442
  method: "POST",
321
- body: JSON.stringify({
322
- fieldData: data.fieldData
323
- })
443
+ body: JSON.stringify(extraBody)
324
444
  })
325
445
  .then(res => {
326
446
  if (res.messages[0].code === "0") {
327
447
  this.recordId = parseInt(res.response.recordId)
328
- console.log(this.recordId)
329
448
  this.modId = parseInt(res.response.modId)
330
449
  resolve(this)
331
450
  } else {
@@ -340,7 +459,7 @@ class record extends EventEmitter {
340
459
  }
341
460
 
342
461
  for (let item of Object.keys(extraBody)) data[item] = extraBody[item]
343
- this.layout.conn.apiRequest(this.endpoint, {
462
+ this.layout.database.apiRequest(this.endpoint, {
344
463
  port: 443,
345
464
  method: "PATCH",
346
465
  body: JSON.stringify(data)
@@ -432,7 +551,7 @@ class field {
432
551
 
433
552
  let _fetch = await fetch(`${this.record.endpoint}/containers/${this.id}/1`, {
434
553
  method: "POST",
435
- headers: {"Authorization": "Bearer " + this.record.layout.conn.token},
554
+ headers: {"Authorization": "Bearer " + this.record.layout.database.token},
436
555
  body: form
437
556
  }).then(res => res.json())
438
557
  .then(data => {
@@ -482,7 +601,7 @@ class portalItem extends record {
482
601
  this.portal = portal
483
602
  }
484
603
 
485
- commit(extraBody = {}) {
604
+ commit(extraBody = {fieldData: undefined}) {
486
605
  return this.portal.record.commit(extraBody)
487
606
  }
488
607
 
@@ -541,7 +660,7 @@ class find {
541
660
  find() {
542
661
  return new Promise((resolve, reject) => {
543
662
  // console.log(this.#toObject())
544
- this.layout.conn.apiRequest(`${this.layout.endpoint}/_find`, {
663
+ this.layout.database.apiRequest(`${this.layout.endpoint}/_find`, {
545
664
  port: 443,
546
665
  method: "POST",
547
666
  body: JSON.stringify(this.toObject())
@@ -570,12 +689,14 @@ export class FMError extends Error {
570
689
  readonly res: any
571
690
  readonly code: number
572
691
  readonly message: string
692
+ readonly messages: string
573
693
 
574
694
  constructor(code, httpStatus, res) {
575
695
  if (typeof code === "string") code = parseInt(code)
576
696
  super(errs.find(err => err.e === code).d || "Unknown error");
577
697
  this.httpStatus = httpStatus
578
698
  this.res = res
699
+ this.messages = res.messages
579
700
  this.code = typeof code === "string" ? parseInt(code) : code
580
701
  Error.captureStackTrace(this, FMError)
581
702
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jd-data-limited/easy-fm",
3
- "version": "0.0.11",
3
+ "version": "1.0.0alpha1",
4
4
  "dependencies": {
5
5
  "@types/btoa": "^1.2.3",
6
6
  "@types/events": "^3.0.0",