@stndrds/schema 0.1.0-alpha.57 → 0.1.0-alpha.59
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/dist/{chunk-DPRLHGPO.js → chunk-DCTLP3ZD.js} +1144 -962
- package/dist/chunk-NEVERCM3.js +41 -0
- package/dist/{chunk-YVUSATKC.mjs → chunk-O7FGYLYG.mjs} +1017 -835
- package/dist/chunk-SV4BCGQU.mjs +617 -0
- package/dist/chunk-U4AB53AM.js +617 -0
- package/dist/chunk-V2RPPE2Y.mjs +41 -0
- package/dist/index.d.mts +223 -30
- package/dist/index.d.ts +223 -30
- package/dist/index.js +39 -93
- package/dist/index.mjs +112 -166
- package/dist/{runtime-BqJdmg_4.d.mts → runtime-BRkoIwsC.d.ts} +274 -1658
- package/dist/{runtime-BqJdmg_4.d.ts → runtime-Chz-bTNq.d.mts} +274 -1658
- package/dist/runtime.d.mts +3 -1
- package/dist/runtime.d.ts +3 -1
- package/dist/runtime.js +6 -2
- package/dist/runtime.mjs +5 -1
- package/dist/utils.d.mts +154 -0
- package/dist/utils.d.ts +154 -0
- package/dist/utils.js +19 -0
- package/dist/utils.mjs +19 -0
- package/dist/validation/validators.d.mts +4 -0
- package/dist/validation/validators.d.ts +4 -0
- package/dist/validation/validators.js +121 -0
- package/dist/validation/validators.mjs +121 -0
- package/dist/validators-BIAmz0CD.d.mts +1631 -0
- package/dist/validators-BPIB7Miq.d.ts +1631 -0
- package/package.json +12 -2
|
@@ -1,40 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asTenantId,
|
|
3
|
+
asUserId,
|
|
4
|
+
generateId
|
|
5
|
+
} from "./chunk-V2RPPE2Y.mjs";
|
|
6
|
+
import {
|
|
7
|
+
computeRecordStatus,
|
|
8
|
+
formatZodErrors,
|
|
9
|
+
parseAttributeConfig,
|
|
10
|
+
validateDraftOrThrow,
|
|
11
|
+
validateObject,
|
|
12
|
+
validateObjectOrThrow
|
|
13
|
+
} from "./chunk-SV4BCGQU.mjs";
|
|
1
14
|
import {
|
|
2
15
|
__require
|
|
3
16
|
} from "./chunk-Y6FXYEAI.mjs";
|
|
4
17
|
|
|
5
18
|
// src/runtime/auth/workflow-jwt.service.ts
|
|
6
19
|
import { SignJWT, importPKCS8, importSPKI, jwtVerify } from "jose";
|
|
7
|
-
|
|
8
|
-
// src/utils.ts
|
|
9
|
-
function asTenantId(id) {
|
|
10
|
-
return id;
|
|
11
|
-
}
|
|
12
|
-
function asUserId(id) {
|
|
13
|
-
return id;
|
|
14
|
-
}
|
|
15
|
-
function generateId() {
|
|
16
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
17
|
-
return crypto.randomUUID();
|
|
18
|
-
}
|
|
19
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
20
|
-
const r = Math.random() * 16 | 0;
|
|
21
|
-
const v = c === "x" ? r : r & 3 | 8;
|
|
22
|
-
return v.toString(16);
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
function generatePrefixedId(prefix) {
|
|
26
|
-
return `${prefix}_${generateId()}`;
|
|
27
|
-
}
|
|
28
|
-
function slugify(input) {
|
|
29
|
-
return input.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase().replace(/[^a-z0-9\s_-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-");
|
|
30
|
-
}
|
|
31
|
-
function generateTemplateName(label) {
|
|
32
|
-
const slug = slugify(label) || "template";
|
|
33
|
-
const suffix = generateId().slice(0, 8);
|
|
34
|
-
return `${slug}-${suffix}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// src/runtime/auth/workflow-jwt.service.ts
|
|
38
20
|
var WorkflowJwtService = class _WorkflowJwtService {
|
|
39
21
|
constructor(config) {
|
|
40
22
|
this.config = config;
|
|
@@ -212,6 +194,26 @@ var WorkflowJwtService = class _WorkflowJwtService {
|
|
|
212
194
|
}
|
|
213
195
|
};
|
|
214
196
|
|
|
197
|
+
// src/lib/object-helpers.ts
|
|
198
|
+
function isEmpty(obj) {
|
|
199
|
+
if (obj === null || obj === void 0) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
if (typeof obj !== "object") {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
return Object.keys(obj).length === 0;
|
|
206
|
+
}
|
|
207
|
+
function isNotEmpty(obj) {
|
|
208
|
+
return obj !== null && obj !== void 0 && typeof obj === "object" && Object.keys(obj).length > 0;
|
|
209
|
+
}
|
|
210
|
+
function toUndefinedIfEmpty(obj) {
|
|
211
|
+
return isNotEmpty(obj) ? obj : void 0;
|
|
212
|
+
}
|
|
213
|
+
function hasProperties(obj) {
|
|
214
|
+
return isNotEmpty(obj);
|
|
215
|
+
}
|
|
216
|
+
|
|
215
217
|
// src/runtime/cache.ts
|
|
216
218
|
function fnv1aHash(str) {
|
|
217
219
|
let hash = 2166136261;
|
|
@@ -222,7 +224,7 @@ function fnv1aHash(str) {
|
|
|
222
224
|
return hash.toString(16).padStart(8, "0");
|
|
223
225
|
}
|
|
224
226
|
function hashOptions(options) {
|
|
225
|
-
if (
|
|
227
|
+
if (isEmpty(options)) {
|
|
226
228
|
return "default";
|
|
227
229
|
}
|
|
228
230
|
const sortedJson = JSON.stringify(options, (_, value) => {
|
|
@@ -1345,12 +1347,6 @@ function or(...rules) {
|
|
|
1345
1347
|
function inValues(field, values) {
|
|
1346
1348
|
return { field, operator: "in", value: values };
|
|
1347
1349
|
}
|
|
1348
|
-
function isEmpty(field) {
|
|
1349
|
-
return { field, operator: "isEmpty", value: null };
|
|
1350
|
-
}
|
|
1351
|
-
function isNotEmpty(field) {
|
|
1352
|
-
return { field, operator: "isNotEmpty", value: null };
|
|
1353
|
-
}
|
|
1354
1350
|
|
|
1355
1351
|
// src/types/workflows/definition.ts
|
|
1356
1352
|
function isWorkflowDefinition(obj) {
|
|
@@ -1460,16 +1456,6 @@ function setContextValue(context, path, value) {
|
|
|
1460
1456
|
}
|
|
1461
1457
|
current[parts[parts.length - 1]] = value;
|
|
1462
1458
|
}
|
|
1463
|
-
function mergeFormToSlot(context, nodeId, slotId) {
|
|
1464
|
-
const formData = context.forms[nodeId];
|
|
1465
|
-
if (!formData) {
|
|
1466
|
-
return;
|
|
1467
|
-
}
|
|
1468
|
-
if (!context.slots[slotId]) {
|
|
1469
|
-
context.slots[slotId] = {};
|
|
1470
|
-
}
|
|
1471
|
-
Object.assign(context.slots[slotId], formData);
|
|
1472
|
-
}
|
|
1473
1459
|
|
|
1474
1460
|
// src/types/workflows/theme.ts
|
|
1475
1461
|
var DEFAULT_THEME = {
|
|
@@ -1823,9 +1809,9 @@ function compareValues(actual, operator, expected) {
|
|
|
1823
1809
|
return typeof actual === "string" && typeof expected === "string" ? actual.endsWith(expected) : false;
|
|
1824
1810
|
// Presence
|
|
1825
1811
|
case "isEmpty":
|
|
1826
|
-
return
|
|
1812
|
+
return isEmptyValue(actual);
|
|
1827
1813
|
case "isNotEmpty":
|
|
1828
|
-
return !
|
|
1814
|
+
return !isEmptyValue(actual);
|
|
1829
1815
|
// Set membership
|
|
1830
1816
|
case "in":
|
|
1831
1817
|
if (Array.isArray(expected)) {
|
|
@@ -1841,7 +1827,7 @@ function compareValues(actual, operator, expected) {
|
|
|
1841
1827
|
return false;
|
|
1842
1828
|
}
|
|
1843
1829
|
}
|
|
1844
|
-
function
|
|
1830
|
+
function isEmptyValue(value) {
|
|
1845
1831
|
if (value === null || value === void 0) {
|
|
1846
1832
|
return true;
|
|
1847
1833
|
}
|
|
@@ -1851,7 +1837,7 @@ function isEmpty2(value) {
|
|
|
1851
1837
|
if (Array.isArray(value) && value.length === 0) {
|
|
1852
1838
|
return true;
|
|
1853
1839
|
}
|
|
1854
|
-
if (typeof value === "object" &&
|
|
1840
|
+
if (typeof value === "object" && isEmpty(value)) {
|
|
1855
1841
|
return true;
|
|
1856
1842
|
}
|
|
1857
1843
|
return false;
|
|
@@ -2096,7 +2082,7 @@ var DocumentExecutor = class {
|
|
|
2096
2082
|
validateSlotReferences(node, workflowSlots) {
|
|
2097
2083
|
const errors = [];
|
|
2098
2084
|
if (node.targetSlotIds && node.targetSlotIds.length > 0) {
|
|
2099
|
-
const slotIdSet =
|
|
2085
|
+
const slotIdSet = workflowSlots.reduce((set, s) => set.add(s.id), /* @__PURE__ */ new Set());
|
|
2100
2086
|
for (const slotId of node.targetSlotIds) {
|
|
2101
2087
|
if (!slotIdSet.has(slotId)) {
|
|
2102
2088
|
errors.push(
|
|
@@ -2132,24 +2118,25 @@ var FormExecutor = class {
|
|
|
2132
2118
|
}
|
|
2133
2119
|
execute(node, context) {
|
|
2134
2120
|
const { input } = context;
|
|
2135
|
-
if (
|
|
2121
|
+
if (isEmpty(input)) {
|
|
2136
2122
|
const requiredParticipationId = node.participantId ?? void 0;
|
|
2137
2123
|
return wait(`Waiting for form submission: ${node.label}`, {
|
|
2138
2124
|
requiredParticipationId
|
|
2139
2125
|
});
|
|
2140
2126
|
}
|
|
2127
|
+
const formInput = input;
|
|
2141
2128
|
const slotIds = this.extractSlotIds(node);
|
|
2142
2129
|
if (slotIds.size === 0) {
|
|
2143
2130
|
return error("MISSING_FIELDS", "FormNode must have fields or rows with slot references");
|
|
2144
2131
|
}
|
|
2145
2132
|
const contextUpdates = {
|
|
2146
2133
|
forms: {
|
|
2147
|
-
[node.id]:
|
|
2134
|
+
[node.id]: formInput
|
|
2148
2135
|
},
|
|
2149
2136
|
slots: {}
|
|
2150
2137
|
};
|
|
2151
2138
|
for (const slotId of slotIds) {
|
|
2152
|
-
const slotInput =
|
|
2139
|
+
const slotInput = formInput[slotId] ?? {};
|
|
2153
2140
|
if (!contextUpdates.slots) {
|
|
2154
2141
|
contextUpdates.slots = {};
|
|
2155
2142
|
}
|
|
@@ -2177,9 +2164,9 @@ var FormExecutor = class {
|
|
|
2177
2164
|
}
|
|
2178
2165
|
canExecute(node, context) {
|
|
2179
2166
|
if (node.participantId && context.executorId) {
|
|
2180
|
-
return
|
|
2167
|
+
return hasProperties(context.input);
|
|
2181
2168
|
}
|
|
2182
|
-
return
|
|
2169
|
+
return hasProperties(context.input);
|
|
2183
2170
|
}
|
|
2184
2171
|
validate(node) {
|
|
2185
2172
|
const errors = [];
|
|
@@ -3471,9 +3458,6 @@ var ConcurrentModificationError = class extends SchemaError {
|
|
|
3471
3458
|
);
|
|
3472
3459
|
}
|
|
3473
3460
|
};
|
|
3474
|
-
function isConcurrentModificationError(error2) {
|
|
3475
|
-
return error2 instanceof ConcurrentModificationError;
|
|
3476
|
-
}
|
|
3477
3461
|
|
|
3478
3462
|
// src/format.ts
|
|
3479
3463
|
import { getCountryByIso3 } from "@stndrds/constants";
|
|
@@ -4075,6 +4059,91 @@ function createMockObjectRecordsRepository(stores) {
|
|
|
4075
4059
|
};
|
|
4076
4060
|
}
|
|
4077
4061
|
|
|
4062
|
+
// src/runtime/mock/mock-relation-attributes.ts
|
|
4063
|
+
import { randomUUID } from "crypto";
|
|
4064
|
+
function createMockRelationAttributesRepository(stores) {
|
|
4065
|
+
return {
|
|
4066
|
+
async upsertBatch(items) {
|
|
4067
|
+
const context = getContext2();
|
|
4068
|
+
if (!context) {
|
|
4069
|
+
throw new Error("Context required for relationAttributes operations");
|
|
4070
|
+
}
|
|
4071
|
+
const results = [];
|
|
4072
|
+
for (const item of items) {
|
|
4073
|
+
const _key = `${context.tenantId}:${item.fromObject}:${item.fromId}:${item.fromAttribute}:${item.toId}`;
|
|
4074
|
+
const existing = Array.from(stores.relationAttributes.values()).find(
|
|
4075
|
+
(row) => row.tenantId === context.tenantId && row.fromObject === item.fromObject && row.fromId === item.fromId && row.fromAttribute === item.fromAttribute && row.toId === item.toId
|
|
4076
|
+
);
|
|
4077
|
+
if (existing) {
|
|
4078
|
+
existing.properties = item.properties ?? {};
|
|
4079
|
+
existing.updatedAt = /* @__PURE__ */ new Date();
|
|
4080
|
+
existing.updatedBy = item.updatedBy ?? context.userId ?? null;
|
|
4081
|
+
results.push(existing);
|
|
4082
|
+
} else {
|
|
4083
|
+
const row = {
|
|
4084
|
+
id: randomUUID(),
|
|
4085
|
+
tenantId: context.tenantId,
|
|
4086
|
+
fromObject: item.fromObject,
|
|
4087
|
+
fromId: item.fromId,
|
|
4088
|
+
fromAttribute: item.fromAttribute,
|
|
4089
|
+
toId: item.toId,
|
|
4090
|
+
properties: item.properties ?? {},
|
|
4091
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
4092
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
4093
|
+
createdBy: item.createdBy ?? context.userId ?? null,
|
|
4094
|
+
updatedBy: item.updatedBy ?? context.userId ?? null
|
|
4095
|
+
};
|
|
4096
|
+
stores.relationAttributes.set(row.id, row);
|
|
4097
|
+
results.push(row);
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
return results;
|
|
4101
|
+
},
|
|
4102
|
+
async findBySource(fromObject, fromId, fromAttribute) {
|
|
4103
|
+
const context = getContext2();
|
|
4104
|
+
if (!context) {
|
|
4105
|
+
throw new Error("Context required for relationAttributes operations");
|
|
4106
|
+
}
|
|
4107
|
+
return Array.from(stores.relationAttributes.values()).filter(
|
|
4108
|
+
(row) => row.tenantId === context.tenantId && row.fromObject === fromObject && row.fromId === fromId && row.fromAttribute === fromAttribute
|
|
4109
|
+
);
|
|
4110
|
+
},
|
|
4111
|
+
async findByTarget(toId) {
|
|
4112
|
+
const context = getContext2();
|
|
4113
|
+
if (!context) {
|
|
4114
|
+
throw new Error("Context required for relationAttributes operations");
|
|
4115
|
+
}
|
|
4116
|
+
return Array.from(stores.relationAttributes.values()).filter(
|
|
4117
|
+
(row) => row.tenantId === context.tenantId && row.toId === toId
|
|
4118
|
+
);
|
|
4119
|
+
},
|
|
4120
|
+
async deleteBySource(fromObject, fromId, fromAttribute) {
|
|
4121
|
+
const context = getContext2();
|
|
4122
|
+
if (!context) {
|
|
4123
|
+
throw new Error("Context required for relationAttributes operations");
|
|
4124
|
+
}
|
|
4125
|
+
const toDelete = Array.from(stores.relationAttributes.entries()).filter(
|
|
4126
|
+
([_id, row]) => row.tenantId === context.tenantId && row.fromObject === fromObject && row.fromId === fromId && row.fromAttribute === fromAttribute
|
|
4127
|
+
);
|
|
4128
|
+
for (const [id] of toDelete) {
|
|
4129
|
+
stores.relationAttributes.delete(id);
|
|
4130
|
+
}
|
|
4131
|
+
},
|
|
4132
|
+
async deleteByTarget(toId) {
|
|
4133
|
+
const context = getContext2();
|
|
4134
|
+
if (!context) {
|
|
4135
|
+
throw new Error("Context required for relationAttributes operations");
|
|
4136
|
+
}
|
|
4137
|
+
const toDelete = Array.from(stores.relationAttributes.entries()).filter(
|
|
4138
|
+
([_id, row]) => row.tenantId === context.tenantId && row.toId === toId
|
|
4139
|
+
);
|
|
4140
|
+
for (const [id] of toDelete) {
|
|
4141
|
+
stores.relationAttributes.delete(id);
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
};
|
|
4145
|
+
}
|
|
4146
|
+
|
|
4078
4147
|
// src/runtime/mock/mock-stores.ts
|
|
4079
4148
|
function createEmptyStores() {
|
|
4080
4149
|
return {
|
|
@@ -4095,7 +4164,8 @@ function createEmptyStores() {
|
|
|
4095
4164
|
aiConversations: /* @__PURE__ */ new Map(),
|
|
4096
4165
|
aiMessages: /* @__PURE__ */ new Map(),
|
|
4097
4166
|
aiUserMemory: /* @__PURE__ */ new Map(),
|
|
4098
|
-
aiUsageMetrics: /* @__PURE__ */ new Map()
|
|
4167
|
+
aiUsageMetrics: /* @__PURE__ */ new Map(),
|
|
4168
|
+
relationAttributes: /* @__PURE__ */ new Map()
|
|
4099
4169
|
};
|
|
4100
4170
|
}
|
|
4101
4171
|
|
|
@@ -4302,7 +4372,8 @@ function createMockPermissionsRepository(stores) {
|
|
|
4302
4372
|
getUserRoles(userProfileId) {
|
|
4303
4373
|
const tenantId = getTenantId();
|
|
4304
4374
|
const roleIds = Array.from(stores.userRoles.values()).filter((ur) => ur.userProfileId === userProfileId && ur.tenantId === tenantId).map((ur) => ur.roleId);
|
|
4305
|
-
const
|
|
4375
|
+
const roleIdsSet = new Set(roleIds);
|
|
4376
|
+
const roles = Array.from(stores.roles.values()).filter((r) => roleIdsSet.has(r.id));
|
|
4306
4377
|
return Promise.resolve(roles);
|
|
4307
4378
|
},
|
|
4308
4379
|
assignRole(input) {
|
|
@@ -4518,7 +4589,7 @@ function createMockViewOverlaysRepository(stores) {
|
|
|
4518
4589
|
const views = Array.from(stores.views.values()).filter(
|
|
4519
4590
|
(v) => v.tenantId === tenantId && v.objectName === objectName && v.type === type
|
|
4520
4591
|
);
|
|
4521
|
-
const viewIds =
|
|
4592
|
+
const viewIds = views.reduce((set, v) => set.add(v.id), /* @__PURE__ */ new Set());
|
|
4522
4593
|
return Promise.resolve(
|
|
4523
4594
|
Array.from(stores.viewOverlays.values()).find(
|
|
4524
4595
|
(o) => o.tenantId === tenantId && o.userId === userId && o.isUserDefault === true && viewIds.has(o.viewId)
|
|
@@ -4603,7 +4674,7 @@ function createMockViewOverlaysRepository(stores) {
|
|
|
4603
4674
|
const views = Array.from(stores.views.values()).filter(
|
|
4604
4675
|
(v) => v.tenantId === tenantId && v.objectName === objectName && v.type === type
|
|
4605
4676
|
);
|
|
4606
|
-
const viewIds =
|
|
4677
|
+
const viewIds = views.reduce((set, v) => set.add(v.id), /* @__PURE__ */ new Set());
|
|
4607
4678
|
for (const overlay of stores.viewOverlays.values()) {
|
|
4608
4679
|
if (overlay.tenantId === tenantId && overlay.userId === userId && overlay.isUserDefault === true && viewIds.has(overlay.viewId)) {
|
|
4609
4680
|
overlay.isUserDefault = false;
|
|
@@ -5009,6 +5080,8 @@ function createMockAdapter() {
|
|
|
5009
5080
|
aiConversations: createMockAIConversationsRepository(stores),
|
|
5010
5081
|
aiUserMemory: createMockAIUserMemoryRepository(stores),
|
|
5011
5082
|
aiUsageMetrics: createMockAIUsageMetricsRepository(stores),
|
|
5083
|
+
// Relation attributes repository
|
|
5084
|
+
relationAttributes: createMockRelationAttributesRepository(stores),
|
|
5012
5085
|
async transaction(callback) {
|
|
5013
5086
|
return await callback(adapter);
|
|
5014
5087
|
},
|
|
@@ -5034,6 +5107,7 @@ function createMockAdapter() {
|
|
|
5034
5107
|
stores.aiMessages.clear();
|
|
5035
5108
|
stores.aiUserMemory.clear();
|
|
5036
5109
|
stores.aiUsageMetrics.clear();
|
|
5110
|
+
stores.relationAttributes.clear();
|
|
5037
5111
|
}
|
|
5038
5112
|
};
|
|
5039
5113
|
return adapter;
|
|
@@ -5512,6 +5586,292 @@ function validateOptions(options, attributeName) {
|
|
|
5512
5586
|
}
|
|
5513
5587
|
}
|
|
5514
5588
|
|
|
5589
|
+
// src/types/relation-properties.ts
|
|
5590
|
+
var FORBIDDEN_PROPERTY_TYPES = [
|
|
5591
|
+
"formula",
|
|
5592
|
+
"rollup",
|
|
5593
|
+
"relation",
|
|
5594
|
+
"file",
|
|
5595
|
+
"user",
|
|
5596
|
+
"document",
|
|
5597
|
+
"richtext"
|
|
5598
|
+
];
|
|
5599
|
+
|
|
5600
|
+
// src/builders/property-schema-builder.ts
|
|
5601
|
+
var PropertySchemaBuilder = class {
|
|
5602
|
+
constructor() {
|
|
5603
|
+
this.definitions = [];
|
|
5604
|
+
}
|
|
5605
|
+
/**
|
|
5606
|
+
* Add a property to the schema
|
|
5607
|
+
* The type of property is automatically detected based on the builder methods used
|
|
5608
|
+
*/
|
|
5609
|
+
add(name, configure) {
|
|
5610
|
+
const builder = new PropertyTypeBuilder(name);
|
|
5611
|
+
const configured = configure(builder);
|
|
5612
|
+
const definition = configured.build();
|
|
5613
|
+
this.definitions.push(definition);
|
|
5614
|
+
return this;
|
|
5615
|
+
}
|
|
5616
|
+
/**
|
|
5617
|
+
* Build the final PropertySchema
|
|
5618
|
+
*/
|
|
5619
|
+
build() {
|
|
5620
|
+
return {
|
|
5621
|
+
definitions: this.definitions
|
|
5622
|
+
};
|
|
5623
|
+
}
|
|
5624
|
+
};
|
|
5625
|
+
var PropertyTypeBuilder = class {
|
|
5626
|
+
constructor(name) {
|
|
5627
|
+
this.name = name;
|
|
5628
|
+
}
|
|
5629
|
+
// Explicit type constructors
|
|
5630
|
+
text() {
|
|
5631
|
+
return new TextPropertyBuilder(this.name);
|
|
5632
|
+
}
|
|
5633
|
+
textarea() {
|
|
5634
|
+
return new TextareaPropertyBuilder(this.name);
|
|
5635
|
+
}
|
|
5636
|
+
number() {
|
|
5637
|
+
return new NumberPropertyBuilder(this.name);
|
|
5638
|
+
}
|
|
5639
|
+
checkbox() {
|
|
5640
|
+
return new CheckboxPropertyBuilder(this.name);
|
|
5641
|
+
}
|
|
5642
|
+
date() {
|
|
5643
|
+
return new DatePropertyBuilder(this.name);
|
|
5644
|
+
}
|
|
5645
|
+
phone() {
|
|
5646
|
+
return new PhonePropertyBuilder(this.name);
|
|
5647
|
+
}
|
|
5648
|
+
currency() {
|
|
5649
|
+
return new CurrencyPropertyBuilder(this.name);
|
|
5650
|
+
}
|
|
5651
|
+
status() {
|
|
5652
|
+
return new StatusPropertyBuilder(this.name);
|
|
5653
|
+
}
|
|
5654
|
+
select() {
|
|
5655
|
+
return new SelectPropertyBuilder(this.name);
|
|
5656
|
+
}
|
|
5657
|
+
multiselect() {
|
|
5658
|
+
return new MultiselectPropertyBuilder(this.name);
|
|
5659
|
+
}
|
|
5660
|
+
rating() {
|
|
5661
|
+
return new RatingPropertyBuilder(this.name);
|
|
5662
|
+
}
|
|
5663
|
+
location() {
|
|
5664
|
+
return new LocationPropertyBuilder(this.name);
|
|
5665
|
+
}
|
|
5666
|
+
};
|
|
5667
|
+
var BasePropertyBuilder = class {
|
|
5668
|
+
constructor(name) {
|
|
5669
|
+
this.definition = { name };
|
|
5670
|
+
}
|
|
5671
|
+
/**
|
|
5672
|
+
* Set the label
|
|
5673
|
+
*/
|
|
5674
|
+
label(label) {
|
|
5675
|
+
this.definition.label = label;
|
|
5676
|
+
return this;
|
|
5677
|
+
}
|
|
5678
|
+
/**
|
|
5679
|
+
* Mark as required
|
|
5680
|
+
*/
|
|
5681
|
+
required() {
|
|
5682
|
+
this.definition.required = true;
|
|
5683
|
+
return this;
|
|
5684
|
+
}
|
|
5685
|
+
/**
|
|
5686
|
+
* Set description
|
|
5687
|
+
*/
|
|
5688
|
+
description(description) {
|
|
5689
|
+
this.definition.description = description;
|
|
5690
|
+
return this;
|
|
5691
|
+
}
|
|
5692
|
+
/**
|
|
5693
|
+
* Build the final definition
|
|
5694
|
+
*/
|
|
5695
|
+
build() {
|
|
5696
|
+
return this.definition;
|
|
5697
|
+
}
|
|
5698
|
+
};
|
|
5699
|
+
var TextPropertyBuilder = class extends BasePropertyBuilder {
|
|
5700
|
+
constructor(name) {
|
|
5701
|
+
super(name);
|
|
5702
|
+
this.definition.type = "text";
|
|
5703
|
+
}
|
|
5704
|
+
minLength(value) {
|
|
5705
|
+
this.definition.minLength = value;
|
|
5706
|
+
return this;
|
|
5707
|
+
}
|
|
5708
|
+
maxLength(value) {
|
|
5709
|
+
this.definition.maxLength = value;
|
|
5710
|
+
return this;
|
|
5711
|
+
}
|
|
5712
|
+
pattern(pattern) {
|
|
5713
|
+
this.definition.pattern = pattern;
|
|
5714
|
+
return this;
|
|
5715
|
+
}
|
|
5716
|
+
placeholder(value) {
|
|
5717
|
+
this.definition.placeholder = value;
|
|
5718
|
+
return this;
|
|
5719
|
+
}
|
|
5720
|
+
};
|
|
5721
|
+
var TextareaPropertyBuilder = class extends BasePropertyBuilder {
|
|
5722
|
+
constructor(name) {
|
|
5723
|
+
super(name);
|
|
5724
|
+
this.definition.type = "textarea";
|
|
5725
|
+
}
|
|
5726
|
+
minLength(value) {
|
|
5727
|
+
this.definition.minLength = value;
|
|
5728
|
+
return this;
|
|
5729
|
+
}
|
|
5730
|
+
maxLength(value) {
|
|
5731
|
+
this.definition.maxLength = value;
|
|
5732
|
+
return this;
|
|
5733
|
+
}
|
|
5734
|
+
placeholder(value) {
|
|
5735
|
+
this.definition.placeholder = value;
|
|
5736
|
+
return this;
|
|
5737
|
+
}
|
|
5738
|
+
};
|
|
5739
|
+
var NumberPropertyBuilder = class extends BasePropertyBuilder {
|
|
5740
|
+
constructor(name) {
|
|
5741
|
+
super(name);
|
|
5742
|
+
this.definition.type = "number";
|
|
5743
|
+
}
|
|
5744
|
+
min(value) {
|
|
5745
|
+
this.definition.min = value;
|
|
5746
|
+
return this;
|
|
5747
|
+
}
|
|
5748
|
+
max(value) {
|
|
5749
|
+
this.definition.max = value;
|
|
5750
|
+
return this;
|
|
5751
|
+
}
|
|
5752
|
+
decimal(places) {
|
|
5753
|
+
this.definition.decimal = places;
|
|
5754
|
+
return this;
|
|
5755
|
+
}
|
|
5756
|
+
integer() {
|
|
5757
|
+
this.definition.integer = true;
|
|
5758
|
+
return this;
|
|
5759
|
+
}
|
|
5760
|
+
placeholder(value) {
|
|
5761
|
+
this.definition.placeholder = value;
|
|
5762
|
+
return this;
|
|
5763
|
+
}
|
|
5764
|
+
};
|
|
5765
|
+
var CheckboxPropertyBuilder = class extends BasePropertyBuilder {
|
|
5766
|
+
constructor(name) {
|
|
5767
|
+
super(name);
|
|
5768
|
+
this.definition.type = "checkbox";
|
|
5769
|
+
}
|
|
5770
|
+
};
|
|
5771
|
+
var DatePropertyBuilder = class extends BasePropertyBuilder {
|
|
5772
|
+
constructor(name) {
|
|
5773
|
+
super(name);
|
|
5774
|
+
this.definition.type = "date";
|
|
5775
|
+
}
|
|
5776
|
+
includeTime() {
|
|
5777
|
+
this.definition.includeTime = true;
|
|
5778
|
+
return this;
|
|
5779
|
+
}
|
|
5780
|
+
min(date2) {
|
|
5781
|
+
this.definition.min = date2;
|
|
5782
|
+
return this;
|
|
5783
|
+
}
|
|
5784
|
+
max(date2) {
|
|
5785
|
+
this.definition.max = date2;
|
|
5786
|
+
return this;
|
|
5787
|
+
}
|
|
5788
|
+
};
|
|
5789
|
+
var PhonePropertyBuilder = class extends BasePropertyBuilder {
|
|
5790
|
+
constructor(name) {
|
|
5791
|
+
super(name);
|
|
5792
|
+
this.definition.type = "phone";
|
|
5793
|
+
}
|
|
5794
|
+
};
|
|
5795
|
+
var CurrencyPropertyBuilder = class extends BasePropertyBuilder {
|
|
5796
|
+
constructor(name) {
|
|
5797
|
+
super(name);
|
|
5798
|
+
this.definition.type = "currency";
|
|
5799
|
+
}
|
|
5800
|
+
currency(code) {
|
|
5801
|
+
this.definition.currency = code;
|
|
5802
|
+
return this;
|
|
5803
|
+
}
|
|
5804
|
+
min(value) {
|
|
5805
|
+
this.definition.min = value;
|
|
5806
|
+
return this;
|
|
5807
|
+
}
|
|
5808
|
+
max(value) {
|
|
5809
|
+
this.definition.max = value;
|
|
5810
|
+
return this;
|
|
5811
|
+
}
|
|
5812
|
+
};
|
|
5813
|
+
var StatusPropertyBuilder = class extends BasePropertyBuilder {
|
|
5814
|
+
constructor(name) {
|
|
5815
|
+
super(name);
|
|
5816
|
+
this.definition.type = "status";
|
|
5817
|
+
}
|
|
5818
|
+
options(options) {
|
|
5819
|
+
this.definition.options = options;
|
|
5820
|
+
return this;
|
|
5821
|
+
}
|
|
5822
|
+
};
|
|
5823
|
+
var SelectPropertyBuilder = class extends BasePropertyBuilder {
|
|
5824
|
+
constructor(name) {
|
|
5825
|
+
super(name);
|
|
5826
|
+
this.definition.type = "select";
|
|
5827
|
+
}
|
|
5828
|
+
options(options) {
|
|
5829
|
+
this.definition.options = options;
|
|
5830
|
+
return this;
|
|
5831
|
+
}
|
|
5832
|
+
};
|
|
5833
|
+
var MultiselectPropertyBuilder = class extends BasePropertyBuilder {
|
|
5834
|
+
constructor(name) {
|
|
5835
|
+
super(name);
|
|
5836
|
+
this.definition.type = "multiselect";
|
|
5837
|
+
}
|
|
5838
|
+
options(options) {
|
|
5839
|
+
this.definition.options = options;
|
|
5840
|
+
return this;
|
|
5841
|
+
}
|
|
5842
|
+
maxSelections(value) {
|
|
5843
|
+
this.definition.maxSelections = value;
|
|
5844
|
+
return this;
|
|
5845
|
+
}
|
|
5846
|
+
};
|
|
5847
|
+
var RatingPropertyBuilder = class extends BasePropertyBuilder {
|
|
5848
|
+
constructor(name) {
|
|
5849
|
+
super(name);
|
|
5850
|
+
this.definition.type = "rating";
|
|
5851
|
+
}
|
|
5852
|
+
max(value) {
|
|
5853
|
+
this.definition.max = value;
|
|
5854
|
+
return this;
|
|
5855
|
+
}
|
|
5856
|
+
icon(icon) {
|
|
5857
|
+
this.definition.icon = icon;
|
|
5858
|
+
return this;
|
|
5859
|
+
}
|
|
5860
|
+
};
|
|
5861
|
+
var LocationPropertyBuilder = class extends BasePropertyBuilder {
|
|
5862
|
+
constructor(name) {
|
|
5863
|
+
super(name);
|
|
5864
|
+
this.definition.type = "location";
|
|
5865
|
+
}
|
|
5866
|
+
};
|
|
5867
|
+
function validatePropertyType(type) {
|
|
5868
|
+
if (FORBIDDEN_PROPERTY_TYPES.includes(type)) {
|
|
5869
|
+
throw new Error(
|
|
5870
|
+
`Property type "${type}" is not supported in .qualifyWith(). Only simple types (text, number, date, select, etc.) are allowed. Complex types (formula, rollup, relation, file, user, document) would require duplicating backend behavior.`
|
|
5871
|
+
);
|
|
5872
|
+
}
|
|
5873
|
+
}
|
|
5874
|
+
|
|
5515
5875
|
// src/builders/attribute-builders.ts
|
|
5516
5876
|
var BaseAttributeBuilder = class {
|
|
5517
5877
|
constructor(type, name, label) {
|
|
@@ -6068,6 +6428,32 @@ var SingleRelationAttributeBuilder = class extends BaseAttributeBuilder {
|
|
|
6068
6428
|
);
|
|
6069
6429
|
return multiBuilder;
|
|
6070
6430
|
}
|
|
6431
|
+
/**
|
|
6432
|
+
* Add properties to qualify the relation
|
|
6433
|
+
* Must be called AFTER .to() to ensure targets are defined
|
|
6434
|
+
*
|
|
6435
|
+
* @example
|
|
6436
|
+
* ```typescript
|
|
6437
|
+
* relation({ name: "mainCompany", label: "Main Company" })
|
|
6438
|
+
* .to("companies")
|
|
6439
|
+
* .qualifyWith(props => props
|
|
6440
|
+
* .add("role", select => select.options([...]).required())
|
|
6441
|
+
* .add("shares", number => number.min(0))
|
|
6442
|
+
* )
|
|
6443
|
+
* ```
|
|
6444
|
+
*/
|
|
6445
|
+
qualifyWith(configure) {
|
|
6446
|
+
const targets = this.attr.targets;
|
|
6447
|
+
if (!targets || targets.length === 0) {
|
|
6448
|
+
throw new Error(
|
|
6449
|
+
'.qualifyWith() must be called AFTER .to(). Example: relation({ name: "mainCompany" }).to("companies").qualifyWith(...)'
|
|
6450
|
+
);
|
|
6451
|
+
}
|
|
6452
|
+
const builder = new PropertySchemaBuilder();
|
|
6453
|
+
const schema = configure(builder).build();
|
|
6454
|
+
this.attr.properties = schema;
|
|
6455
|
+
return this;
|
|
6456
|
+
}
|
|
6071
6457
|
required() {
|
|
6072
6458
|
this.setRequired(true);
|
|
6073
6459
|
return this;
|
|
@@ -6129,6 +6515,33 @@ var MultiRelationAttributeBuilder = class extends BaseAttributeBuilder {
|
|
|
6129
6515
|
this.attr.maxItems = count;
|
|
6130
6516
|
return this;
|
|
6131
6517
|
}
|
|
6518
|
+
/**
|
|
6519
|
+
* Add properties to qualify the relation
|
|
6520
|
+
* Must be called AFTER .to() or .many() to ensure targets are defined
|
|
6521
|
+
*
|
|
6522
|
+
* @example
|
|
6523
|
+
* ```typescript
|
|
6524
|
+
* relation({ name: "companies", label: "Companies" })
|
|
6525
|
+
* .to("companies")
|
|
6526
|
+
* .many()
|
|
6527
|
+
* .qualifyWith(props => props
|
|
6528
|
+
* .add("role", select => select.options([...]).required())
|
|
6529
|
+
* .add("shares", number => number.min(0))
|
|
6530
|
+
* )
|
|
6531
|
+
* ```
|
|
6532
|
+
*/
|
|
6533
|
+
qualifyWith(configure) {
|
|
6534
|
+
const targets = this.attr.targets;
|
|
6535
|
+
if (!targets || targets.length === 0) {
|
|
6536
|
+
throw new Error(
|
|
6537
|
+
'.qualifyWith() must be called AFTER .to() or .many(). Example: relation({ name: "companies" }).to("companies").many().qualifyWith(...)'
|
|
6538
|
+
);
|
|
6539
|
+
}
|
|
6540
|
+
const builder = new PropertySchemaBuilder();
|
|
6541
|
+
const schema = configure(builder).build();
|
|
6542
|
+
this.attr.properties = schema;
|
|
6543
|
+
return this;
|
|
6544
|
+
}
|
|
6132
6545
|
required() {
|
|
6133
6546
|
this.setRequired(true);
|
|
6134
6547
|
return this;
|
|
@@ -6514,7 +6927,7 @@ function object(config) {
|
|
|
6514
6927
|
}
|
|
6515
6928
|
|
|
6516
6929
|
// src/builders/view-builder.ts
|
|
6517
|
-
import { randomUUID } from "crypto";
|
|
6930
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
6518
6931
|
import { z as z3 } from "zod";
|
|
6519
6932
|
var GroupBuilder = class {
|
|
6520
6933
|
constructor(id, label) {
|
|
@@ -7374,7 +7787,7 @@ var ListViewBuilder = class {
|
|
|
7374
7787
|
columns: this.data.columns,
|
|
7375
7788
|
columnSizing: this.data.columnSizing,
|
|
7376
7789
|
defaultFilters: this.data.defaultFilters ? {
|
|
7377
|
-
id:
|
|
7790
|
+
id: randomUUID2(),
|
|
7378
7791
|
combinator: this.data.defaultFilters.combinator,
|
|
7379
7792
|
rules: this.data.defaultFilters.rules
|
|
7380
7793
|
} : void 0,
|
|
@@ -7385,7 +7798,7 @@ var ListViewBuilder = class {
|
|
|
7385
7798
|
label: tab.label,
|
|
7386
7799
|
icon: tab.icon,
|
|
7387
7800
|
filters: tab.filters ? {
|
|
7388
|
-
id:
|
|
7801
|
+
id: randomUUID2(),
|
|
7389
7802
|
combinator: tab.filters.combinator,
|
|
7390
7803
|
rules: tab.filters.rules
|
|
7391
7804
|
} : void 0,
|
|
@@ -7899,13 +8312,13 @@ var WorkflowBuilder = class {
|
|
|
7899
8312
|
if (!this.startNodeId) {
|
|
7900
8313
|
throw new Error("[WorkflowBuilder] A start node is required. Use .start() to add one.");
|
|
7901
8314
|
}
|
|
7902
|
-
if (
|
|
8315
|
+
if (isEmpty(this.data.nodes)) {
|
|
7903
8316
|
throw new Error("[WorkflowBuilder] At least one node is required.");
|
|
7904
8317
|
}
|
|
7905
8318
|
if (!this.data.slots || this.data.slots.length === 0) {
|
|
7906
8319
|
throw new Error("[WorkflowBuilder] At least one slot is required. Use .slot() to add slots.");
|
|
7907
8320
|
}
|
|
7908
|
-
const hasEndNode = Object.values(this.data.nodes).some((n) => n.type === "end");
|
|
8321
|
+
const hasEndNode = this.data.nodes ? Object.values(this.data.nodes).some((n) => n.type === "end") : false;
|
|
7909
8322
|
if (!hasEndNode) {
|
|
7910
8323
|
throw new Error(
|
|
7911
8324
|
"[WorkflowBuilder] At least one end node is required. Use .end() to add one."
|
|
@@ -7936,7 +8349,7 @@ var WorkflowBuilder = class {
|
|
|
7936
8349
|
}
|
|
7937
8350
|
}
|
|
7938
8351
|
validateSlotReferences() {
|
|
7939
|
-
const slotIds =
|
|
8352
|
+
const slotIds = this.data.slots?.reduce((set, s) => set.add(s.id), /* @__PURE__ */ new Set()) ?? /* @__PURE__ */ new Set();
|
|
7940
8353
|
for (const node of Object.values(this.data.nodes ?? {})) {
|
|
7941
8354
|
if (node.type === "form") {
|
|
7942
8355
|
const referencedSlots = /* @__PURE__ */ new Set();
|
|
@@ -8041,22 +8454,6 @@ function isBehaviorProperty(property) {
|
|
|
8041
8454
|
function isPresentationProperty(property) {
|
|
8042
8455
|
return PRESENTATION_PROPERTIES.includes(property);
|
|
8043
8456
|
}
|
|
8044
|
-
function getPropertyProtectionLevel(property) {
|
|
8045
|
-
if (isIdentityProperty(property)) return "identity";
|
|
8046
|
-
if (isBehaviorProperty(property)) return "behavior";
|
|
8047
|
-
if (isPresentationProperty(property)) return "presentation";
|
|
8048
|
-
return "unknown";
|
|
8049
|
-
}
|
|
8050
|
-
function filterPropertiesByCategory(properties, category) {
|
|
8051
|
-
switch (category) {
|
|
8052
|
-
case "identity":
|
|
8053
|
-
return properties.filter(isIdentityProperty);
|
|
8054
|
-
case "behavior":
|
|
8055
|
-
return properties.filter(isBehaviorProperty);
|
|
8056
|
-
case "presentation":
|
|
8057
|
-
return properties.filter(isPresentationProperty);
|
|
8058
|
-
}
|
|
8059
|
-
}
|
|
8060
8457
|
|
|
8061
8458
|
// src/types/errors.ts
|
|
8062
8459
|
var RecordReferencedError = class extends Error {
|
|
@@ -8075,656 +8472,99 @@ var AttributeInUseError = class extends Error {
|
|
|
8075
8472
|
this.attributeName = attributeName;
|
|
8076
8473
|
this.usage = usage;
|
|
8077
8474
|
this.code = "ATTRIBUTE_IN_USE";
|
|
8078
|
-
this.name = "AttributeInUseError";
|
|
8079
|
-
}
|
|
8080
|
-
};
|
|
8081
|
-
var ObjectReferencedError = class extends Error {
|
|
8082
|
-
constructor(objectName, referencingObjects) {
|
|
8083
|
-
super(
|
|
8084
|
-
`Cannot delete object "${objectName}": target of relations in ${referencingObjects.join(", ")}`
|
|
8085
|
-
);
|
|
8086
|
-
this.objectName = objectName;
|
|
8087
|
-
this.referencingObjects = referencingObjects;
|
|
8088
|
-
this.code = "OBJECT_REFERENCED";
|
|
8089
|
-
this.name = "ObjectReferencedError";
|
|
8090
|
-
}
|
|
8091
|
-
};
|
|
8092
|
-
|
|
8093
|
-
// src/types/system-attributes.ts
|
|
8094
|
-
var SYSTEM_ATTRIBUTES = {
|
|
8095
|
-
createdAt: {
|
|
8096
|
-
id: "system:createdAt",
|
|
8097
|
-
name: "createdAt",
|
|
8098
|
-
label: "Created time",
|
|
8099
|
-
type: "date",
|
|
8100
|
-
required: false,
|
|
8101
|
-
disabled: true,
|
|
8102
|
-
system: true,
|
|
8103
|
-
icon: "clock-circle",
|
|
8104
|
-
description: "When this record was created"
|
|
8105
|
-
},
|
|
8106
|
-
updatedAt: {
|
|
8107
|
-
id: "system:updatedAt",
|
|
8108
|
-
name: "updatedAt",
|
|
8109
|
-
label: "Last edited time",
|
|
8110
|
-
type: "date",
|
|
8111
|
-
required: false,
|
|
8112
|
-
disabled: true,
|
|
8113
|
-
system: true,
|
|
8114
|
-
icon: "clock-circle",
|
|
8115
|
-
description: "When this record was last modified"
|
|
8116
|
-
},
|
|
8117
|
-
createdBy: {
|
|
8118
|
-
id: "system:createdBy",
|
|
8119
|
-
name: "createdBy",
|
|
8120
|
-
label: "Created by",
|
|
8121
|
-
type: "user",
|
|
8122
|
-
required: false,
|
|
8123
|
-
disabled: true,
|
|
8124
|
-
system: true,
|
|
8125
|
-
multiple: false,
|
|
8126
|
-
icon: "user",
|
|
8127
|
-
description: "User who created this record"
|
|
8128
|
-
},
|
|
8129
|
-
lastUpdatedBy: {
|
|
8130
|
-
id: "system:lastUpdatedBy",
|
|
8131
|
-
name: "lastUpdatedBy",
|
|
8132
|
-
label: "Last edited by",
|
|
8133
|
-
type: "user",
|
|
8134
|
-
required: false,
|
|
8135
|
-
disabled: true,
|
|
8136
|
-
system: true,
|
|
8137
|
-
multiple: false,
|
|
8138
|
-
icon: "user",
|
|
8139
|
-
description: "User who last modified this record"
|
|
8140
|
-
},
|
|
8141
|
-
/**
|
|
8142
|
-
* System attribute for free-form document attachments.
|
|
8143
|
-
* Hidden from forms, visible in Documents tab.
|
|
8144
|
-
* Users can attach any document without template constraints.
|
|
8145
|
-
*/
|
|
8146
|
-
attachments: {
|
|
8147
|
-
id: "system:attachments",
|
|
8148
|
-
name: "attachments",
|
|
8149
|
-
label: "Pi\xE8ces jointes",
|
|
8150
|
-
type: "document",
|
|
8151
|
-
required: false,
|
|
8152
|
-
disabled: false,
|
|
8153
|
-
// Editable via Documents tab
|
|
8154
|
-
system: true,
|
|
8155
|
-
hidden: true,
|
|
8156
|
-
// Hidden from regular form views
|
|
8157
|
-
multiple: true,
|
|
8158
|
-
icon: "paperclip",
|
|
8159
|
-
description: "Free-form document attachments"
|
|
8160
|
-
// No templateId = all templates allowed
|
|
8161
|
-
}
|
|
8162
|
-
};
|
|
8163
|
-
function getSystemAttributeList() {
|
|
8164
|
-
return Object.values(SYSTEM_ATTRIBUTES);
|
|
8165
|
-
}
|
|
8166
|
-
function isSystemAttribute(name) {
|
|
8167
|
-
return name in SYSTEM_ATTRIBUTES;
|
|
8168
|
-
}
|
|
8169
|
-
function isSystemAttributeObject(attr) {
|
|
8170
|
-
return attr.system === true;
|
|
8171
|
-
}
|
|
8172
|
-
|
|
8173
|
-
// src/validation/validators.ts
|
|
8174
|
-
import { z as z5 } from "zod";
|
|
8175
|
-
var regexPatternCache = /* @__PURE__ */ new Map();
|
|
8176
|
-
function getCachedRegex(pattern) {
|
|
8177
|
-
let cached = regexPatternCache.get(pattern);
|
|
8178
|
-
if (!cached) {
|
|
8179
|
-
cached = new RegExp(pattern);
|
|
8180
|
-
regexPatternCache.set(pattern, cached);
|
|
8181
|
-
}
|
|
8182
|
-
return cached;
|
|
8183
|
-
}
|
|
8184
|
-
var DEFAULT_VALIDATION_MESSAGES = {
|
|
8185
|
-
required: (attr) => `${attr.label} is required`,
|
|
8186
|
-
invalidType: (attr, expected) => `${attr.label} must be a ${expected}`,
|
|
8187
|
-
minLength: (attr, min) => `${attr.label} must be at least ${min} characters`,
|
|
8188
|
-
maxLength: (attr, max) => `${attr.label} must be at most ${max} characters`,
|
|
8189
|
-
invalidPattern: (attr) => `${attr.label} format is invalid`,
|
|
8190
|
-
minValue: (attr, min) => `${attr.label} must be at least ${min}`,
|
|
8191
|
-
maxValue: (attr, max) => `${attr.label} must be at most ${max}`,
|
|
8192
|
-
mustBeInteger: (attr) => `${attr.label} must be an integer`,
|
|
8193
|
-
invalidDate: (attr) => `${attr.label} must be a valid date`,
|
|
8194
|
-
invalidOption: (attr, options) => `${attr.label} must be one of: ${options.join(", ")}`,
|
|
8195
|
-
invalidId: (attr) => `${attr.label} must be a valid ID`,
|
|
8196
|
-
minItems: (attr, min) => `${attr.label} must have at least ${min} item${min > 1 ? "s" : ""}`,
|
|
8197
|
-
maxItems: (attr, max) => `${attr.label} must have at most ${max} item${max > 1 ? "s" : ""}`,
|
|
8198
|
-
invalidRichtext: (attr) => `${attr.label} must be valid rich text content`,
|
|
8199
|
-
invalidPhone: (attr) => `${attr.label} must be a valid phone number`,
|
|
8200
|
-
invalidCurrency: (attr) => `${attr.label} must be a valid currency value`,
|
|
8201
|
-
invalidLocation: (attr) => `${attr.label} must be a valid location`
|
|
8202
|
-
};
|
|
8203
|
-
var baseConfigSchema = z5.object({
|
|
8204
|
-
disabled: z5.boolean().optional(),
|
|
8205
|
-
placeholder: z5.string().optional(),
|
|
8206
|
-
description: z5.string().optional(),
|
|
8207
|
-
defaultValue: z5.unknown().optional(),
|
|
8208
|
-
icon: z5.string().optional(),
|
|
8209
|
-
order: z5.number().int().optional(),
|
|
8210
|
-
hidden: z5.boolean().optional(),
|
|
8211
|
-
archived: z5.boolean().optional(),
|
|
8212
|
-
deprecated: z5.boolean().optional(),
|
|
8213
|
-
metadata: z5.record(z5.string(), z5.unknown()).optional()
|
|
8214
|
-
});
|
|
8215
|
-
var optionSchema = z5.object({
|
|
8216
|
-
id: z5.string().min(1),
|
|
8217
|
-
label: z5.string().min(1),
|
|
8218
|
-
value: z5.string().min(1),
|
|
8219
|
-
color: z5.string().optional(),
|
|
8220
|
-
icon: z5.string().optional(),
|
|
8221
|
-
description: z5.string().optional(),
|
|
8222
|
-
group: z5.enum(["idle", "in_progress", "finished"]).optional()
|
|
8223
|
-
});
|
|
8224
|
-
var optionsArraySchema = z5.array(optionSchema).min(1).refine(
|
|
8225
|
-
(options) => {
|
|
8226
|
-
const values = options.map((o) => o.value);
|
|
8227
|
-
return new Set(values).size === values.length;
|
|
8228
|
-
},
|
|
8229
|
-
{ message: "Duplicate option values are not allowed" }
|
|
8230
|
-
);
|
|
8231
|
-
var relationTargetSchema = z5.object({
|
|
8232
|
-
object: z5.string().min(1),
|
|
8233
|
-
displayTemplate: z5.string().optional(),
|
|
8234
|
-
filter: z5.record(z5.string(), z5.unknown()).optional()
|
|
8235
|
-
});
|
|
8236
|
-
var textConfigSchema = baseConfigSchema.extend({
|
|
8237
|
-
minLength: z5.number().int().min(0).optional(),
|
|
8238
|
-
maxLength: z5.number().int().min(1).optional(),
|
|
8239
|
-
pattern: z5.string().optional()
|
|
8240
|
-
});
|
|
8241
|
-
var textareaConfigSchema = baseConfigSchema;
|
|
8242
|
-
var richtextConfigSchema = baseConfigSchema.extend({
|
|
8243
|
-
features: z5.array(
|
|
8244
|
-
z5.enum(["headings", "bold", "italic", "lists", "links", "images", "codeBlocks", "tables"])
|
|
8245
|
-
).optional()
|
|
8246
|
-
});
|
|
8247
|
-
var numberConfigSchema = baseConfigSchema.extend({
|
|
8248
|
-
min: z5.number().optional(),
|
|
8249
|
-
max: z5.number().optional(),
|
|
8250
|
-
unit: z5.enum(["integer", "decimal", "percentage"]).optional(),
|
|
8251
|
-
decimals: z5.number().int().min(0).optional()
|
|
8252
|
-
});
|
|
8253
|
-
var checkboxConfigSchema = baseConfigSchema;
|
|
8254
|
-
var dateConfigSchema = baseConfigSchema.extend({
|
|
8255
|
-
dateFormat: z5.enum(["short", "long", "full", "relative"]).optional(),
|
|
8256
|
-
minDate: z5.string().optional(),
|
|
8257
|
-
maxDate: z5.string().optional()
|
|
8258
|
-
});
|
|
8259
|
-
var phoneConfigSchema = baseConfigSchema.extend({
|
|
8260
|
-
defaultCountryCode: z5.string().length(3).optional()
|
|
8261
|
-
});
|
|
8262
|
-
var currencyConfigSchema = baseConfigSchema.extend({
|
|
8263
|
-
defaultCurrency: z5.string().length(3).optional(),
|
|
8264
|
-
allowedCurrencies: z5.array(z5.string().length(3)).optional()
|
|
8265
|
-
});
|
|
8266
|
-
var statusConfigSchema = baseConfigSchema.extend({
|
|
8267
|
-
options: optionsArraySchema
|
|
8268
|
-
});
|
|
8269
|
-
var locationConfigSchema = baseConfigSchema.extend({
|
|
8270
|
-
granularity: z5.enum(["full", "address", "city", "state", "country", "coordinates"]),
|
|
8271
|
-
enableAutocomplete: z5.boolean().optional(),
|
|
8272
|
-
enableMap: z5.boolean().optional(),
|
|
8273
|
-
defaultCountry: z5.string().length(3).optional(),
|
|
8274
|
-
allowedCountries: z5.array(z5.string().length(3)).optional(),
|
|
8275
|
-
displayFormat: z5.enum(["single_line", "multi_line", "compact"]).optional()
|
|
8276
|
-
});
|
|
8277
|
-
var selectConfigSchema = baseConfigSchema.extend({
|
|
8278
|
-
options: optionsArraySchema
|
|
8279
|
-
});
|
|
8280
|
-
var multiselectConfigSchema = baseConfigSchema.extend({
|
|
8281
|
-
options: optionsArraySchema
|
|
8282
|
-
});
|
|
8283
|
-
var fileConfigSchema = baseConfigSchema.extend({
|
|
8284
|
-
maxFiles: z5.number().int().min(1).optional(),
|
|
8285
|
-
maxSize: z5.number().int().min(1).optional(),
|
|
8286
|
-
allowedTypes: z5.array(z5.string()).optional(),
|
|
8287
|
-
multiple: z5.boolean().optional()
|
|
8288
|
-
});
|
|
8289
|
-
var userConfigSchema = baseConfigSchema.extend({
|
|
8290
|
-
allowedRoles: z5.array(z5.string()).optional(),
|
|
8291
|
-
multiple: z5.boolean().optional()
|
|
8292
|
-
});
|
|
8293
|
-
var relationConfigSchema = baseConfigSchema.extend({
|
|
8294
|
-
targets: z5.array(relationTargetSchema).min(1),
|
|
8295
|
-
cardinality: z5.enum(["one", "many"]),
|
|
8296
|
-
minItems: z5.number().int().min(0).optional(),
|
|
8297
|
-
maxItems: z5.number().int().min(1).optional()
|
|
8298
|
-
});
|
|
8299
|
-
var ratingConfigSchema = baseConfigSchema.extend({
|
|
8300
|
-
max: z5.number().int().min(1).optional(),
|
|
8301
|
-
iconType: z5.enum(["star", "heart", "thumbs", "number"]).optional()
|
|
8302
|
-
});
|
|
8303
|
-
var formulaConfigSchema = baseConfigSchema.extend({
|
|
8304
|
-
expression: z5.string().min(1),
|
|
8305
|
-
returnType: z5.enum(["text", "number", "boolean", "date"]),
|
|
8306
|
-
decimals: z5.number().int().min(0).max(10).optional(),
|
|
8307
|
-
allowRelations: z5.boolean().optional()
|
|
8308
|
-
});
|
|
8309
|
-
var rollupConfigSchema = baseConfigSchema.extend({
|
|
8310
|
-
relationAttribute: z5.string().min(1).optional(),
|
|
8311
|
-
relationPath: z5.string().optional(),
|
|
8312
|
-
targetAttribute: z5.string().min(1),
|
|
8313
|
-
function: z5.enum([
|
|
8314
|
-
// Numeric aggregates
|
|
8315
|
-
"sum",
|
|
8316
|
-
"avg",
|
|
8317
|
-
// Date aggregates
|
|
8318
|
-
"earliest",
|
|
8319
|
-
"latest",
|
|
8320
|
-
// Count (universal)
|
|
8321
|
-
"count",
|
|
8322
|
-
"countValues",
|
|
8323
|
-
"countUniqueValues",
|
|
8324
|
-
"countEmpty",
|
|
8325
|
-
// Percent (universal)
|
|
8326
|
-
"percentEmpty",
|
|
8327
|
-
"percentNotEmpty",
|
|
8328
|
-
// Lookup (universal)
|
|
8329
|
-
"original"
|
|
8330
|
-
]),
|
|
8331
|
-
decimals: z5.number().int().min(0).max(10).optional(),
|
|
8332
|
-
targetAttributeType: z5.string().optional(),
|
|
8333
|
-
targetAttributeOptions: z5.array(
|
|
8334
|
-
z5.object({
|
|
8335
|
-
id: z5.string(),
|
|
8336
|
-
label: z5.string(),
|
|
8337
|
-
value: z5.string(),
|
|
8338
|
-
color: z5.string().optional(),
|
|
8339
|
-
icon: z5.string().optional(),
|
|
8340
|
-
description: z5.string().optional(),
|
|
8341
|
-
group: z5.enum(["idle", "in_progress", "finished"]).optional()
|
|
8342
|
-
})
|
|
8343
|
-
).optional()
|
|
8344
|
-
});
|
|
8345
|
-
var documentConfigSchema = baseConfigSchema.extend({
|
|
8346
|
-
templateId: z5.string().optional(),
|
|
8347
|
-
allowedTemplates: z5.array(z5.string()).optional(),
|
|
8348
|
-
multiple: z5.boolean().optional(),
|
|
8349
|
-
maxDocuments: z5.number().int().min(1).optional(),
|
|
8350
|
-
autoProcess: z5.boolean().optional()
|
|
8351
|
-
});
|
|
8352
|
-
var attributeConfigSchemas = {
|
|
8353
|
-
text: textConfigSchema,
|
|
8354
|
-
textarea: textareaConfigSchema,
|
|
8355
|
-
richtext: richtextConfigSchema,
|
|
8356
|
-
number: numberConfigSchema,
|
|
8357
|
-
checkbox: checkboxConfigSchema,
|
|
8358
|
-
date: dateConfigSchema,
|
|
8359
|
-
phone: phoneConfigSchema,
|
|
8360
|
-
currency: currencyConfigSchema,
|
|
8361
|
-
status: statusConfigSchema,
|
|
8362
|
-
location: locationConfigSchema,
|
|
8363
|
-
select: selectConfigSchema,
|
|
8364
|
-
multiselect: multiselectConfigSchema,
|
|
8365
|
-
file: fileConfigSchema,
|
|
8366
|
-
user: userConfigSchema,
|
|
8367
|
-
relation: relationConfigSchema,
|
|
8368
|
-
rating: ratingConfigSchema,
|
|
8369
|
-
formula: formulaConfigSchema,
|
|
8370
|
-
rollup: rollupConfigSchema,
|
|
8371
|
-
document: documentConfigSchema
|
|
8372
|
-
};
|
|
8373
|
-
function getAttributeConfigSchema(type) {
|
|
8374
|
-
return attributeConfigSchemas[type];
|
|
8375
|
-
}
|
|
8376
|
-
function validateAttributeConfig(type, config) {
|
|
8377
|
-
const schema = getAttributeConfigSchema(type);
|
|
8378
|
-
const result = schema.safeParse(config);
|
|
8379
|
-
if (result.success) {
|
|
8380
|
-
return { success: true, data: result.data };
|
|
8381
|
-
}
|
|
8382
|
-
return {
|
|
8383
|
-
success: false,
|
|
8384
|
-
errors: result.error.issues.map((err) => `${err.path.join(".")}: ${err.message}`)
|
|
8385
|
-
};
|
|
8386
|
-
}
|
|
8387
|
-
function parseAttributeConfig(type, config) {
|
|
8388
|
-
const schema = getAttributeConfigSchema(type);
|
|
8389
|
-
return schema.strip().parse(config);
|
|
8390
|
-
}
|
|
8391
|
-
function safeParseAttributeConfig(type, config) {
|
|
8392
|
-
const schema = getAttributeConfigSchema(type);
|
|
8393
|
-
const result = schema.strip().safeParse(config);
|
|
8394
|
-
return result.success ? result.data : void 0;
|
|
8395
|
-
}
|
|
8396
|
-
function createTextValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8397
|
-
let schema = z5.string();
|
|
8398
|
-
if (attr.minLength !== void 0) {
|
|
8399
|
-
schema = schema.min(attr.minLength, messages.minLength(attr, attr.minLength));
|
|
8400
|
-
}
|
|
8401
|
-
if (attr.maxLength !== void 0) {
|
|
8402
|
-
schema = schema.max(attr.maxLength, messages.maxLength(attr, attr.maxLength));
|
|
8403
|
-
}
|
|
8404
|
-
if (attr.pattern) {
|
|
8405
|
-
schema = schema.regex(getCachedRegex(attr.pattern), messages.invalidPattern(attr));
|
|
8406
|
-
}
|
|
8407
|
-
return schema;
|
|
8408
|
-
}
|
|
8409
|
-
function createNumberValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8410
|
-
let schema = z5.number();
|
|
8411
|
-
if (attr.min !== void 0) {
|
|
8412
|
-
schema = schema.min(attr.min, messages.minValue(attr, attr.min));
|
|
8413
|
-
}
|
|
8414
|
-
if (attr.max !== void 0) {
|
|
8415
|
-
schema = schema.max(attr.max, messages.maxValue(attr, attr.max));
|
|
8416
|
-
}
|
|
8417
|
-
if (attr.unit === "integer") {
|
|
8418
|
-
schema = schema.int(messages.mustBeInteger(attr));
|
|
8419
|
-
}
|
|
8420
|
-
return schema;
|
|
8421
|
-
}
|
|
8422
|
-
function createCheckboxValidator(_attr, _messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8423
|
-
return z5.boolean();
|
|
8424
|
-
}
|
|
8425
|
-
function createDateValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8426
|
-
return z5.coerce.date({ message: messages.invalidDate(attr) });
|
|
8427
|
-
}
|
|
8428
|
-
function createPhoneValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8429
|
-
return z5.object(
|
|
8430
|
-
{
|
|
8431
|
-
countryCode: z5.string().length(3),
|
|
8432
|
-
phoneNumber: z5.string().min(1)
|
|
8433
|
-
},
|
|
8434
|
-
{ message: messages.invalidPhone(attr) }
|
|
8435
|
-
);
|
|
8436
|
-
}
|
|
8437
|
-
function createCurrencyValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8438
|
-
return z5.object(
|
|
8439
|
-
{
|
|
8440
|
-
code: z5.string().length(3),
|
|
8441
|
-
value: z5.number().min(0)
|
|
8442
|
-
},
|
|
8443
|
-
{ message: messages.invalidCurrency(attr) }
|
|
8444
|
-
);
|
|
8445
|
-
}
|
|
8446
|
-
function createStatusValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8447
|
-
const validValues = attr.options.map((opt) => opt.value);
|
|
8448
|
-
return z5.enum(validValues, {
|
|
8449
|
-
message: messages.invalidOption(attr, validValues)
|
|
8450
|
-
});
|
|
8451
|
-
}
|
|
8452
|
-
function createSelectValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8453
|
-
const validValues = attr.options.map((opt) => opt.value);
|
|
8454
|
-
return z5.enum(validValues, {
|
|
8455
|
-
message: messages.invalidOption(attr, validValues)
|
|
8456
|
-
});
|
|
8457
|
-
}
|
|
8458
|
-
function createMultiselectValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8459
|
-
const validValues = attr.options.map((opt) => opt.value);
|
|
8460
|
-
return z5.array(
|
|
8461
|
-
z5.enum(validValues, {
|
|
8462
|
-
message: messages.invalidOption(attr, validValues)
|
|
8463
|
-
})
|
|
8464
|
-
);
|
|
8465
|
-
}
|
|
8466
|
-
function createLocationValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8467
|
-
return z5.object(
|
|
8468
|
-
{
|
|
8469
|
-
address: z5.string().optional(),
|
|
8470
|
-
address2: z5.string().optional(),
|
|
8471
|
-
city: z5.string().optional(),
|
|
8472
|
-
state: z5.string().optional(),
|
|
8473
|
-
postalCode: z5.string().optional(),
|
|
8474
|
-
country: z5.string().length(3).optional(),
|
|
8475
|
-
latitude: z5.number().optional(),
|
|
8476
|
-
longitude: z5.number().optional()
|
|
8477
|
-
},
|
|
8478
|
-
{ message: messages.invalidLocation(attr) }
|
|
8479
|
-
);
|
|
8480
|
-
}
|
|
8481
|
-
function createFileValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8482
|
-
const uuidSchema = z5.uuid({
|
|
8483
|
-
message: messages.invalidId(attr)
|
|
8484
|
-
});
|
|
8485
|
-
if (attr.multiple) {
|
|
8486
|
-
let arraySchema = z5.array(uuidSchema);
|
|
8487
|
-
if (attr.maxFiles) {
|
|
8488
|
-
arraySchema = arraySchema.max(attr.maxFiles, messages.maxItems(attr, attr.maxFiles));
|
|
8489
|
-
}
|
|
8490
|
-
return arraySchema;
|
|
8491
|
-
}
|
|
8492
|
-
return uuidSchema;
|
|
8493
|
-
}
|
|
8494
|
-
function createUserValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8495
|
-
const uuidSchema = z5.uuid({
|
|
8496
|
-
message: messages.invalidId(attr)
|
|
8497
|
-
});
|
|
8498
|
-
if (attr.multiple) {
|
|
8499
|
-
return z5.array(uuidSchema);
|
|
8500
|
-
}
|
|
8501
|
-
return uuidSchema;
|
|
8502
|
-
}
|
|
8503
|
-
function createSingleRelationValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8504
|
-
const uuidSchema = z5.uuid({
|
|
8505
|
-
message: messages.invalidId(attr)
|
|
8506
|
-
});
|
|
8507
|
-
return z5.union([uuidSchema, z5.null()]);
|
|
8508
|
-
}
|
|
8509
|
-
function createMultiRelationValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8510
|
-
const uuidSchema = z5.uuid({
|
|
8511
|
-
message: messages.invalidId(attr)
|
|
8512
|
-
});
|
|
8513
|
-
let arraySchema = z5.array(uuidSchema);
|
|
8514
|
-
if (attr.minItems !== void 0) {
|
|
8515
|
-
arraySchema = arraySchema.min(attr.minItems, messages.minItems(attr, attr.minItems));
|
|
8516
|
-
}
|
|
8517
|
-
if (attr.maxItems !== void 0) {
|
|
8518
|
-
arraySchema = arraySchema.max(attr.maxItems, messages.maxItems(attr, attr.maxItems));
|
|
8519
|
-
}
|
|
8520
|
-
return arraySchema;
|
|
8521
|
-
}
|
|
8522
|
-
function createRelationValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8523
|
-
if (attr.cardinality === "many") {
|
|
8524
|
-
return createMultiRelationValidator(attr, messages);
|
|
8525
|
-
}
|
|
8526
|
-
return createSingleRelationValidator(attr, messages);
|
|
8527
|
-
}
|
|
8528
|
-
function createRatingValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8529
|
-
let schema = z5.number().min(0);
|
|
8530
|
-
if (attr.max !== void 0) {
|
|
8531
|
-
schema = schema.max(attr.max, messages.maxValue(attr, attr.max));
|
|
8532
|
-
}
|
|
8533
|
-
return schema;
|
|
8534
|
-
}
|
|
8535
|
-
function createFormulaValidator(_attr, _messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8536
|
-
return z5.unknown();
|
|
8537
|
-
}
|
|
8538
|
-
function createRollupValidator(_attr, _messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8539
|
-
return z5.unknown();
|
|
8540
|
-
}
|
|
8541
|
-
function createTextAreaValidator(_attr, _messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8542
|
-
return z5.string();
|
|
8543
|
-
}
|
|
8544
|
-
function createRichtextValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8545
|
-
return z5.string({
|
|
8546
|
-
message: messages.invalidRichtext(attr)
|
|
8547
|
-
});
|
|
8548
|
-
}
|
|
8549
|
-
function createAttributeValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8550
|
-
switch (attr.type) {
|
|
8551
|
-
case "text":
|
|
8552
|
-
return createTextValidator(attr, messages);
|
|
8553
|
-
case "textarea":
|
|
8554
|
-
return createTextAreaValidator(attr, messages);
|
|
8555
|
-
case "richtext":
|
|
8556
|
-
return createRichtextValidator(attr, messages);
|
|
8557
|
-
case "number":
|
|
8558
|
-
return createNumberValidator(attr, messages);
|
|
8559
|
-
case "checkbox":
|
|
8560
|
-
return createCheckboxValidator(attr, messages);
|
|
8561
|
-
case "date":
|
|
8562
|
-
return createDateValidator(attr, messages);
|
|
8563
|
-
case "phone":
|
|
8564
|
-
return createPhoneValidator(attr, messages);
|
|
8565
|
-
case "currency":
|
|
8566
|
-
return createCurrencyValidator(attr, messages);
|
|
8567
|
-
case "status":
|
|
8568
|
-
return createStatusValidator(attr, messages);
|
|
8569
|
-
case "location":
|
|
8570
|
-
return createLocationValidator(attr, messages);
|
|
8571
|
-
case "select":
|
|
8572
|
-
return createSelectValidator(attr, messages);
|
|
8573
|
-
case "multiselect":
|
|
8574
|
-
return createMultiselectValidator(attr, messages);
|
|
8575
|
-
case "file":
|
|
8576
|
-
return createFileValidator(attr, messages);
|
|
8577
|
-
case "user":
|
|
8578
|
-
return createUserValidator(attr, messages);
|
|
8579
|
-
case "relation":
|
|
8580
|
-
return createRelationValidator(attr, messages);
|
|
8581
|
-
case "rating":
|
|
8582
|
-
return createRatingValidator(attr, messages);
|
|
8583
|
-
case "formula":
|
|
8584
|
-
return createFormulaValidator(attr, messages);
|
|
8585
|
-
case "rollup":
|
|
8586
|
-
return createRollupValidator(attr, messages);
|
|
8587
|
-
default:
|
|
8588
|
-
return z5.unknown();
|
|
8589
|
-
}
|
|
8590
|
-
}
|
|
8591
|
-
function isEmptyValue(value) {
|
|
8592
|
-
if (value === null || value === void 0) return true;
|
|
8593
|
-
if (typeof value === "string" && value.trim() === "") return true;
|
|
8594
|
-
if (value instanceof Date) return false;
|
|
8595
|
-
if (typeof value === "object" && !Array.isArray(value)) {
|
|
8596
|
-
return Object.values(value).every(
|
|
8597
|
-
(v) => v === null || v === void 0 || typeof v === "string" && v.trim() === ""
|
|
8598
|
-
);
|
|
8599
|
-
}
|
|
8600
|
-
return false;
|
|
8601
|
-
}
|
|
8602
|
-
function withEmptyToNull(validator) {
|
|
8603
|
-
return z5.preprocess((val) => isEmptyValue(val) ? null : val, validator.nullish());
|
|
8604
|
-
}
|
|
8605
|
-
function createFormAttributeValidator(attr, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
8606
|
-
const validator = createAttributeValidator(attr, messages);
|
|
8607
|
-
if (!attr.required) {
|
|
8608
|
-
return withEmptyToNull(validator);
|
|
8609
|
-
}
|
|
8610
|
-
return validator;
|
|
8611
|
-
}
|
|
8612
|
-
function createObjectValidator(objectDef) {
|
|
8613
|
-
const shape = {};
|
|
8614
|
-
for (const attr of objectDef.attributes) {
|
|
8615
|
-
const validator = createAttributeValidator(attr);
|
|
8616
|
-
shape[attr.name] = attr.required ? validator : withEmptyToNull(validator);
|
|
8617
|
-
}
|
|
8618
|
-
return z5.object(shape).passthrough();
|
|
8619
|
-
}
|
|
8620
|
-
function validateAttribute(attr, value) {
|
|
8621
|
-
const validator = createAttributeValidator(attr);
|
|
8622
|
-
if (!attr.required && (value === void 0 || value === null)) {
|
|
8623
|
-
return { success: true, data: { [attr.name]: value } };
|
|
8624
|
-
}
|
|
8625
|
-
const result = validator.safeParse(value);
|
|
8626
|
-
if (result.success) {
|
|
8627
|
-
return {
|
|
8628
|
-
success: true,
|
|
8629
|
-
data: { [attr.name]: result.data }
|
|
8630
|
-
};
|
|
8631
|
-
}
|
|
8632
|
-
return {
|
|
8633
|
-
success: false,
|
|
8634
|
-
errors: result.error.issues.map((err) => ({
|
|
8635
|
-
path: [attr.name, ...err.path.map(String)],
|
|
8636
|
-
message: err.message
|
|
8637
|
-
}))
|
|
8638
|
-
};
|
|
8639
|
-
}
|
|
8640
|
-
function validateObject(objectDef, data) {
|
|
8641
|
-
const validator = createObjectValidator(objectDef);
|
|
8642
|
-
const result = validator.safeParse(data);
|
|
8643
|
-
if (result.success) {
|
|
8644
|
-
return {
|
|
8645
|
-
success: true,
|
|
8646
|
-
data: result.data
|
|
8647
|
-
};
|
|
8648
|
-
}
|
|
8649
|
-
return {
|
|
8650
|
-
success: false,
|
|
8651
|
-
errors: result.error.issues.map((err) => ({
|
|
8652
|
-
path: err.path.map(String),
|
|
8653
|
-
message: err.message
|
|
8654
|
-
}))
|
|
8655
|
-
};
|
|
8656
|
-
}
|
|
8657
|
-
function validateObjectOrThrow(objectDef, data) {
|
|
8658
|
-
const result = validateObject(objectDef, data);
|
|
8659
|
-
if (!result.success) {
|
|
8660
|
-
const errorMessages = result.errors?.map((err) => `${err.path.join(".")}: ${err.message}`).join("\n") || "Unknown validation error";
|
|
8661
|
-
throw new Error(`Validation failed for ${objectDef.label}:
|
|
8662
|
-
${errorMessages}`);
|
|
8663
|
-
}
|
|
8664
|
-
return result.data;
|
|
8665
|
-
}
|
|
8666
|
-
function createDraftValidator(objectDef) {
|
|
8667
|
-
const shape = {};
|
|
8668
|
-
for (const attr of objectDef.attributes) {
|
|
8669
|
-
const validator = createAttributeValidator(attr);
|
|
8670
|
-
shape[attr.name] = withEmptyToNull(validator);
|
|
8671
|
-
}
|
|
8672
|
-
return z5.object(shape).passthrough();
|
|
8673
|
-
}
|
|
8674
|
-
function validateDraft(objectDef, data) {
|
|
8675
|
-
const validator = createDraftValidator(objectDef);
|
|
8676
|
-
const result = validator.safeParse(data);
|
|
8677
|
-
if (result.success) {
|
|
8678
|
-
return {
|
|
8679
|
-
success: true,
|
|
8680
|
-
data: result.data
|
|
8681
|
-
};
|
|
8682
|
-
}
|
|
8683
|
-
return {
|
|
8684
|
-
success: false,
|
|
8685
|
-
errors: result.error.issues.map((err) => ({
|
|
8686
|
-
path: err.path.map(String),
|
|
8687
|
-
message: err.message
|
|
8688
|
-
}))
|
|
8689
|
-
};
|
|
8690
|
-
}
|
|
8691
|
-
function validateDraftOrThrow(objectDef, data) {
|
|
8692
|
-
const result = validateDraft(objectDef, data);
|
|
8693
|
-
if (!result.success) {
|
|
8694
|
-
const errorMessages = result.errors?.map((err) => `${err.path.join(".")}: ${err.message}`).join("\n") || "Unknown validation error";
|
|
8695
|
-
throw new Error(`Draft validation failed for ${objectDef.label}:
|
|
8696
|
-
${errorMessages}`);
|
|
8697
|
-
}
|
|
8698
|
-
return result.data;
|
|
8699
|
-
}
|
|
8700
|
-
function isValuePresent(value) {
|
|
8701
|
-
if (value === void 0 || value === null) {
|
|
8702
|
-
return false;
|
|
8475
|
+
this.name = "AttributeInUseError";
|
|
8703
8476
|
}
|
|
8704
|
-
|
|
8705
|
-
|
|
8477
|
+
};
|
|
8478
|
+
var ObjectReferencedError = class extends Error {
|
|
8479
|
+
constructor(objectName, referencingObjects) {
|
|
8480
|
+
super(
|
|
8481
|
+
`Cannot delete object "${objectName}": target of relations in ${referencingObjects.join(", ")}`
|
|
8482
|
+
);
|
|
8483
|
+
this.objectName = objectName;
|
|
8484
|
+
this.referencingObjects = referencingObjects;
|
|
8485
|
+
this.code = "OBJECT_REFERENCED";
|
|
8486
|
+
this.name = "ObjectReferencedError";
|
|
8706
8487
|
}
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8488
|
+
};
|
|
8489
|
+
|
|
8490
|
+
// src/types/system-attributes.ts
|
|
8491
|
+
var SYSTEM_ATTRIBUTES = {
|
|
8492
|
+
createdAt: {
|
|
8493
|
+
id: "system:createdAt",
|
|
8494
|
+
name: "createdAt",
|
|
8495
|
+
label: "Created time",
|
|
8496
|
+
type: "date",
|
|
8497
|
+
required: false,
|
|
8498
|
+
disabled: true,
|
|
8499
|
+
system: true,
|
|
8500
|
+
icon: "clock-circle",
|
|
8501
|
+
description: "When this record was created"
|
|
8502
|
+
},
|
|
8503
|
+
updatedAt: {
|
|
8504
|
+
id: "system:updatedAt",
|
|
8505
|
+
name: "updatedAt",
|
|
8506
|
+
label: "Last edited time",
|
|
8507
|
+
type: "date",
|
|
8508
|
+
required: false,
|
|
8509
|
+
disabled: true,
|
|
8510
|
+
system: true,
|
|
8511
|
+
icon: "clock-circle",
|
|
8512
|
+
description: "When this record was last modified"
|
|
8513
|
+
},
|
|
8514
|
+
createdBy: {
|
|
8515
|
+
id: "system:createdBy",
|
|
8516
|
+
name: "createdBy",
|
|
8517
|
+
label: "Created by",
|
|
8518
|
+
type: "user",
|
|
8519
|
+
required: false,
|
|
8520
|
+
disabled: true,
|
|
8521
|
+
system: true,
|
|
8522
|
+
multiple: false,
|
|
8523
|
+
icon: "user",
|
|
8524
|
+
description: "User who created this record"
|
|
8525
|
+
},
|
|
8526
|
+
lastUpdatedBy: {
|
|
8527
|
+
id: "system:lastUpdatedBy",
|
|
8528
|
+
name: "lastUpdatedBy",
|
|
8529
|
+
label: "Last edited by",
|
|
8530
|
+
type: "user",
|
|
8531
|
+
required: false,
|
|
8532
|
+
disabled: true,
|
|
8533
|
+
system: true,
|
|
8534
|
+
multiple: false,
|
|
8535
|
+
icon: "user",
|
|
8536
|
+
description: "User who last modified this record"
|
|
8537
|
+
},
|
|
8538
|
+
/**
|
|
8539
|
+
* System attribute for free-form document attachments.
|
|
8540
|
+
* Hidden from forms, visible in Documents tab.
|
|
8541
|
+
* Users can attach any document without template constraints.
|
|
8542
|
+
*/
|
|
8543
|
+
attachments: {
|
|
8544
|
+
id: "system:attachments",
|
|
8545
|
+
name: "attachments",
|
|
8546
|
+
label: "Pi\xE8ces jointes",
|
|
8547
|
+
type: "document",
|
|
8548
|
+
required: false,
|
|
8549
|
+
disabled: false,
|
|
8550
|
+
// Editable via Documents tab
|
|
8551
|
+
system: true,
|
|
8552
|
+
hidden: true,
|
|
8553
|
+
// Hidden from regular form views
|
|
8554
|
+
multiple: true,
|
|
8555
|
+
icon: "paperclip",
|
|
8556
|
+
description: "Free-form document attachments"
|
|
8557
|
+
// No templateId = all templates allowed
|
|
8715
8558
|
}
|
|
8716
|
-
|
|
8559
|
+
};
|
|
8560
|
+
function getSystemAttributeList() {
|
|
8561
|
+
return Object.values(SYSTEM_ATTRIBUTES);
|
|
8717
8562
|
}
|
|
8718
|
-
function
|
|
8719
|
-
|
|
8720
|
-
if (missing.length > 0) {
|
|
8721
|
-
return false;
|
|
8722
|
-
}
|
|
8723
|
-
const validation = validateObject(objectDef, data);
|
|
8724
|
-
return validation.success;
|
|
8563
|
+
function isSystemAttribute(name) {
|
|
8564
|
+
return name in SYSTEM_ATTRIBUTES;
|
|
8725
8565
|
}
|
|
8726
|
-
function
|
|
8727
|
-
return
|
|
8566
|
+
function isSystemAttributeObject(attr) {
|
|
8567
|
+
return attr.system === true;
|
|
8728
8568
|
}
|
|
8729
8569
|
|
|
8730
8570
|
// src/runtime/services/audit/helpers.ts
|
|
@@ -10238,7 +10078,7 @@ async function preloadSchemas(records, schemaService) {
|
|
|
10238
10078
|
if (records.length === 0) {
|
|
10239
10079
|
return schemasByObjectId;
|
|
10240
10080
|
}
|
|
10241
|
-
const uniqueObjectIds = [...
|
|
10081
|
+
const uniqueObjectIds = [...records.reduce((set, r) => set.add(r.objectId), /* @__PURE__ */ new Set())];
|
|
10242
10082
|
await Promise.all(
|
|
10243
10083
|
uniqueObjectIds.map(async (objId) => {
|
|
10244
10084
|
const schema = await schemaService.getObjectSchema(objId);
|
|
@@ -10387,6 +10227,13 @@ var RecordQueryService = class extends BaseService {
|
|
|
10387
10227
|
effectiveTotal = exhausted ? collected.length : Math.max(collected.length, result.total);
|
|
10388
10228
|
filteredRecords = collected.slice(requestedOffset, requestedOffset + requestedLimit);
|
|
10389
10229
|
}
|
|
10230
|
+
if (options?.include && options.include.length > 0) {
|
|
10231
|
+
filteredRecords = await this.includeRelationsWithProperties(
|
|
10232
|
+
filteredRecords,
|
|
10233
|
+
schema,
|
|
10234
|
+
options.include
|
|
10235
|
+
);
|
|
10236
|
+
}
|
|
10390
10237
|
if (!options?.skipFormulas) {
|
|
10391
10238
|
return {
|
|
10392
10239
|
records: enrichRecordsWithFormulas(filteredRecords, schema),
|
|
@@ -10462,6 +10309,79 @@ var RecordQueryService = class extends BaseService {
|
|
|
10462
10309
|
}
|
|
10463
10310
|
return result;
|
|
10464
10311
|
}
|
|
10312
|
+
// ============================================================================
|
|
10313
|
+
// INCLUDE RELATIONS WITH PROPERTIES
|
|
10314
|
+
// ============================================================================
|
|
10315
|
+
/**
|
|
10316
|
+
* Include relation properties in records.
|
|
10317
|
+
*
|
|
10318
|
+
* For each requested relation attribute:
|
|
10319
|
+
* - If attribute has properties → Fetch from relation_attributes and return hybrid format
|
|
10320
|
+
* - If attribute has NO properties → Return legacy format (string[] or string)
|
|
10321
|
+
*
|
|
10322
|
+
* Uses batch loading to avoid N+1 queries.
|
|
10323
|
+
*
|
|
10324
|
+
* @param records - Records to enrich with relation properties
|
|
10325
|
+
* @param schema - Object schema
|
|
10326
|
+
* @param includes - Array of relation attribute names to include
|
|
10327
|
+
* @returns Records enriched with relation properties in hybrid format
|
|
10328
|
+
* @private
|
|
10329
|
+
*/
|
|
10330
|
+
async includeRelationsWithProperties(records, schema, includes) {
|
|
10331
|
+
if (records.length === 0 || includes.length === 0) {
|
|
10332
|
+
return records;
|
|
10333
|
+
}
|
|
10334
|
+
for (const includeName of includes) {
|
|
10335
|
+
const attr = schema.attributes.find((a) => a.name === includeName);
|
|
10336
|
+
if (!attr || attr.type !== "relation") {
|
|
10337
|
+
continue;
|
|
10338
|
+
}
|
|
10339
|
+
if (attr.properties && this.adapter.relationAttributes) {
|
|
10340
|
+
const recordIds = records.map((r) => r.id);
|
|
10341
|
+
const relationAttributesRepo = this.adapter.relationAttributes;
|
|
10342
|
+
const allRelationProps = await Promise.all(
|
|
10343
|
+
recordIds.map(
|
|
10344
|
+
(recordId) => relationAttributesRepo.findBySource(schema.name, recordId, includeName)
|
|
10345
|
+
)
|
|
10346
|
+
);
|
|
10347
|
+
const propsByRecord = /* @__PURE__ */ new Map();
|
|
10348
|
+
allRelationProps.forEach((props, index) => {
|
|
10349
|
+
const recordId = recordIds[index];
|
|
10350
|
+
const propsMap = /* @__PURE__ */ new Map();
|
|
10351
|
+
for (const prop of props) {
|
|
10352
|
+
propsMap.set(prop.toId, prop.properties);
|
|
10353
|
+
}
|
|
10354
|
+
propsByRecord.set(recordId, propsMap);
|
|
10355
|
+
});
|
|
10356
|
+
for (const record of records) {
|
|
10357
|
+
const currentValue = record.values[includeName];
|
|
10358
|
+
const propsMap = propsByRecord.get(record.id);
|
|
10359
|
+
if (!currentValue) {
|
|
10360
|
+
continue;
|
|
10361
|
+
}
|
|
10362
|
+
if (!propsMap) {
|
|
10363
|
+
continue;
|
|
10364
|
+
}
|
|
10365
|
+
if (attr.cardinality === "many" && Array.isArray(currentValue)) {
|
|
10366
|
+
record.values[includeName] = currentValue.map((id) => {
|
|
10367
|
+
if (typeof id === "string") {
|
|
10368
|
+
const props = propsMap.get(id);
|
|
10369
|
+
return props ? { id, props } : { id };
|
|
10370
|
+
}
|
|
10371
|
+
return id;
|
|
10372
|
+
});
|
|
10373
|
+
} else if (attr.cardinality === "one") {
|
|
10374
|
+
const id = typeof currentValue === "string" ? currentValue : null;
|
|
10375
|
+
if (id) {
|
|
10376
|
+
const props = propsMap.get(id);
|
|
10377
|
+
record.values[includeName] = props ? { id, props } : { id };
|
|
10378
|
+
}
|
|
10379
|
+
}
|
|
10380
|
+
}
|
|
10381
|
+
}
|
|
10382
|
+
}
|
|
10383
|
+
return records;
|
|
10384
|
+
}
|
|
10465
10385
|
};
|
|
10466
10386
|
|
|
10467
10387
|
// src/runtime/services/record/record-resolver.service.ts
|
|
@@ -10556,6 +10476,280 @@ var RecordResolverService = class extends BaseService {
|
|
|
10556
10476
|
}
|
|
10557
10477
|
};
|
|
10558
10478
|
|
|
10479
|
+
// src/runtime/services/record/relation-properties.service.ts
|
|
10480
|
+
import { z as z5 } from "zod";
|
|
10481
|
+
var RelationPropertiesService = class extends BaseService {
|
|
10482
|
+
constructor(adapter) {
|
|
10483
|
+
super(adapter);
|
|
10484
|
+
}
|
|
10485
|
+
// ============================================================================
|
|
10486
|
+
// PUBLIC API
|
|
10487
|
+
// ============================================================================
|
|
10488
|
+
/**
|
|
10489
|
+
* Normalize relation values for storage in object_records table.
|
|
10490
|
+
*
|
|
10491
|
+
* Extracts IDs from hybrid format ({ id, props }) and returns legacy format (string[] or string).
|
|
10492
|
+
* This ensures object_records.values only contains IDs, while properties are in relation_attributes.
|
|
10493
|
+
*
|
|
10494
|
+
* @param schema - Object schema
|
|
10495
|
+
* @param data - Record data with hybrid relation values
|
|
10496
|
+
* @returns Data with relation values normalized to ID-only format
|
|
10497
|
+
*/
|
|
10498
|
+
normalizeRelationValuesForStorage(schema, data) {
|
|
10499
|
+
const normalized = { ...data };
|
|
10500
|
+
for (const attr of schema.attributes) {
|
|
10501
|
+
if (attr.type !== "relation" || !attr.properties) {
|
|
10502
|
+
continue;
|
|
10503
|
+
}
|
|
10504
|
+
const value = data[attr.name];
|
|
10505
|
+
if (value === null || value === void 0) {
|
|
10506
|
+
continue;
|
|
10507
|
+
}
|
|
10508
|
+
if (attr.cardinality === "many" && Array.isArray(value)) {
|
|
10509
|
+
normalized[attr.name] = value.map((item) => {
|
|
10510
|
+
if (typeof item === "string") return item;
|
|
10511
|
+
if (typeof item === "object" && item !== null && "id" in item) {
|
|
10512
|
+
return item.id;
|
|
10513
|
+
}
|
|
10514
|
+
return item;
|
|
10515
|
+
});
|
|
10516
|
+
} else if (typeof value === "object" && value !== null && "id" in value) {
|
|
10517
|
+
normalized[attr.name] = value.id;
|
|
10518
|
+
}
|
|
10519
|
+
}
|
|
10520
|
+
return normalized;
|
|
10521
|
+
}
|
|
10522
|
+
/**
|
|
10523
|
+
* Synchronize relation properties for a given attribute.
|
|
10524
|
+
*
|
|
10525
|
+
* Handles:
|
|
10526
|
+
* - Format normalization (legacy → new)
|
|
10527
|
+
* - Validation of properties
|
|
10528
|
+
* - Upsert for present IDs
|
|
10529
|
+
* - Delete for absent IDs
|
|
10530
|
+
*
|
|
10531
|
+
* @param schema - Object schema
|
|
10532
|
+
* @param recordId - Source record ID
|
|
10533
|
+
* @param attributeName - Relation attribute name
|
|
10534
|
+
* @param relationValue - Relation value (hybrid format)
|
|
10535
|
+
* @param adapter - Database adapter
|
|
10536
|
+
*/
|
|
10537
|
+
async syncRelationProperties(schema, recordId, attributeName, relationValue, adapter) {
|
|
10538
|
+
const attribute = schema.attributes.find((a) => a.name === attributeName);
|
|
10539
|
+
if (!attribute || attribute.type !== "relation") {
|
|
10540
|
+
return;
|
|
10541
|
+
}
|
|
10542
|
+
if (!attribute.properties) {
|
|
10543
|
+
return;
|
|
10544
|
+
}
|
|
10545
|
+
const normalized = this.normalizeRelationValue(relationValue);
|
|
10546
|
+
for (const item of normalized) {
|
|
10547
|
+
if (item.props) {
|
|
10548
|
+
this.validateProperties(attribute.properties, item.props);
|
|
10549
|
+
}
|
|
10550
|
+
}
|
|
10551
|
+
const existing = await adapter.relationAttributes?.findBySource(
|
|
10552
|
+
schema.name,
|
|
10553
|
+
recordId,
|
|
10554
|
+
attributeName
|
|
10555
|
+
);
|
|
10556
|
+
const existingIds = new Set((existing ?? []).map((r) => r.toId));
|
|
10557
|
+
const newIds = new Set(normalized.map((item) => item.id));
|
|
10558
|
+
const toUpsert = normalized.filter((item) => item.props !== void 0);
|
|
10559
|
+
const toDelete = Array.from(existingIds).filter((id) => !newIds.has(id));
|
|
10560
|
+
if (toUpsert.length > 0 && adapter.relationAttributes) {
|
|
10561
|
+
const inputs = toUpsert.map((item) => ({
|
|
10562
|
+
fromObject: schema.name,
|
|
10563
|
+
fromId: recordId,
|
|
10564
|
+
fromAttribute: attributeName,
|
|
10565
|
+
toId: item.id,
|
|
10566
|
+
properties: item.props ?? {},
|
|
10567
|
+
updatedBy: this.userId ?? void 0,
|
|
10568
|
+
createdBy: this.userId ?? void 0
|
|
10569
|
+
}));
|
|
10570
|
+
await adapter.relationAttributes.upsertBatch(inputs);
|
|
10571
|
+
}
|
|
10572
|
+
if (toDelete.length > 0 && adapter.relationAttributes && existing) {
|
|
10573
|
+
for (const toId of toDelete) {
|
|
10574
|
+
const relation2 = existing.find((r) => r.toId === toId);
|
|
10575
|
+
if (relation2) {
|
|
10576
|
+
}
|
|
10577
|
+
}
|
|
10578
|
+
await adapter.relationAttributes.deleteBySource(schema.name, recordId, attributeName);
|
|
10579
|
+
if (toUpsert.length > 0) {
|
|
10580
|
+
const inputs = toUpsert.map((item) => ({
|
|
10581
|
+
fromObject: schema.name,
|
|
10582
|
+
fromId: recordId,
|
|
10583
|
+
fromAttribute: attributeName,
|
|
10584
|
+
toId: item.id,
|
|
10585
|
+
properties: item.props ?? {},
|
|
10586
|
+
updatedBy: this.userId ?? void 0,
|
|
10587
|
+
createdBy: this.userId ?? void 0
|
|
10588
|
+
}));
|
|
10589
|
+
await adapter.relationAttributes.upsertBatch(inputs);
|
|
10590
|
+
}
|
|
10591
|
+
}
|
|
10592
|
+
}
|
|
10593
|
+
/**
|
|
10594
|
+
* Validate relation properties against PropertySchema.
|
|
10595
|
+
*
|
|
10596
|
+
* Uses Zod for runtime validation based on PropertyDefinition types.
|
|
10597
|
+
*
|
|
10598
|
+
* @param propertySchema - Schema defining allowed properties
|
|
10599
|
+
* @param properties - Properties to validate
|
|
10600
|
+
* @throws {z.ZodError} if validation fails
|
|
10601
|
+
*/
|
|
10602
|
+
validateProperties(propertySchema, properties) {
|
|
10603
|
+
const schema = this.buildZodSchema(propertySchema);
|
|
10604
|
+
schema.parse(properties);
|
|
10605
|
+
}
|
|
10606
|
+
// ============================================================================
|
|
10607
|
+
// PRIVATE HELPERS
|
|
10608
|
+
// ============================================================================
|
|
10609
|
+
/**
|
|
10610
|
+
* Normalize relation value to unified internal format.
|
|
10611
|
+
*
|
|
10612
|
+
* Converts:
|
|
10613
|
+
* - string[] → Array<{ id, props?: undefined }>
|
|
10614
|
+
* - string → [{ id, props?: undefined }]
|
|
10615
|
+
* - null → []
|
|
10616
|
+
* - Array<{ id, props }> → Array<{ id, props }> (passthrough)
|
|
10617
|
+
* - { id, props } → [{ id, props }] (single to array)
|
|
10618
|
+
*
|
|
10619
|
+
* @param value - Relation value in hybrid format
|
|
10620
|
+
* @returns Normalized array of relation items
|
|
10621
|
+
* @private
|
|
10622
|
+
*/
|
|
10623
|
+
normalizeRelationValue(value) {
|
|
10624
|
+
if (value === null || value === void 0) {
|
|
10625
|
+
return [];
|
|
10626
|
+
}
|
|
10627
|
+
if (typeof value === "string") {
|
|
10628
|
+
return [{ id: value }];
|
|
10629
|
+
}
|
|
10630
|
+
if (!Array.isArray(value) && typeof value === "object" && "id" in value) {
|
|
10631
|
+
return [value];
|
|
10632
|
+
}
|
|
10633
|
+
if (Array.isArray(value)) {
|
|
10634
|
+
return value.map((item) => {
|
|
10635
|
+
if (typeof item === "string") {
|
|
10636
|
+
return { id: item };
|
|
10637
|
+
}
|
|
10638
|
+
return item;
|
|
10639
|
+
});
|
|
10640
|
+
}
|
|
10641
|
+
return [];
|
|
10642
|
+
}
|
|
10643
|
+
/**
|
|
10644
|
+
* Build Zod schema from PropertySchema definition.
|
|
10645
|
+
*
|
|
10646
|
+
* Dynamically generates validation schema based on PropertyDefinition types.
|
|
10647
|
+
*
|
|
10648
|
+
* @param propertySchema - PropertySchema with definitions
|
|
10649
|
+
* @returns Zod schema for validation
|
|
10650
|
+
* @private
|
|
10651
|
+
*/
|
|
10652
|
+
buildZodSchema(propertySchema) {
|
|
10653
|
+
const shape = {};
|
|
10654
|
+
for (const def of propertySchema.definitions) {
|
|
10655
|
+
let fieldSchema = this.buildFieldSchema(def);
|
|
10656
|
+
if (!def.required) {
|
|
10657
|
+
fieldSchema = fieldSchema.optional();
|
|
10658
|
+
}
|
|
10659
|
+
shape[def.name] = fieldSchema;
|
|
10660
|
+
}
|
|
10661
|
+
return z5.object(shape);
|
|
10662
|
+
}
|
|
10663
|
+
/**
|
|
10664
|
+
* Build Zod schema for a single property field.
|
|
10665
|
+
*
|
|
10666
|
+
* @param def - PropertyDefinition
|
|
10667
|
+
* @returns Zod schema for the field
|
|
10668
|
+
* @private
|
|
10669
|
+
*/
|
|
10670
|
+
buildFieldSchema(def) {
|
|
10671
|
+
switch (def.type) {
|
|
10672
|
+
case "text":
|
|
10673
|
+
case "textarea": {
|
|
10674
|
+
let schema = z5.string();
|
|
10675
|
+
if (def.minLength !== void 0) {
|
|
10676
|
+
schema = schema.min(def.minLength);
|
|
10677
|
+
}
|
|
10678
|
+
if (def.maxLength !== void 0) {
|
|
10679
|
+
schema = schema.max(def.maxLength);
|
|
10680
|
+
}
|
|
10681
|
+
if (def.type === "text" && def.pattern) {
|
|
10682
|
+
schema = schema.regex(new RegExp(def.pattern));
|
|
10683
|
+
}
|
|
10684
|
+
return schema;
|
|
10685
|
+
}
|
|
10686
|
+
case "number": {
|
|
10687
|
+
let schema = z5.number();
|
|
10688
|
+
if (def.min !== void 0) {
|
|
10689
|
+
schema = schema.min(def.min);
|
|
10690
|
+
}
|
|
10691
|
+
if (def.max !== void 0) {
|
|
10692
|
+
schema = schema.max(def.max);
|
|
10693
|
+
}
|
|
10694
|
+
if (def.integer) {
|
|
10695
|
+
schema = schema.int();
|
|
10696
|
+
}
|
|
10697
|
+
return schema;
|
|
10698
|
+
}
|
|
10699
|
+
case "checkbox": {
|
|
10700
|
+
return z5.boolean();
|
|
10701
|
+
}
|
|
10702
|
+
case "date": {
|
|
10703
|
+
const schema = z5.string().datetime();
|
|
10704
|
+
return schema;
|
|
10705
|
+
}
|
|
10706
|
+
case "phone": {
|
|
10707
|
+
return z5.string();
|
|
10708
|
+
}
|
|
10709
|
+
case "currency": {
|
|
10710
|
+
let schema = z5.number();
|
|
10711
|
+
if (def.min !== void 0) {
|
|
10712
|
+
schema = schema.min(def.min);
|
|
10713
|
+
}
|
|
10714
|
+
if (def.max !== void 0) {
|
|
10715
|
+
schema = schema.max(def.max);
|
|
10716
|
+
}
|
|
10717
|
+
return schema;
|
|
10718
|
+
}
|
|
10719
|
+
case "status":
|
|
10720
|
+
case "select": {
|
|
10721
|
+
const validValues = def.options.map((opt) => opt.value);
|
|
10722
|
+
return z5.enum(validValues);
|
|
10723
|
+
}
|
|
10724
|
+
case "multiselect": {
|
|
10725
|
+
const validValues = def.options.map((opt) => opt.value);
|
|
10726
|
+
let schema = z5.array(z5.enum(validValues));
|
|
10727
|
+
if (def.maxSelections !== void 0) {
|
|
10728
|
+
schema = schema.max(def.maxSelections);
|
|
10729
|
+
}
|
|
10730
|
+
return schema;
|
|
10731
|
+
}
|
|
10732
|
+
case "rating": {
|
|
10733
|
+
let schema = z5.number().int();
|
|
10734
|
+
if (def.max !== void 0) {
|
|
10735
|
+
schema = schema.max(def.max);
|
|
10736
|
+
}
|
|
10737
|
+
return schema.min(0);
|
|
10738
|
+
}
|
|
10739
|
+
case "location": {
|
|
10740
|
+
return z5.object({
|
|
10741
|
+
address: z5.string().optional(),
|
|
10742
|
+
lat: z5.number().optional(),
|
|
10743
|
+
lng: z5.number().optional()
|
|
10744
|
+
});
|
|
10745
|
+
}
|
|
10746
|
+
default: {
|
|
10747
|
+
return z5.unknown();
|
|
10748
|
+
}
|
|
10749
|
+
}
|
|
10750
|
+
}
|
|
10751
|
+
};
|
|
10752
|
+
|
|
10559
10753
|
// src/runtime/services/record/relation.service.ts
|
|
10560
10754
|
var RelationService = class extends BaseService {
|
|
10561
10755
|
constructor(adapter, nativeRegistry, options) {
|
|
@@ -10885,8 +11079,10 @@ var RelationService = class extends BaseService {
|
|
|
10885
11079
|
const [attributeId, recordId] = c.split(":");
|
|
10886
11080
|
return { compositeId: c, attributeId, recordId };
|
|
10887
11081
|
});
|
|
10888
|
-
const uniqueRecordIds = [...
|
|
10889
|
-
const uniqueAttributeIds = [
|
|
11082
|
+
const uniqueRecordIds = [...parsed.reduce((set, p) => set.add(p.recordId), /* @__PURE__ */ new Set())];
|
|
11083
|
+
const uniqueAttributeIds = [
|
|
11084
|
+
...parsed.reduce((set, p) => set.add(p.attributeId), /* @__PURE__ */ new Set())
|
|
11085
|
+
];
|
|
10890
11086
|
const records = await this.recordResolver.findByIds(uniqueRecordIds);
|
|
10891
11087
|
if (records.length === 0) {
|
|
10892
11088
|
return [];
|
|
@@ -10895,7 +11091,7 @@ var RelationService = class extends BaseService {
|
|
|
10895
11091
|
const attributePromises = uniqueAttributeIds.map((id) => this.findAttributeById(id));
|
|
10896
11092
|
const attributes = await Promise.all(attributePromises);
|
|
10897
11093
|
const attributeMap = new Map(uniqueAttributeIds.map((id, i) => [id, attributes[i]]));
|
|
10898
|
-
const uniqueObjectIds = [...
|
|
11094
|
+
const uniqueObjectIds = [...records.reduce((set, r) => set.add(r.objectId), /* @__PURE__ */ new Set())];
|
|
10899
11095
|
const schemaPromises = uniqueObjectIds.map((id) => this.schemaService.getObjectSchema(id));
|
|
10900
11096
|
const schemas = await Promise.all(schemaPromises);
|
|
10901
11097
|
const schemaMap = new Map(uniqueObjectIds.map((id, i) => [id, schemas[i]]));
|
|
@@ -11148,7 +11344,10 @@ var RollupService = class extends BaseService {
|
|
|
11148
11344
|
return values.filter((v) => v != null && v !== "").length;
|
|
11149
11345
|
case "countUniqueValues": {
|
|
11150
11346
|
const nonEmpty = values.filter((v) => v != null && v !== "");
|
|
11151
|
-
return
|
|
11347
|
+
return nonEmpty.reduce(
|
|
11348
|
+
(set, v) => set.add(JSON.stringify(v)),
|
|
11349
|
+
/* @__PURE__ */ new Set()
|
|
11350
|
+
).size;
|
|
11152
11351
|
}
|
|
11153
11352
|
case "countEmpty":
|
|
11154
11353
|
return values.filter((v) => v == null || v === "").length;
|
|
@@ -11379,6 +11578,7 @@ var RecordService = class extends BaseService {
|
|
|
11379
11578
|
queryService: this.queryService,
|
|
11380
11579
|
recordResolver: this.recordResolver
|
|
11381
11580
|
});
|
|
11581
|
+
this.relationPropertiesService = new RelationPropertiesService(adapter);
|
|
11382
11582
|
this.rollupService = new RollupService(adapter, {
|
|
11383
11583
|
recordResolver: this.recordResolver
|
|
11384
11584
|
});
|
|
@@ -11423,29 +11623,45 @@ var RecordService = class extends BaseService {
|
|
|
11423
11623
|
if (!options?.skipHooks) {
|
|
11424
11624
|
await this.hookRegistry.execute("beforeCreate", schema.name, hookCtx);
|
|
11425
11625
|
}
|
|
11626
|
+
const normalizedData = this.relationPropertiesService.normalizeRelationValuesForStorage(
|
|
11627
|
+
schema,
|
|
11628
|
+
dataWithDefaults
|
|
11629
|
+
);
|
|
11426
11630
|
if (options?.validate !== false) {
|
|
11427
11631
|
if (options?.allowDraft) {
|
|
11428
|
-
validateDraftOrThrow(schema,
|
|
11632
|
+
validateDraftOrThrow(schema, normalizedData);
|
|
11429
11633
|
} else {
|
|
11430
|
-
validateObjectOrThrow(schema,
|
|
11634
|
+
validateObjectOrThrow(schema, normalizedData);
|
|
11431
11635
|
}
|
|
11432
11636
|
if (!options?.skipRelationValidation) {
|
|
11433
|
-
await this.relationService.validateRelationsOrThrow(schema,
|
|
11637
|
+
await this.relationService.validateRelationsOrThrow(schema, normalizedData);
|
|
11434
11638
|
}
|
|
11435
11639
|
if (!options?.skipUserValidation) {
|
|
11436
|
-
await this.userService.validateUsersOrThrow(schema,
|
|
11640
|
+
await this.userService.validateUsersOrThrow(schema, normalizedData);
|
|
11437
11641
|
}
|
|
11438
11642
|
}
|
|
11439
|
-
const completionStatus = computeRecordStatus(schema,
|
|
11440
|
-
const label = await computeLabel(schema,
|
|
11643
|
+
const completionStatus = computeRecordStatus(schema, normalizedData);
|
|
11644
|
+
const label = await computeLabel(schema, normalizedData, this.labelResolver);
|
|
11441
11645
|
const record = await this.adapter.objectRecords.create({
|
|
11442
11646
|
objectId,
|
|
11443
|
-
data:
|
|
11647
|
+
data: normalizedData,
|
|
11444
11648
|
label,
|
|
11445
11649
|
completionStatus,
|
|
11446
11650
|
metadata: options?.metadata,
|
|
11447
11651
|
createdBy: this.userId
|
|
11448
11652
|
});
|
|
11653
|
+
for (const [attrName, value] of Object.entries(dataWithDefaults)) {
|
|
11654
|
+
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
11655
|
+
if (attr?.type === "relation" && attr.properties) {
|
|
11656
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
11657
|
+
schema,
|
|
11658
|
+
record.id,
|
|
11659
|
+
attrName,
|
|
11660
|
+
value,
|
|
11661
|
+
this.adapter
|
|
11662
|
+
);
|
|
11663
|
+
}
|
|
11664
|
+
}
|
|
11449
11665
|
if (!options?.skipHooks) {
|
|
11450
11666
|
const afterCtx = {
|
|
11451
11667
|
...hookCtx,
|
|
@@ -11576,30 +11792,29 @@ var RecordService = class extends BaseService {
|
|
|
11576
11792
|
hookModifiedValues[key] = hookCtx.newValues[key];
|
|
11577
11793
|
}
|
|
11578
11794
|
}
|
|
11795
|
+
const dataToUpdate = { ...data, ...hookModifiedValues };
|
|
11796
|
+
const normalizedUpdate = this.relationPropertiesService.normalizeRelationValuesForStorage(
|
|
11797
|
+
schema,
|
|
11798
|
+
dataToUpdate
|
|
11799
|
+
);
|
|
11800
|
+
const normalizedMergedData = { ...existing.values, ...normalizedUpdate };
|
|
11579
11801
|
if (options?.validate !== false) {
|
|
11580
11802
|
if (options?.partial) {
|
|
11581
|
-
validateDraftOrThrow(schema,
|
|
11803
|
+
validateDraftOrThrow(schema, normalizedMergedData);
|
|
11582
11804
|
} else {
|
|
11583
|
-
validateObjectOrThrow(schema,
|
|
11805
|
+
validateObjectOrThrow(schema, normalizedMergedData);
|
|
11584
11806
|
}
|
|
11585
11807
|
if (!options?.skipRelationValidation) {
|
|
11586
|
-
await this.relationService.validateRelationsOrThrow(schema,
|
|
11587
|
-
...data,
|
|
11588
|
-
...hookModifiedValues
|
|
11589
|
-
});
|
|
11808
|
+
await this.relationService.validateRelationsOrThrow(schema, normalizedUpdate);
|
|
11590
11809
|
}
|
|
11591
11810
|
if (!options?.skipUserValidation) {
|
|
11592
|
-
await this.userService.validateUsersOrThrow(schema,
|
|
11593
|
-
...data,
|
|
11594
|
-
...hookModifiedValues
|
|
11595
|
-
});
|
|
11811
|
+
await this.userService.validateUsersOrThrow(schema, normalizedUpdate);
|
|
11596
11812
|
}
|
|
11597
11813
|
}
|
|
11598
|
-
const completionStatus = computeRecordStatus(schema,
|
|
11599
|
-
const label = await computeLabel(schema,
|
|
11814
|
+
const completionStatus = computeRecordStatus(schema, normalizedMergedData);
|
|
11815
|
+
const label = await computeLabel(schema, normalizedMergedData, this.labelResolver);
|
|
11600
11816
|
const updatePayload = {
|
|
11601
|
-
...
|
|
11602
|
-
...hookModifiedValues,
|
|
11817
|
+
...normalizedUpdate,
|
|
11603
11818
|
__completionStatus: completionStatus,
|
|
11604
11819
|
__label: label,
|
|
11605
11820
|
__lastUpdatedBy: this.userId,
|
|
@@ -11615,6 +11830,18 @@ var RecordService = class extends BaseService {
|
|
|
11615
11830
|
}
|
|
11616
11831
|
const updated = await this.adapter.objectRecords.update(recordId, updatePayload);
|
|
11617
11832
|
await this.invalidateRecordCaches(recordId, existing.objectId);
|
|
11833
|
+
for (const [attrName, value] of Object.entries(dataToUpdate)) {
|
|
11834
|
+
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
11835
|
+
if (attr?.type === "relation" && attr.properties) {
|
|
11836
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
11837
|
+
schema,
|
|
11838
|
+
recordId,
|
|
11839
|
+
attrName,
|
|
11840
|
+
value,
|
|
11841
|
+
this.adapter
|
|
11842
|
+
);
|
|
11843
|
+
}
|
|
11844
|
+
}
|
|
11618
11845
|
if (!options?.skipHooks) {
|
|
11619
11846
|
const afterCtx = {
|
|
11620
11847
|
...hookCtx,
|
|
@@ -13987,7 +14214,7 @@ var WorkflowService = class extends BaseService {
|
|
|
13987
14214
|
};
|
|
13988
14215
|
const validationResult = WorkflowDefinitionSchema.safeParse(definition);
|
|
13989
14216
|
if (!validationResult.success) {
|
|
13990
|
-
const errors = validationResult.error.
|
|
14217
|
+
const errors = formatZodErrors(validationResult.error).map((err) => err.message);
|
|
13991
14218
|
throw new SchemaError(
|
|
13992
14219
|
`Invalid workflow definition: ${errors.join(", ")}`,
|
|
13993
14220
|
SchemaErrorCode.VALIDATION_FAILED
|
|
@@ -14029,7 +14256,7 @@ var WorkflowService = class extends BaseService {
|
|
|
14029
14256
|
};
|
|
14030
14257
|
const validationResult = WorkflowDefinitionSchema.safeParse(updated);
|
|
14031
14258
|
if (!validationResult.success) {
|
|
14032
|
-
const errors = validationResult.error.
|
|
14259
|
+
const errors = formatZodErrors(validationResult.error).map((err) => err.message);
|
|
14033
14260
|
throw new SchemaError(
|
|
14034
14261
|
`Invalid workflow definition: ${errors.join(", ")}`,
|
|
14035
14262
|
SchemaErrorCode.VALIDATION_FAILED
|
|
@@ -14058,7 +14285,7 @@ var WorkflowService = class extends BaseService {
|
|
|
14058
14285
|
}
|
|
14059
14286
|
const validationResult = WorkflowDefinitionSchema.safeParse(existing);
|
|
14060
14287
|
if (!validationResult.success) {
|
|
14061
|
-
const errors = validationResult.error.
|
|
14288
|
+
const errors = formatZodErrors(validationResult.error).map((err) => err.message);
|
|
14062
14289
|
throw new SchemaError(
|
|
14063
14290
|
`Cannot publish invalid workflow: ${errors.join(", ")}`,
|
|
14064
14291
|
SchemaErrorCode.VALIDATION_FAILED
|
|
@@ -15143,7 +15370,7 @@ var DocumentService = class extends BaseService {
|
|
|
15143
15370
|
const template = await this.templateService.getTemplateOrThrow(document2.templateId);
|
|
15144
15371
|
const slots = await this.getSlots(documentId);
|
|
15145
15372
|
const requiredSlots = template.slots.filter((s) => s.required);
|
|
15146
|
-
const filledSlotNames =
|
|
15373
|
+
const filledSlotNames = slots.reduce((set, s) => set.add(s.slotName), /* @__PURE__ */ new Set());
|
|
15147
15374
|
const allRequiredFilled = requiredSlots.every((s) => filledSlotNames.has(s.name));
|
|
15148
15375
|
if (!allRequiredFilled) {
|
|
15149
15376
|
return await this.updateStatus(documentId, "draft");
|
|
@@ -16717,7 +16944,7 @@ var PermissionService = class extends BaseService {
|
|
|
16717
16944
|
DEFAULT_ROLE_PERMISSIONS
|
|
16718
16945
|
} = await import("./default-roles-42X3TJI5.mjs");
|
|
16719
16946
|
const existingRoles = await this.getRoles();
|
|
16720
|
-
const existingRoleNames =
|
|
16947
|
+
const existingRoleNames = existingRoles.reduce((set, r) => set.add(r.name), /* @__PURE__ */ new Set());
|
|
16721
16948
|
for (const roleName of Object.values(DEFAULT_ROLES)) {
|
|
16722
16949
|
if (existingRoleNames.has(roleName)) {
|
|
16723
16950
|
continue;
|
|
@@ -17211,7 +17438,7 @@ var ViewService = class extends BaseService {
|
|
|
17211
17438
|
*/
|
|
17212
17439
|
async hasUserCustomizations(viewId, userId) {
|
|
17213
17440
|
const overlay = await this.adapter.viewOverlays.findByViewAndUser(viewId, userId);
|
|
17214
|
-
return overlay !== null &&
|
|
17441
|
+
return overlay !== null && hasProperties(overlay.configOverrides);
|
|
17215
17442
|
}
|
|
17216
17443
|
// ============================================================================
|
|
17217
17444
|
// OVERLAY MERGE LOGIC
|
|
@@ -17586,8 +17813,9 @@ async function handleDryRun(adapter, nativeObject, existingObject, result, optio
|
|
|
17586
17813
|
if (options.verbose) {
|
|
17587
17814
|
console.info(`[SyncService] Would ${isNew ? "create" : "update"} object: ${nativeObject.name}`);
|
|
17588
17815
|
}
|
|
17816
|
+
const existingAttrs = existingObject ? await adapter.attributes.findByObjectId(existingObject.id) : [];
|
|
17589
17817
|
for (const attr of nativeObject.attributes) {
|
|
17590
|
-
const existingAttr =
|
|
17818
|
+
const existingAttr = existingAttrs.find((a) => a.name === attr.name) ?? null;
|
|
17591
17819
|
if (existingAttr) {
|
|
17592
17820
|
result.attributesUpdated++;
|
|
17593
17821
|
} else {
|
|
@@ -17609,8 +17837,9 @@ async function upsertObject(adapter, nativeObject, _options) {
|
|
|
17609
17837
|
});
|
|
17610
17838
|
}
|
|
17611
17839
|
async function syncAttributes(adapter, nativeObject, dbObject, existingObject, result) {
|
|
17840
|
+
const existingAttrs = existingObject ? await adapter.attributes.findByObjectId(dbObject.id) : [];
|
|
17612
17841
|
for (const [index, attr] of nativeObject.attributes.entries()) {
|
|
17613
|
-
const existingAttr =
|
|
17842
|
+
const existingAttr = existingAttrs.find((a) => a.name === attr.name) ?? null;
|
|
17614
17843
|
await adapter.attributes.upsert({
|
|
17615
17844
|
objectId: dbObject.id,
|
|
17616
17845
|
name: attr.name,
|
|
@@ -17704,8 +17933,6 @@ export {
|
|
|
17704
17933
|
isIdentityProperty,
|
|
17705
17934
|
isBehaviorProperty,
|
|
17706
17935
|
isPresentationProperty,
|
|
17707
|
-
getPropertyProtectionLevel,
|
|
17708
|
-
filterPropertiesByCategory,
|
|
17709
17936
|
RELATION_TARGET_ANY,
|
|
17710
17937
|
isUniversalRelation,
|
|
17711
17938
|
RecordReferencedError,
|
|
@@ -17715,6 +17942,7 @@ export {
|
|
|
17715
17942
|
SYSTEM_FIELD_NAMES,
|
|
17716
17943
|
RESERVED_ATTRIBUTE_NAMES,
|
|
17717
17944
|
PolicyViolationError,
|
|
17945
|
+
FORBIDDEN_PROPERTY_TYPES,
|
|
17718
17946
|
SYSTEM_ATTRIBUTES,
|
|
17719
17947
|
getSystemAttributeList,
|
|
17720
17948
|
isSystemAttribute,
|
|
@@ -17734,8 +17962,6 @@ export {
|
|
|
17734
17962
|
and,
|
|
17735
17963
|
or,
|
|
17736
17964
|
inValues,
|
|
17737
|
-
isEmpty,
|
|
17738
|
-
isNotEmpty,
|
|
17739
17965
|
isWorkflowDefinition,
|
|
17740
17966
|
isWorkflowPublished,
|
|
17741
17967
|
isSystemWorkflow,
|
|
@@ -17754,7 +17980,6 @@ export {
|
|
|
17754
17980
|
createEmptyContext,
|
|
17755
17981
|
getContextValue,
|
|
17756
17982
|
setContextValue,
|
|
17757
|
-
mergeFormToSlot,
|
|
17758
17983
|
DEFAULT_THEME,
|
|
17759
17984
|
mergeWithDefaults,
|
|
17760
17985
|
generateCssVariables,
|
|
@@ -17788,12 +18013,10 @@ export {
|
|
|
17788
18013
|
WorkflowConfigSchema,
|
|
17789
18014
|
WorkflowStatusSchema,
|
|
17790
18015
|
WorkflowDefinitionSchema,
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
slugify,
|
|
17796
|
-
generateTemplateName,
|
|
18016
|
+
isEmpty,
|
|
18017
|
+
isNotEmpty,
|
|
18018
|
+
toUndefinedIfEmpty,
|
|
18019
|
+
hasProperties,
|
|
17797
18020
|
EMPTY_VALUE_PLACEHOLDER,
|
|
17798
18021
|
formatAttributeValue,
|
|
17799
18022
|
SchemaErrorCode,
|
|
@@ -17818,7 +18041,22 @@ export {
|
|
|
17818
18041
|
RoleNotFoundError,
|
|
17819
18042
|
isForbiddenError,
|
|
17820
18043
|
ConcurrentModificationError,
|
|
17821
|
-
|
|
18044
|
+
PropertySchemaBuilder,
|
|
18045
|
+
PropertyTypeBuilder,
|
|
18046
|
+
BasePropertyBuilder,
|
|
18047
|
+
TextPropertyBuilder,
|
|
18048
|
+
TextareaPropertyBuilder,
|
|
18049
|
+
NumberPropertyBuilder,
|
|
18050
|
+
CheckboxPropertyBuilder,
|
|
18051
|
+
DatePropertyBuilder,
|
|
18052
|
+
PhonePropertyBuilder,
|
|
18053
|
+
CurrencyPropertyBuilder,
|
|
18054
|
+
StatusPropertyBuilder,
|
|
18055
|
+
SelectPropertyBuilder,
|
|
18056
|
+
MultiselectPropertyBuilder,
|
|
18057
|
+
RatingPropertyBuilder,
|
|
18058
|
+
LocationPropertyBuilder,
|
|
18059
|
+
validatePropertyType,
|
|
17822
18060
|
text,
|
|
17823
18061
|
textarea,
|
|
17824
18062
|
richtext,
|
|
@@ -17876,63 +18114,6 @@ export {
|
|
|
17876
18114
|
SYSTEM_TEMPLATES,
|
|
17877
18115
|
getSystemTemplate,
|
|
17878
18116
|
isSystemTemplate,
|
|
17879
|
-
DEFAULT_VALIDATION_MESSAGES,
|
|
17880
|
-
textConfigSchema,
|
|
17881
|
-
textareaConfigSchema,
|
|
17882
|
-
richtextConfigSchema,
|
|
17883
|
-
numberConfigSchema,
|
|
17884
|
-
checkboxConfigSchema,
|
|
17885
|
-
dateConfigSchema,
|
|
17886
|
-
phoneConfigSchema,
|
|
17887
|
-
currencyConfigSchema,
|
|
17888
|
-
statusConfigSchema,
|
|
17889
|
-
locationConfigSchema,
|
|
17890
|
-
selectConfigSchema,
|
|
17891
|
-
multiselectConfigSchema,
|
|
17892
|
-
fileConfigSchema,
|
|
17893
|
-
userConfigSchema,
|
|
17894
|
-
relationConfigSchema,
|
|
17895
|
-
ratingConfigSchema,
|
|
17896
|
-
formulaConfigSchema,
|
|
17897
|
-
rollupConfigSchema,
|
|
17898
|
-
documentConfigSchema,
|
|
17899
|
-
attributeConfigSchemas,
|
|
17900
|
-
getAttributeConfigSchema,
|
|
17901
|
-
validateAttributeConfig,
|
|
17902
|
-
parseAttributeConfig,
|
|
17903
|
-
safeParseAttributeConfig,
|
|
17904
|
-
createTextValidator,
|
|
17905
|
-
createNumberValidator,
|
|
17906
|
-
createCheckboxValidator,
|
|
17907
|
-
createDateValidator,
|
|
17908
|
-
createPhoneValidator,
|
|
17909
|
-
createCurrencyValidator,
|
|
17910
|
-
createStatusValidator,
|
|
17911
|
-
createSelectValidator,
|
|
17912
|
-
createMultiselectValidator,
|
|
17913
|
-
createLocationValidator,
|
|
17914
|
-
createFileValidator,
|
|
17915
|
-
createUserValidator,
|
|
17916
|
-
createSingleRelationValidator,
|
|
17917
|
-
createMultiRelationValidator,
|
|
17918
|
-
createRelationValidator,
|
|
17919
|
-
createRatingValidator,
|
|
17920
|
-
createFormulaValidator,
|
|
17921
|
-
createRollupValidator,
|
|
17922
|
-
createTextAreaValidator,
|
|
17923
|
-
createRichtextValidator,
|
|
17924
|
-
createAttributeValidator,
|
|
17925
|
-
createFormAttributeValidator,
|
|
17926
|
-
createObjectValidator,
|
|
17927
|
-
validateAttribute,
|
|
17928
|
-
validateObject,
|
|
17929
|
-
validateObjectOrThrow,
|
|
17930
|
-
createDraftValidator,
|
|
17931
|
-
validateDraft,
|
|
17932
|
-
validateDraftOrThrow,
|
|
17933
|
-
getMissingRequiredAttributes,
|
|
17934
|
-
isRecordComplete,
|
|
17935
|
-
computeRecordStatus,
|
|
17936
18117
|
WorkflowJwtService,
|
|
17937
18118
|
hashOptions,
|
|
17938
18119
|
cacheKeys,
|
|
@@ -18045,6 +18226,7 @@ export {
|
|
|
18045
18226
|
recalculateParentRollups,
|
|
18046
18227
|
RecordQueryService,
|
|
18047
18228
|
RecordResolverService,
|
|
18229
|
+
RelationPropertiesService,
|
|
18048
18230
|
RelationService,
|
|
18049
18231
|
RollupService,
|
|
18050
18232
|
RecordService,
|