@jd-data-limited/easy-fm 5.0.0-beta.1 → 5.0.0-beta.4
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/LICENSE +21 -21
- package/README.md +93 -90
- package/dist/bin/cli.js +34 -5
- package/dist/bin/generateClient.d.ts +1 -0
- package/dist/bin/generateClient.js +48 -0
- package/dist/bin/generateTypes.js +20 -19
- package/dist/bin/init.d.ts +6 -0
- package/dist/bin/init.js +46 -0
- package/dist/bin/stressSearch.js +12 -12
- package/dist/connection/DataApiProvider.d.ts +15 -0
- package/dist/connection/DataApiProvider.js +246 -0
- package/dist/connection/FMHost.d.ts +1 -3
- package/dist/connection/FMHost.js +1 -3
- package/dist/connection/HostBase.d.ts +0 -2
- package/dist/connection/dataApiDatabaseSession.d.ts +11 -0
- package/dist/connection/dataApiDatabaseSession.js +139 -0
- package/dist/connection/database.d.ts +22 -56
- package/dist/connection/database.js +175 -111
- package/dist/connection/databaseBase.d.ts +9 -22
- package/dist/connection/databaseBase.js +0 -3
- package/dist/connection/databaseProvider.d.ts +196 -0
- package/dist/connection/databaseProvider.js +6 -0
- package/dist/connection/databaseSessionPool.d.ts +8 -7
- package/dist/connection/databaseSessionPool.js +110 -106
- package/dist/index.d.ts +11 -7
- package/dist/index.js +7 -5
- package/dist/layouts/layout.d.ts +0 -2
- package/dist/layouts/layout.js +6 -16
- package/dist/layouts/layoutBase.d.ts +0 -1
- package/dist/layouts/layoutInterface.d.ts +4 -1
- package/dist/models/apiResults.d.ts +7 -6
- package/dist/models/apiResults.js +1 -1
- package/dist/records/fields/baseField.d.ts +60 -0
- package/dist/records/fields/baseField.js +59 -0
- package/dist/records/fields/containerField.d.ts +18 -0
- package/dist/records/fields/containerField.js +44 -0
- package/dist/records/fields/field.d.ts +3 -0
- package/dist/records/fields/field.js +1 -0
- package/dist/records/fields/valueField.d.ts +41 -0
- package/dist/records/fields/valueField.js +108 -0
- package/dist/records/getOperations/recordGetOperation.js +24 -24
- package/dist/records/layoutRecord.d.ts +15 -8
- package/dist/records/layoutRecord.js +61 -98
- package/dist/records/portal.d.ts +1 -1
- package/dist/records/portalBase.d.ts +1 -2
- package/dist/records/portalRecord.d.ts +11 -5
- package/dist/records/portalRecord.js +24 -2
- package/dist/records/recordBase.d.ts +11 -7
- package/dist/records/recordBase.js +38 -38
- package/dist/schema.d.ts +54 -0
- package/dist/schema.js +87 -0
- package/dist/typegen/dataApiSchemaSource.d.ts +3 -0
- package/dist/typegen/dataApiSchemaSource.js +32 -0
- package/dist/typegen/dependencies.d.ts +11 -0
- package/dist/typegen/dependencies.js +67 -0
- package/dist/typegen/generate.d.ts +5 -0
- package/dist/typegen/generate.js +85 -0
- package/dist/typegen/index.d.ts +6 -0
- package/dist/typegen/index.js +6 -0
- package/dist/typegen/init.d.ts +13 -0
- package/dist/typegen/init.js +113 -0
- package/dist/typegen/types.d.ts +40 -0
- package/dist/typegen/types.js +1 -0
- package/dist/typegen/zod.d.ts +3 -0
- package/dist/typegen/zod.js +32 -0
- package/dist/types.d.ts +1 -1
- package/dist/utils/query.d.ts +21 -12
- package/dist/utils/query.js +58 -23
- package/dist/utils/temporal.d.ts +9 -0
- package/dist/utils/temporal.js +110 -0
- package/package.json +47 -24
- package/dist/layouts/recordFieldsMap.d.ts +0 -2
- package/dist/layouts/recordFieldsMap.js +0 -4
- package/dist/records/field.d.ts +0 -77
- package/dist/records/field.js +0 -192
package/dist/records/field.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
|
-
*/
|
|
4
|
-
import { RecordTypes } from '../types.js';
|
|
5
|
-
import { ApiFieldDisplayTypes, ApiFieldResultTypes, ApiFieldTypes, ApiResults } from '../models/apiResults.js';
|
|
6
|
-
import { FMError } from '../FMError.js';
|
|
7
|
-
import { Readable } from 'node:stream';
|
|
8
|
-
import { HttpError } from '../connection/Session.js';
|
|
9
|
-
/**
|
|
10
|
-
* A class representing a field in a record.
|
|
11
|
-
*
|
|
12
|
-
* @template T - The type of the field value.
|
|
13
|
-
*/
|
|
14
|
-
export class Field {
|
|
15
|
-
parent;
|
|
16
|
-
id;
|
|
17
|
-
_value;
|
|
18
|
-
#originalContents;
|
|
19
|
-
static firstContainerDownload = null;
|
|
20
|
-
constructor(record, id, originalContents) {
|
|
21
|
-
this.parent = record;
|
|
22
|
-
this.id = id;
|
|
23
|
-
this._value = originalContents;
|
|
24
|
-
this.#originalContents = originalContents;
|
|
25
|
-
}
|
|
26
|
-
/** `true` if this field has changed since it was last loaded or saved. */
|
|
27
|
-
get edited() {
|
|
28
|
-
return this.#originalContents !== this._value;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Resets the 'edited' state of this field, without changing its value
|
|
32
|
-
*/
|
|
33
|
-
updateOriginalContents() {
|
|
34
|
-
this.#originalContents = this._value;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Sets the value of the field.
|
|
38
|
-
*
|
|
39
|
-
* @param {T | null} content - The new content value to be set. Can be either the type T or null.
|
|
40
|
-
* @throws {Error} Cannot set container value using set(). Use upload() instead, if the result is a 'container'.
|
|
41
|
-
*/
|
|
42
|
-
set(content) {
|
|
43
|
-
if (this.metadata.result === 'container')
|
|
44
|
-
throw new Error('Cannot set container value using set(). Use upload() instead.');
|
|
45
|
-
else
|
|
46
|
-
this._value = content;
|
|
47
|
-
}
|
|
48
|
-
/** Returns the FileMaker metadata for this field. */
|
|
49
|
-
get metadata() {
|
|
50
|
-
if (!this.parent.layout.metadata) {
|
|
51
|
-
// Default to a regular text field
|
|
52
|
-
return {
|
|
53
|
-
name: this.id.toString(),
|
|
54
|
-
type: ApiFieldTypes.NORMAL,
|
|
55
|
-
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
56
|
-
result: ApiFieldResultTypes.TEXT,
|
|
57
|
-
global: false,
|
|
58
|
-
autoEnter: true,
|
|
59
|
-
fourDigitYear: false,
|
|
60
|
-
maxRepeat: 1,
|
|
61
|
-
maxCharacters: 0,
|
|
62
|
-
notEmpty: false,
|
|
63
|
-
numeric: false,
|
|
64
|
-
timeOfDay: false,
|
|
65
|
-
repetitionStart: 1,
|
|
66
|
-
repetitionEnd: 1,
|
|
67
|
-
valueList: ''
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
if (this.parent.type === RecordTypes.PORTAL && this.parent.portal) {
|
|
71
|
-
return this.parent.layout.metadata.portalMetaData[this.parent.portal.name || 'portal not attached'].find(i => i.name === this.id) ??
|
|
72
|
-
{
|
|
73
|
-
name: this.id.toString(),
|
|
74
|
-
type: ApiFieldTypes.NORMAL,
|
|
75
|
-
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
76
|
-
result: ApiFieldResultTypes.TEXT,
|
|
77
|
-
global: false,
|
|
78
|
-
autoEnter: true,
|
|
79
|
-
fourDigitYear: false,
|
|
80
|
-
maxRepeat: 1,
|
|
81
|
-
maxCharacters: 0,
|
|
82
|
-
notEmpty: false,
|
|
83
|
-
numeric: false,
|
|
84
|
-
timeOfDay: false,
|
|
85
|
-
repetitionStart: 1,
|
|
86
|
-
repetitionEnd: 1,
|
|
87
|
-
valueList: ''
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
return this.parent.layout.metadata.fieldMetaData.find(i => i.name === this.id) ?? {
|
|
92
|
-
name: this.id.toString(),
|
|
93
|
-
type: ApiFieldTypes.NORMAL,
|
|
94
|
-
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
95
|
-
result: ApiFieldResultTypes.TEXT,
|
|
96
|
-
global: false,
|
|
97
|
-
autoEnter: true,
|
|
98
|
-
fourDigitYear: false,
|
|
99
|
-
maxRepeat: 1,
|
|
100
|
-
maxCharacters: 0,
|
|
101
|
-
notEmpty: false,
|
|
102
|
-
numeric: false,
|
|
103
|
-
timeOfDay: false,
|
|
104
|
-
repetitionStart: 1,
|
|
105
|
-
repetitionEnd: 1,
|
|
106
|
-
valueList: ''
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/** Gets or sets the current field value. */
|
|
111
|
-
get value() {
|
|
112
|
-
// if (this.metadata.result === "container") throw "Use await field.stream() to get the contents of a container field, instead of field.value"
|
|
113
|
-
return this._value;
|
|
114
|
-
}
|
|
115
|
-
set value(value) {
|
|
116
|
-
this.set(value);
|
|
117
|
-
}
|
|
118
|
-
/** Returns this field value as a string. Throws if the value is not a string. */
|
|
119
|
-
get string() {
|
|
120
|
-
if (typeof this._value === 'string') {
|
|
121
|
-
return this._value;
|
|
122
|
-
}
|
|
123
|
-
throw new Error('Field value is not a string');
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Uploads a file to the container field.
|
|
127
|
-
*
|
|
128
|
-
* @param {Buffer} file - The file content as a buffer.
|
|
129
|
-
*
|
|
130
|
-
* @throws {Error} - Cannot upload a file to the field if it's not a container field.
|
|
131
|
-
* @throws {Error} - Upload failed with HTTP error.
|
|
132
|
-
*
|
|
133
|
-
* @returns {Promise<void>} - A promise that resolves when the file is successfully uploaded.
|
|
134
|
-
*/
|
|
135
|
-
async upload(file) {
|
|
136
|
-
if (this.metadata.result !== 'container') {
|
|
137
|
-
throw new Error('Cannot upload a file to the field; ' + this.id + ' (not a container field)');
|
|
138
|
-
}
|
|
139
|
-
const form = new FormData();
|
|
140
|
-
form.append('upload', file);
|
|
141
|
-
const res = await this.parent.layout.database.fetch(`${this.parent.endpoint}/containers/${this.id}/1`, {
|
|
142
|
-
method: 'POST',
|
|
143
|
-
body: form
|
|
144
|
-
});
|
|
145
|
-
if (!res.ok) {
|
|
146
|
-
throw await HttpError.new(res);
|
|
147
|
-
}
|
|
148
|
-
const data = ApiResults.parse(await res.json());
|
|
149
|
-
if (data.messages[0].code === 0)
|
|
150
|
-
return;
|
|
151
|
-
else {
|
|
152
|
-
throw new FMError(data.messages[0].code, res.status, res);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
async #streamAsync(options = {}) {
|
|
156
|
-
const req = await this.parent.layout.database.fetch(this.string, {
|
|
157
|
-
signal: options.abortSignal ?? null,
|
|
158
|
-
});
|
|
159
|
-
// const req = await this.parent.layout.database._apiRequestRaw(this.string, {useCookieJar: true})
|
|
160
|
-
if (!req.ok || !req.body) {
|
|
161
|
-
throw new Error(`HTTP Error: ${req.status} (${req.statusText})`);
|
|
162
|
-
}
|
|
163
|
-
return req;
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* @deprecated use webStream instead.
|
|
167
|
-
*/
|
|
168
|
-
async stream() {
|
|
169
|
-
const stream = await this.#streamAsync();
|
|
170
|
-
if (!stream.body) {
|
|
171
|
-
throw await HttpError.new(stream);
|
|
172
|
-
}
|
|
173
|
-
return {
|
|
174
|
-
// @ts-expect-error stream types are correct
|
|
175
|
-
data: Readable.fromWeb(stream.body),
|
|
176
|
-
mime: stream.headers.get('Content-Type') ?? ''
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Returns the container download as a Web `Response`.
|
|
181
|
-
*/
|
|
182
|
-
async webStream(options) {
|
|
183
|
-
return await this.#streamAsync(options);
|
|
184
|
-
}
|
|
185
|
-
/** Downloads the full container contents into memory. */
|
|
186
|
-
async arrayBuffer() {
|
|
187
|
-
const stream = await this.#streamAsync();
|
|
188
|
-
if (!stream.ok)
|
|
189
|
-
throw await HttpError.new(stream);
|
|
190
|
-
return { data: await stream.arrayBuffer(), mime: stream.headers.get('Content-Type') ?? '' };
|
|
191
|
-
}
|
|
192
|
-
}
|