@tailor-platform/sdk 0.0.1 → 0.8.0
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/CHANGELOG.md +784 -0
- package/LICENSE +21 -0
- package/README.md +8 -41
- package/dist/auth-Di3vQUrT.mjs +743 -0
- package/dist/cli/api.d.mts +213 -0
- package/dist/cli/api.mjs +4 -0
- package/dist/cli/index.d.mts +3 -0
- package/dist/cli/index.mjs +996 -0
- package/dist/configure/index.d.mts +5 -0
- package/dist/configure/index.mjs +108 -0
- package/dist/index-D-0knE68.d.mts +232 -0
- package/dist/plugin-generated.d.ts +14 -0
- package/dist/token-PbgBrNwb.mjs +5498 -0
- package/dist/types-DSAthMLp.d.mts +1389 -0
- package/dist/utils/test/index.d.mts +40 -0
- package/dist/utils/test/index.mjs +63 -0
- package/docs/cli-reference.md +484 -0
- package/docs/configuration.md +132 -0
- package/docs/core-concepts.md +504 -0
- package/docs/quickstart.md +96 -0
- package/docs/testing.md +298 -0
- package/package.json +87 -8
- package/postinstall.mjs +87 -0
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
import { clone } from "es-toolkit";
|
|
2
|
+
|
|
3
|
+
//#region src/configure/types/field.ts
|
|
4
|
+
function mapAllowedValues(values) {
|
|
5
|
+
return values.map((value) => {
|
|
6
|
+
if (typeof value === "string") return {
|
|
7
|
+
value,
|
|
8
|
+
description: ""
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
...value,
|
|
12
|
+
description: value.description ?? ""
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/configure/types/type.ts
|
|
19
|
+
const regex = {
|
|
20
|
+
uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
|
|
21
|
+
date: /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/,
|
|
22
|
+
time: /^(?<hour>\d{2}):(?<minute>\d{2})$/,
|
|
23
|
+
datetime: /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minute>\d{2}):(?<second>\d{2})(.(?<millisec>\d{3}))?Z$/
|
|
24
|
+
};
|
|
25
|
+
var TailorField = class TailorField {
|
|
26
|
+
_metadata;
|
|
27
|
+
_defined = void 0;
|
|
28
|
+
_output = void 0;
|
|
29
|
+
get metadata() {
|
|
30
|
+
return { ...this._metadata };
|
|
31
|
+
}
|
|
32
|
+
constructor(type, options, fields = {}, values) {
|
|
33
|
+
this.type = type;
|
|
34
|
+
this.fields = fields;
|
|
35
|
+
this._metadata = { required: true };
|
|
36
|
+
if (options) {
|
|
37
|
+
if (options.optional === true) this._metadata.required = false;
|
|
38
|
+
if (options.array === true) this._metadata.array = true;
|
|
39
|
+
}
|
|
40
|
+
if (values) this._metadata.allowedValues = mapAllowedValues(values);
|
|
41
|
+
}
|
|
42
|
+
static create(type, options, fields, values) {
|
|
43
|
+
return new TailorField(type, options, fields, values);
|
|
44
|
+
}
|
|
45
|
+
description(description) {
|
|
46
|
+
this._metadata.description = description;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
typeName(typeName) {
|
|
50
|
+
this._metadata.typeName = typeName;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
validate(...validate) {
|
|
54
|
+
this._metadata.validate = validate;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Parse and validate a value against this field's validation rules
|
|
59
|
+
* Returns StandardSchema Result type with success or failure
|
|
60
|
+
*/
|
|
61
|
+
parse(args) {
|
|
62
|
+
return this._parseInternal({
|
|
63
|
+
value: args.value,
|
|
64
|
+
data: args.data,
|
|
65
|
+
user: args.user,
|
|
66
|
+
pathArray: []
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validate a single value (not an array element)
|
|
71
|
+
* Used internally for array element validation
|
|
72
|
+
* @private
|
|
73
|
+
*/
|
|
74
|
+
_validateValue(args) {
|
|
75
|
+
const { value, data, user, pathArray } = args;
|
|
76
|
+
const issues = [];
|
|
77
|
+
switch (this.type) {
|
|
78
|
+
case "string":
|
|
79
|
+
if (typeof value !== "string") issues.push({
|
|
80
|
+
message: `Expected a string: received ${String(value)}`,
|
|
81
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
82
|
+
});
|
|
83
|
+
break;
|
|
84
|
+
case "integer":
|
|
85
|
+
if (typeof value !== "number" || !Number.isInteger(value)) issues.push({
|
|
86
|
+
message: `Expected an integer: received ${String(value)}`,
|
|
87
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
88
|
+
});
|
|
89
|
+
break;
|
|
90
|
+
case "float":
|
|
91
|
+
if (typeof value !== "number" || !Number.isFinite(value)) issues.push({
|
|
92
|
+
message: `Expected a number: received ${String(value)}`,
|
|
93
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
94
|
+
});
|
|
95
|
+
break;
|
|
96
|
+
case "boolean":
|
|
97
|
+
if (typeof value !== "boolean") issues.push({
|
|
98
|
+
message: `Expected a boolean: received ${String(value)}`,
|
|
99
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
100
|
+
});
|
|
101
|
+
break;
|
|
102
|
+
case "uuid":
|
|
103
|
+
if (typeof value !== "string" || !regex.uuid.test(value)) issues.push({
|
|
104
|
+
message: `Expected a valid UUID: received ${String(value)}`,
|
|
105
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
106
|
+
});
|
|
107
|
+
break;
|
|
108
|
+
case "date":
|
|
109
|
+
if (typeof value !== "string" || !regex.date.test(value)) issues.push({
|
|
110
|
+
message: `Expected to match "yyyy-MM-dd" format: received ${String(value)}`,
|
|
111
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
112
|
+
});
|
|
113
|
+
break;
|
|
114
|
+
case "datetime":
|
|
115
|
+
if (typeof value !== "string" || !regex.datetime.test(value)) issues.push({
|
|
116
|
+
message: `Expected to match ISO format: received ${String(value)}`,
|
|
117
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
118
|
+
});
|
|
119
|
+
break;
|
|
120
|
+
case "time":
|
|
121
|
+
if (typeof value !== "string" || !regex.time.test(value)) issues.push({
|
|
122
|
+
message: `Expected to match "HH:mm:ss" format`,
|
|
123
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
124
|
+
});
|
|
125
|
+
break;
|
|
126
|
+
case "enum":
|
|
127
|
+
if (this.metadata.allowedValues) {
|
|
128
|
+
const allowedValues = this.metadata.allowedValues.map((v) => v.value);
|
|
129
|
+
if (!allowedValues.includes(value)) issues.push({
|
|
130
|
+
message: `Must be one of [${allowedValues.join(", ")}]: received ${String(value)}`,
|
|
131
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
case "nested":
|
|
136
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) issues.push({
|
|
137
|
+
message: `Expected an object: received ${String(value)}`,
|
|
138
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
139
|
+
});
|
|
140
|
+
else if (this.fields && Object.keys(this.fields).length > 0) for (const [fieldName, field] of Object.entries(this.fields)) {
|
|
141
|
+
const fieldValue = value?.[fieldName];
|
|
142
|
+
const result = field._parseInternal({
|
|
143
|
+
value: fieldValue,
|
|
144
|
+
data,
|
|
145
|
+
user,
|
|
146
|
+
pathArray: pathArray.concat(fieldName)
|
|
147
|
+
});
|
|
148
|
+
if (result.issues) issues.push(...result.issues);
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
const validateFns = this.metadata.validate;
|
|
153
|
+
if (validateFns && validateFns.length > 0) for (const validateInput of validateFns) {
|
|
154
|
+
const { fn, message } = typeof validateInput === "function" ? {
|
|
155
|
+
fn: validateInput,
|
|
156
|
+
message: "Validation failed"
|
|
157
|
+
} : {
|
|
158
|
+
fn: validateInput[0],
|
|
159
|
+
message: validateInput[1]
|
|
160
|
+
};
|
|
161
|
+
if (!fn({
|
|
162
|
+
value,
|
|
163
|
+
data,
|
|
164
|
+
user
|
|
165
|
+
})) issues.push({
|
|
166
|
+
message,
|
|
167
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return issues;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Internal parse method that tracks field path for nested validation
|
|
174
|
+
* @private
|
|
175
|
+
*/
|
|
176
|
+
_parseInternal(args) {
|
|
177
|
+
const { value, data, user, pathArray } = args;
|
|
178
|
+
const issues = [];
|
|
179
|
+
const isNullOrUndefined = value === null || value === void 0;
|
|
180
|
+
if (this.metadata.required && isNullOrUndefined) {
|
|
181
|
+
issues.push({
|
|
182
|
+
message: "Required field is missing",
|
|
183
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
184
|
+
});
|
|
185
|
+
return { issues };
|
|
186
|
+
}
|
|
187
|
+
if (!this.metadata.required && isNullOrUndefined) return { value };
|
|
188
|
+
if (this.metadata.array) {
|
|
189
|
+
if (!Array.isArray(value)) {
|
|
190
|
+
issues.push({
|
|
191
|
+
message: "Expected an array",
|
|
192
|
+
path: pathArray.length > 0 ? pathArray : void 0
|
|
193
|
+
});
|
|
194
|
+
return { issues };
|
|
195
|
+
}
|
|
196
|
+
for (let i = 0; i < value.length; i++) {
|
|
197
|
+
const elementValue = value[i];
|
|
198
|
+
const elementPath = pathArray.concat(`[${i}]`);
|
|
199
|
+
const elementIssues = this._validateValue({
|
|
200
|
+
value: elementValue,
|
|
201
|
+
data,
|
|
202
|
+
user,
|
|
203
|
+
pathArray: elementPath
|
|
204
|
+
});
|
|
205
|
+
if (elementIssues.length > 0) issues.push(...elementIssues);
|
|
206
|
+
}
|
|
207
|
+
if (issues.length > 0) return { issues };
|
|
208
|
+
return { value };
|
|
209
|
+
}
|
|
210
|
+
const valueIssues = this._validateValue({
|
|
211
|
+
value,
|
|
212
|
+
data,
|
|
213
|
+
user,
|
|
214
|
+
pathArray
|
|
215
|
+
});
|
|
216
|
+
issues.push(...valueIssues);
|
|
217
|
+
if (issues.length > 0) return { issues };
|
|
218
|
+
return { value };
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const createField$1 = TailorField.create;
|
|
222
|
+
function uuid$1(options) {
|
|
223
|
+
return createField$1("uuid", options);
|
|
224
|
+
}
|
|
225
|
+
function string$1(options) {
|
|
226
|
+
return createField$1("string", options);
|
|
227
|
+
}
|
|
228
|
+
function bool$1(options) {
|
|
229
|
+
return createField$1("boolean", options);
|
|
230
|
+
}
|
|
231
|
+
function int$1(options) {
|
|
232
|
+
return createField$1("integer", options);
|
|
233
|
+
}
|
|
234
|
+
function float$1(options) {
|
|
235
|
+
return createField$1("float", options);
|
|
236
|
+
}
|
|
237
|
+
function date$1(options) {
|
|
238
|
+
return createField$1("date", options);
|
|
239
|
+
}
|
|
240
|
+
function datetime$1(options) {
|
|
241
|
+
return createField$1("datetime", options);
|
|
242
|
+
}
|
|
243
|
+
function time$1(options) {
|
|
244
|
+
return createField$1("time", options);
|
|
245
|
+
}
|
|
246
|
+
function _enum$1(...args) {
|
|
247
|
+
let values;
|
|
248
|
+
let options;
|
|
249
|
+
const lastArg = args[args.length - 1];
|
|
250
|
+
if (typeof lastArg === "object" && !("value" in lastArg)) {
|
|
251
|
+
values = args.slice(0, -1);
|
|
252
|
+
options = lastArg;
|
|
253
|
+
} else {
|
|
254
|
+
values = args;
|
|
255
|
+
options = void 0;
|
|
256
|
+
}
|
|
257
|
+
return createField$1("enum", options, void 0, values);
|
|
258
|
+
}
|
|
259
|
+
function object$1(fields, options) {
|
|
260
|
+
return createField$1("nested", options, fields);
|
|
261
|
+
}
|
|
262
|
+
const t = {
|
|
263
|
+
uuid: uuid$1,
|
|
264
|
+
string: string$1,
|
|
265
|
+
bool: bool$1,
|
|
266
|
+
int: int$1,
|
|
267
|
+
float: float$1,
|
|
268
|
+
date: date$1,
|
|
269
|
+
datetime: datetime$1,
|
|
270
|
+
time: time$1,
|
|
271
|
+
enum: _enum$1,
|
|
272
|
+
object: object$1
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region src/configure/types/user.ts
|
|
277
|
+
/** Represents an unauthenticated user in the Tailor platform. */
|
|
278
|
+
const unauthenticatedTailorUser = {
|
|
279
|
+
id: "00000000-0000-0000-0000-000000000000",
|
|
280
|
+
type: "",
|
|
281
|
+
workspaceId: "00000000-0000-0000-0000-000000000000",
|
|
282
|
+
attributes: null,
|
|
283
|
+
attributeList: []
|
|
284
|
+
};
|
|
285
|
+
const tailorUserMap = `{ id: user.id, type: user.type, workspaceId: user.workspace_id, attributes: user.attribute_map, attributeList: user.attributes }`;
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/configure/services/tailordb/permission.ts
|
|
289
|
+
const operatorMap = {
|
|
290
|
+
"=": "eq",
|
|
291
|
+
"!=": "ne",
|
|
292
|
+
in: "in",
|
|
293
|
+
"not in": "nin"
|
|
294
|
+
};
|
|
295
|
+
function normalizeOperand(operand) {
|
|
296
|
+
if (typeof operand === "object" && "user" in operand) return { user: { id: "_id" }[operand.user] ?? operand.user };
|
|
297
|
+
return operand;
|
|
298
|
+
}
|
|
299
|
+
function normalizeConditions(conditions) {
|
|
300
|
+
return conditions.map((cond) => {
|
|
301
|
+
const [left, operator, right] = cond;
|
|
302
|
+
return [
|
|
303
|
+
normalizeOperand(left),
|
|
304
|
+
operatorMap[operator],
|
|
305
|
+
normalizeOperand(right)
|
|
306
|
+
];
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
function isObjectFormat(p) {
|
|
310
|
+
return typeof p === "object" && p !== null && "conditions" in p;
|
|
311
|
+
}
|
|
312
|
+
function isSingleArrayConditionFormat(cond) {
|
|
313
|
+
return cond.length >= 2 && typeof cond[1] === "string";
|
|
314
|
+
}
|
|
315
|
+
function normalizePermission(permission) {
|
|
316
|
+
return Object.keys(permission).reduce((acc, action) => {
|
|
317
|
+
acc[action] = permission[action].map((p) => normalizeActionPermission(p));
|
|
318
|
+
return acc;
|
|
319
|
+
}, {});
|
|
320
|
+
}
|
|
321
|
+
function normalizeGqlPermission(permission) {
|
|
322
|
+
return permission.map((policy) => normalizeGqlPolicy(policy));
|
|
323
|
+
}
|
|
324
|
+
function normalizeGqlPolicy(policy) {
|
|
325
|
+
return {
|
|
326
|
+
conditions: policy.conditions ? normalizeConditions(policy.conditions) : [],
|
|
327
|
+
actions: policy.actions === "all" ? ["all"] : policy.actions,
|
|
328
|
+
permit: policy.permit ? "allow" : "deny",
|
|
329
|
+
description: policy.description
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function normalizeActionPermission(permission) {
|
|
333
|
+
if (isObjectFormat(permission)) return {
|
|
334
|
+
conditions: normalizeConditions(isSingleArrayConditionFormat(permission.conditions) ? [permission.conditions] : permission.conditions),
|
|
335
|
+
permit: permission.permit ? "allow" : "deny",
|
|
336
|
+
description: permission.description
|
|
337
|
+
};
|
|
338
|
+
if (isSingleArrayConditionFormat(permission)) {
|
|
339
|
+
const [op1, operator, op2, permit] = [...permission, true];
|
|
340
|
+
return {
|
|
341
|
+
conditions: normalizeConditions([[
|
|
342
|
+
op1,
|
|
343
|
+
operator,
|
|
344
|
+
op2
|
|
345
|
+
]]),
|
|
346
|
+
permit: permit ? "allow" : "deny"
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
const conditions = [];
|
|
350
|
+
const conditionArray = permission;
|
|
351
|
+
let conditionArrayPermit = true;
|
|
352
|
+
for (const item of conditionArray) {
|
|
353
|
+
if (typeof item === "boolean") {
|
|
354
|
+
conditionArrayPermit = item;
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
conditions.push(item);
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
conditions: normalizeConditions(conditions),
|
|
361
|
+
permit: conditionArrayPermit ? "allow" : "deny"
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
//#endregion
|
|
366
|
+
//#region src/configure/services/tailordb/schema.ts
|
|
367
|
+
function isRelationSelfConfig(config) {
|
|
368
|
+
return config.toward.type === "self";
|
|
369
|
+
}
|
|
370
|
+
var TailorDBField = class TailorDBField extends TailorField {
|
|
371
|
+
_ref = void 0;
|
|
372
|
+
_pendingSelfRelation = void 0;
|
|
373
|
+
get reference() {
|
|
374
|
+
return clone(this._ref);
|
|
375
|
+
}
|
|
376
|
+
get metadata() {
|
|
377
|
+
return { ...this._metadata };
|
|
378
|
+
}
|
|
379
|
+
get config() {
|
|
380
|
+
return {
|
|
381
|
+
type: this.type,
|
|
382
|
+
...this._metadata,
|
|
383
|
+
...this.type === "nested" && Object.keys(this.fields).length > 0 ? { fields: Object.entries(this.fields).reduce((acc, [key, field]) => {
|
|
384
|
+
acc[key] = field.config;
|
|
385
|
+
return acc;
|
|
386
|
+
}, {}) } : {},
|
|
387
|
+
validate: this._metadata.validate?.map((v) => {
|
|
388
|
+
const { fn, message } = typeof v === "function" ? {
|
|
389
|
+
fn: v,
|
|
390
|
+
message: `failed by \`${v.toString().trim()}\``
|
|
391
|
+
} : {
|
|
392
|
+
fn: v[0],
|
|
393
|
+
message: v[1]
|
|
394
|
+
};
|
|
395
|
+
return {
|
|
396
|
+
script: { expr: `(${fn.toString().trim()})({ value: _value, data: _data, user: ${tailorUserMap} })` },
|
|
397
|
+
errorMessage: message
|
|
398
|
+
};
|
|
399
|
+
}),
|
|
400
|
+
hooks: this._metadata.hooks ? {
|
|
401
|
+
create: this._metadata.hooks.create ? { expr: `(${this._metadata.hooks.create.toString().trim()})({ value: _value, data: _data, user: ${tailorUserMap} })` } : void 0,
|
|
402
|
+
update: this._metadata.hooks.update ? { expr: `(${this._metadata.hooks.update.toString().trim()})({ value: _value, data: _data, user: ${tailorUserMap} })` } : void 0
|
|
403
|
+
} : void 0,
|
|
404
|
+
serial: this._metadata.serial ? {
|
|
405
|
+
start: this._metadata.serial.start,
|
|
406
|
+
maxValue: this._metadata.serial.maxValue,
|
|
407
|
+
format: "format" in this._metadata.serial ? this._metadata.serial.format : void 0
|
|
408
|
+
} : void 0
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
constructor(type, options, fields, values) {
|
|
412
|
+
super(type, options, fields, values);
|
|
413
|
+
}
|
|
414
|
+
static create(type, options, fields, values) {
|
|
415
|
+
return new TailorDBField(type, options, fields, values);
|
|
416
|
+
}
|
|
417
|
+
description(description) {
|
|
418
|
+
return super.description(description);
|
|
419
|
+
}
|
|
420
|
+
relation(config) {
|
|
421
|
+
this._metadata.index = true;
|
|
422
|
+
this._metadata.foreignKey = true;
|
|
423
|
+
this._metadata.unique = ["oneToOne", "1-1"].includes(config.type);
|
|
424
|
+
const key = config.toward.key ?? "id";
|
|
425
|
+
const backward = config.backward ?? "";
|
|
426
|
+
if (!isRelationSelfConfig(config)) {
|
|
427
|
+
this._metadata.foreignKeyType = config.toward.type.name;
|
|
428
|
+
this._metadata.foreignKeyField = key;
|
|
429
|
+
}
|
|
430
|
+
if (config.type === "keyOnly") return this;
|
|
431
|
+
if (isRelationSelfConfig(config)) this._pendingSelfRelation = {
|
|
432
|
+
as: config.toward.as,
|
|
433
|
+
key,
|
|
434
|
+
backward
|
|
435
|
+
};
|
|
436
|
+
else {
|
|
437
|
+
const forward = config.toward.as;
|
|
438
|
+
this._ref = {
|
|
439
|
+
type: config.toward.type,
|
|
440
|
+
nameMap: [forward, backward],
|
|
441
|
+
key
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
this._metadata.relation = true;
|
|
445
|
+
return this;
|
|
446
|
+
}
|
|
447
|
+
index() {
|
|
448
|
+
this._metadata.index = true;
|
|
449
|
+
return this;
|
|
450
|
+
}
|
|
451
|
+
unique() {
|
|
452
|
+
this._metadata.unique = true;
|
|
453
|
+
this._metadata.index = true;
|
|
454
|
+
return this;
|
|
455
|
+
}
|
|
456
|
+
vector() {
|
|
457
|
+
this._metadata.vector = true;
|
|
458
|
+
return this;
|
|
459
|
+
}
|
|
460
|
+
hooks(hooks) {
|
|
461
|
+
this._metadata.hooks = hooks;
|
|
462
|
+
return this;
|
|
463
|
+
}
|
|
464
|
+
validate(...validate) {
|
|
465
|
+
this._metadata.validate = validate;
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
serial(config) {
|
|
469
|
+
this._metadata.serial = config;
|
|
470
|
+
return this;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Clone the field with optional overrides for field options
|
|
474
|
+
* @param options - Optional field options to override
|
|
475
|
+
* @returns A new TailorDBField instance with the same configuration
|
|
476
|
+
*/
|
|
477
|
+
clone(options) {
|
|
478
|
+
const clonedField = Object.create(Object.getPrototypeOf(this));
|
|
479
|
+
Object.assign(clonedField, {
|
|
480
|
+
type: this.type,
|
|
481
|
+
fields: this.fields,
|
|
482
|
+
_defined: this._defined,
|
|
483
|
+
_output: this._output
|
|
484
|
+
});
|
|
485
|
+
clonedField._metadata = { ...this._metadata };
|
|
486
|
+
if (options) {
|
|
487
|
+
if (options.optional !== void 0) clonedField._metadata.required = !options.optional;
|
|
488
|
+
if (options.array !== void 0) clonedField._metadata.array = options.array;
|
|
489
|
+
}
|
|
490
|
+
if (this._ref) clonedField._ref = clone(this._ref);
|
|
491
|
+
if (this._pendingSelfRelation) clonedField._pendingSelfRelation = { ...this._pendingSelfRelation };
|
|
492
|
+
return clonedField;
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
const createField = TailorDBField.create;
|
|
496
|
+
function uuid(options) {
|
|
497
|
+
return createField("uuid", options);
|
|
498
|
+
}
|
|
499
|
+
function string(options) {
|
|
500
|
+
return createField("string", options);
|
|
501
|
+
}
|
|
502
|
+
function bool(options) {
|
|
503
|
+
return createField("boolean", options);
|
|
504
|
+
}
|
|
505
|
+
function int(options) {
|
|
506
|
+
return createField("integer", options);
|
|
507
|
+
}
|
|
508
|
+
function float(options) {
|
|
509
|
+
return createField("float", options);
|
|
510
|
+
}
|
|
511
|
+
function date(options) {
|
|
512
|
+
return createField("date", options);
|
|
513
|
+
}
|
|
514
|
+
function datetime(options) {
|
|
515
|
+
return createField("datetime", options);
|
|
516
|
+
}
|
|
517
|
+
function time(options) {
|
|
518
|
+
return createField("time", options);
|
|
519
|
+
}
|
|
520
|
+
function _enum(...args) {
|
|
521
|
+
let values;
|
|
522
|
+
let options;
|
|
523
|
+
const lastArg = args[args.length - 1];
|
|
524
|
+
if (typeof lastArg === "object" && !("value" in lastArg)) {
|
|
525
|
+
values = args.slice(0, -1);
|
|
526
|
+
options = lastArg;
|
|
527
|
+
} else {
|
|
528
|
+
values = args;
|
|
529
|
+
options = void 0;
|
|
530
|
+
}
|
|
531
|
+
return createField("enum", options, void 0, values);
|
|
532
|
+
}
|
|
533
|
+
function object(fields, options) {
|
|
534
|
+
return createField("nested", options, fields);
|
|
535
|
+
}
|
|
536
|
+
var TailorDBType = class {
|
|
537
|
+
_output = null;
|
|
538
|
+
_description;
|
|
539
|
+
referenced = {};
|
|
540
|
+
_settings = {};
|
|
541
|
+
_indexes = [];
|
|
542
|
+
_permissions = {};
|
|
543
|
+
_files = {};
|
|
544
|
+
constructor(name, fields, options) {
|
|
545
|
+
this.name = name;
|
|
546
|
+
this.fields = fields;
|
|
547
|
+
this._description = options.description;
|
|
548
|
+
if (options.pluralForm) {
|
|
549
|
+
if (name === options.pluralForm) throw new Error(`The name and the plural form must be different. name=${name}`);
|
|
550
|
+
this._settings.pluralForm = options.pluralForm;
|
|
551
|
+
}
|
|
552
|
+
Object.entries(this.fields).forEach(([fieldName, field]) => {
|
|
553
|
+
const f = field;
|
|
554
|
+
const pending = f._pendingSelfRelation;
|
|
555
|
+
if (pending) {
|
|
556
|
+
const forward = pending.as ?? fieldName.replace(/(ID|Id|id)$/u, "");
|
|
557
|
+
f._ref = {
|
|
558
|
+
type: this,
|
|
559
|
+
nameMap: [forward, pending.backward],
|
|
560
|
+
key: pending.key
|
|
561
|
+
};
|
|
562
|
+
f._metadata.foreignKeyType = this.name;
|
|
563
|
+
f._metadata.foreignKeyField = pending.key;
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
Object.entries(this.fields).forEach(([fieldName, field]) => {
|
|
567
|
+
if (field.reference && field.reference !== void 0) {
|
|
568
|
+
const ref = field.reference;
|
|
569
|
+
if (ref.type) {
|
|
570
|
+
const backwardFieldName = ref.nameMap?.[1];
|
|
571
|
+
if (backwardFieldName !== void 0) ref.type.referenced[backwardFieldName] = [this, fieldName];
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
get metadata() {
|
|
577
|
+
const metadataFields = Object.entries(this.fields).reduce((acc, [key, field]) => {
|
|
578
|
+
acc[key] = field.config;
|
|
579
|
+
return acc;
|
|
580
|
+
}, {});
|
|
581
|
+
const indexes = {};
|
|
582
|
+
if (this._indexes && this._indexes.length > 0) this._indexes.forEach((index) => {
|
|
583
|
+
const fieldNames = index.fields.map((field) => String(field));
|
|
584
|
+
const key = index.name || `idx_${fieldNames.join("_")}`;
|
|
585
|
+
indexes[key] = {
|
|
586
|
+
fields: fieldNames,
|
|
587
|
+
unique: index.unique
|
|
588
|
+
};
|
|
589
|
+
});
|
|
590
|
+
return {
|
|
591
|
+
name: this.name,
|
|
592
|
+
schema: {
|
|
593
|
+
description: this._description,
|
|
594
|
+
extends: false,
|
|
595
|
+
fields: metadataFields,
|
|
596
|
+
settings: this._settings,
|
|
597
|
+
permissions: this._permissions,
|
|
598
|
+
files: this._files,
|
|
599
|
+
...Object.keys(indexes).length > 0 && { indexes }
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
hooks(hooks) {
|
|
604
|
+
Object.entries(hooks).forEach(([fieldName, fieldHooks]) => {
|
|
605
|
+
this.fields[fieldName].hooks(fieldHooks);
|
|
606
|
+
});
|
|
607
|
+
return this;
|
|
608
|
+
}
|
|
609
|
+
validate(validators) {
|
|
610
|
+
Object.entries(validators).forEach(([fieldName, fieldValidators]) => {
|
|
611
|
+
const field = this.fields[fieldName];
|
|
612
|
+
const validators$1 = fieldValidators;
|
|
613
|
+
const isValidateConfig = (v) => {
|
|
614
|
+
return Array.isArray(v) && v.length === 2 && typeof v[1] === "string";
|
|
615
|
+
};
|
|
616
|
+
if (Array.isArray(validators$1)) if (isValidateConfig(validators$1)) field.validate(validators$1);
|
|
617
|
+
else field.validate(...validators$1);
|
|
618
|
+
else field.validate(validators$1);
|
|
619
|
+
});
|
|
620
|
+
return this;
|
|
621
|
+
}
|
|
622
|
+
features(features) {
|
|
623
|
+
this._settings = {
|
|
624
|
+
...this._settings,
|
|
625
|
+
...features
|
|
626
|
+
};
|
|
627
|
+
return this;
|
|
628
|
+
}
|
|
629
|
+
indexes(...indexes) {
|
|
630
|
+
this._indexes = indexes;
|
|
631
|
+
return this;
|
|
632
|
+
}
|
|
633
|
+
files(files) {
|
|
634
|
+
this._files = files;
|
|
635
|
+
return this;
|
|
636
|
+
}
|
|
637
|
+
permission(permission) {
|
|
638
|
+
const ret = this;
|
|
639
|
+
ret._permissions.record = normalizePermission(permission);
|
|
640
|
+
return ret;
|
|
641
|
+
}
|
|
642
|
+
gqlPermission(permission) {
|
|
643
|
+
const ret = this;
|
|
644
|
+
ret._permissions.gql = normalizeGqlPermission(permission);
|
|
645
|
+
return ret;
|
|
646
|
+
}
|
|
647
|
+
description(description) {
|
|
648
|
+
this._description = description;
|
|
649
|
+
return this;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Pick specific fields from the type
|
|
653
|
+
* @param keys - Array of field keys to pick
|
|
654
|
+
* @param options - Optional field options to apply to picked fields
|
|
655
|
+
* @returns An object containing only the specified fields
|
|
656
|
+
*/
|
|
657
|
+
pickFields(keys, options) {
|
|
658
|
+
const result = {};
|
|
659
|
+
for (const key of keys) if (options) result[key] = this.fields[key].clone(options);
|
|
660
|
+
else result[key] = this.fields[key];
|
|
661
|
+
return result;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Omit specific fields from the type
|
|
665
|
+
* @param keys - Array of field keys to omit
|
|
666
|
+
* @returns An object containing all fields except the specified ones
|
|
667
|
+
*/
|
|
668
|
+
omitFields(keys) {
|
|
669
|
+
const keysSet = new Set(keys);
|
|
670
|
+
const result = {};
|
|
671
|
+
for (const key in this.fields) if (Object.hasOwn(this.fields, key) && !keysSet.has(key)) result[key] = this.fields[key];
|
|
672
|
+
return result;
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
const idField = uuid();
|
|
676
|
+
function dbType(name, fieldsOrDescription, fields) {
|
|
677
|
+
const typeName = Array.isArray(name) ? name[0] : name;
|
|
678
|
+
const pluralForm = Array.isArray(name) ? name[1] : void 0;
|
|
679
|
+
let description;
|
|
680
|
+
let fieldDef;
|
|
681
|
+
if (typeof fieldsOrDescription === "string") {
|
|
682
|
+
description = fieldsOrDescription;
|
|
683
|
+
fieldDef = fields;
|
|
684
|
+
} else fieldDef = fieldsOrDescription;
|
|
685
|
+
return new TailorDBType(typeName, {
|
|
686
|
+
id: idField,
|
|
687
|
+
...fieldDef
|
|
688
|
+
}, {
|
|
689
|
+
pluralForm,
|
|
690
|
+
description
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
const db = {
|
|
694
|
+
type: dbType,
|
|
695
|
+
uuid,
|
|
696
|
+
string,
|
|
697
|
+
bool,
|
|
698
|
+
int,
|
|
699
|
+
float,
|
|
700
|
+
date,
|
|
701
|
+
datetime,
|
|
702
|
+
time,
|
|
703
|
+
enum: _enum,
|
|
704
|
+
object,
|
|
705
|
+
fields: { timestamps: () => ({
|
|
706
|
+
createdAt: datetime().hooks({ create: () => (/* @__PURE__ */ new Date()).toISOString() }).description("Record creation timestamp"),
|
|
707
|
+
updatedAt: datetime({ optional: true }).hooks({ update: () => (/* @__PURE__ */ new Date()).toISOString() }).description("Record last update timestamp")
|
|
708
|
+
}) }
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
//#endregion
|
|
712
|
+
//#region src/configure/config.ts
|
|
713
|
+
let distPath = null;
|
|
714
|
+
const getDistDir = () => {
|
|
715
|
+
const configured = process.env.TAILOR_SDK_OUTPUT_DIR;
|
|
716
|
+
if (configured && configured !== distPath) distPath = configured;
|
|
717
|
+
else if (distPath === null) distPath = configured || ".tailor-sdk";
|
|
718
|
+
return distPath;
|
|
719
|
+
};
|
|
720
|
+
function defineConfig(config) {
|
|
721
|
+
return config;
|
|
722
|
+
}
|
|
723
|
+
function defineGenerators(...configs) {
|
|
724
|
+
return configs;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
//#endregion
|
|
728
|
+
//#region src/configure/services/auth/index.ts
|
|
729
|
+
function defineAuth(name, config) {
|
|
730
|
+
return {
|
|
731
|
+
...config,
|
|
732
|
+
name,
|
|
733
|
+
invoker(machineUser) {
|
|
734
|
+
return {
|
|
735
|
+
authName: name,
|
|
736
|
+
machineUser
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
//#endregion
|
|
743
|
+
export { TailorField, db, defineAuth, defineConfig, defineGenerators, getDistDir, t, tailorUserMap, unauthenticatedTailorUser };
|