@stndrds/schema 1.0.0-alpha.84 → 1.0.0-alpha.87
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-I4D33CVC.js → chunk-B23XC4L2.js} +980 -292
- package/dist/{chunk-NEVERCM3.js → chunk-E6XO2STS.js} +21 -1
- package/dist/{chunk-HTE7NOF3.mjs → chunk-IFJJT3JZ.mjs} +705 -17
- package/dist/{chunk-7VNLLASJ.mjs → chunk-JUVFK6XD.mjs} +2 -1
- package/dist/{chunk-V2RPPE2Y.mjs → chunk-XAORXFAX.mjs} +21 -1
- package/dist/{chunk-HUT6HYXJ.js → chunk-ZW4N6FV7.js} +2 -1
- package/dist/index.d.mts +305 -8
- package/dist/index.d.ts +305 -8
- package/dist/index.js +31 -7
- package/dist/index.mjs +27 -3
- package/dist/{runtime-BUk5CZfD.d.ts → runtime-Cg0Rwnwx.d.ts} +766 -362
- package/dist/{runtime-BGZqT9aX.d.mts → runtime-Dz1JEYu7.d.mts} +766 -362
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +14 -4
- package/dist/runtime.mjs +13 -3
- package/dist/utils.d.mts +20 -1
- package/dist/utils.d.ts +20 -1
- package/dist/utils.js +4 -2
- package/dist/utils.mjs +3 -1
- package/dist/validation/validators.d.mts +1 -1
- package/dist/validation/validators.d.ts +1 -1
- package/dist/validation/validators.js +2 -2
- package/dist/validation/validators.mjs +1 -1
- package/dist/{validators-BeBrdQCB.d.mts → validators-CJmtOk1a.d.mts} +29 -1
- package/dist/{validators-UuAMCPc6.d.ts → validators-pv_b6bI_.d.ts} +29 -1
- package/package.json +2 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
asTenantId,
|
|
3
3
|
asUserId,
|
|
4
|
+
deepEqual,
|
|
4
5
|
generateId
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XAORXFAX.mjs";
|
|
6
7
|
import {
|
|
7
8
|
computeRecordStatus,
|
|
8
9
|
createFormAttributeValidator,
|
|
@@ -12,7 +13,7 @@ import {
|
|
|
12
13
|
validateDraftOrThrow,
|
|
13
14
|
validateObject,
|
|
14
15
|
validateObjectOrThrow
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-JUVFK6XD.mjs";
|
|
16
17
|
import {
|
|
17
18
|
__require
|
|
18
19
|
} from "./chunk-Y6FXYEAI.mjs";
|
|
@@ -1389,6 +1390,9 @@ function isConditionNode(node) {
|
|
|
1389
1390
|
function isAssignNode(node) {
|
|
1390
1391
|
return node.type === "assign";
|
|
1391
1392
|
}
|
|
1393
|
+
function isAINode(node) {
|
|
1394
|
+
return node.type === "ai";
|
|
1395
|
+
}
|
|
1392
1396
|
function isEndNode(node) {
|
|
1393
1397
|
return node.type === "end";
|
|
1394
1398
|
}
|
|
@@ -1529,6 +1533,47 @@ var assignNodeType = {
|
|
|
1529
1533
|
};
|
|
1530
1534
|
nodeTypeRegistry.register(assignNodeType);
|
|
1531
1535
|
|
|
1536
|
+
// src/types/workflows/node-types/ai.node-type.ts
|
|
1537
|
+
var aiNodeType = {
|
|
1538
|
+
type: "ai",
|
|
1539
|
+
isLinear: true,
|
|
1540
|
+
structural: false,
|
|
1541
|
+
getOutputs(node) {
|
|
1542
|
+
return node.next ? [node.next] : [];
|
|
1543
|
+
},
|
|
1544
|
+
setNext(node, targetId) {
|
|
1545
|
+
return { ...node, next: targetId };
|
|
1546
|
+
},
|
|
1547
|
+
getSlotIds(node) {
|
|
1548
|
+
const slotIds = /* @__PURE__ */ new Set();
|
|
1549
|
+
const action = node.action;
|
|
1550
|
+
if (action.type === "document-generation") {
|
|
1551
|
+
for (const id of action.inputSlotIds) slotIds.add(id);
|
|
1552
|
+
for (const id of action.targetSlotIds) slotIds.add(id);
|
|
1553
|
+
} else if (action.type === "code-execution") {
|
|
1554
|
+
for (const id of action.inputSlotIds ?? []) slotIds.add(id);
|
|
1555
|
+
}
|
|
1556
|
+
return [...slotIds];
|
|
1557
|
+
},
|
|
1558
|
+
validate(node) {
|
|
1559
|
+
const errors = [];
|
|
1560
|
+
if (!node.label) errors.push("AINode must have a label");
|
|
1561
|
+
if (!node.action) errors.push("AINode must have an action");
|
|
1562
|
+
if (!node.next) errors.push("AINode must have a 'next' target");
|
|
1563
|
+
if (node.action?.type === "document-generation") {
|
|
1564
|
+
if (!node.action.templateId) errors.push("Document generation must have a templateId");
|
|
1565
|
+
if (!node.action.inputSlotIds?.length)
|
|
1566
|
+
errors.push("Document generation must have input slots");
|
|
1567
|
+
if (!node.action.targetSlotIds?.length)
|
|
1568
|
+
errors.push("Document generation must have target slots");
|
|
1569
|
+
} else if (node.action?.type === "code-execution") {
|
|
1570
|
+
if (!node.action.code) errors.push("Code execution must have code");
|
|
1571
|
+
}
|
|
1572
|
+
return errors;
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
nodeTypeRegistry.register(aiNodeType);
|
|
1576
|
+
|
|
1532
1577
|
// src/types/workflows/node-types/end.node-type.ts
|
|
1533
1578
|
var endNodeType = {
|
|
1534
1579
|
type: "end",
|
|
@@ -1741,14 +1786,15 @@ function isInvitationOrGrantEvent(event) {
|
|
|
1741
1786
|
var ZONE_ORDER = ["collect", "actions"];
|
|
1742
1787
|
var ZONE_CONFIG = {
|
|
1743
1788
|
collect: { allowedNodeTypes: ["form", "condition"] },
|
|
1744
|
-
actions: { allowedNodeTypes: ["condition", "assign"] }
|
|
1789
|
+
actions: { allowedNodeTypes: ["condition", "assign", "ai"] }
|
|
1745
1790
|
};
|
|
1746
1791
|
var TERMINAL_NODE_TYPES = /* @__PURE__ */ new Set(["start", "end"]);
|
|
1747
1792
|
var NODE_TYPE_ZONE = {
|
|
1748
1793
|
form: "collect",
|
|
1749
1794
|
condition: "collect",
|
|
1750
1795
|
// default — overridden by assignNodeZones logic
|
|
1751
|
-
assign: "actions"
|
|
1796
|
+
assign: "actions",
|
|
1797
|
+
ai: "actions"
|
|
1752
1798
|
};
|
|
1753
1799
|
function assignNodeZones(orderedNodes) {
|
|
1754
1800
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -1833,9 +1879,14 @@ var StartNodeSchema = z.object({
|
|
|
1833
1879
|
id: z.string().min(1),
|
|
1834
1880
|
next: z.string().nullish()
|
|
1835
1881
|
});
|
|
1882
|
+
var RelationFieldConfigSchema = z.object({
|
|
1883
|
+
visibleProperties: z.array(z.string()).optional(),
|
|
1884
|
+
allowCreate: z.boolean().optional()
|
|
1885
|
+
}).optional();
|
|
1836
1886
|
var FormFieldRefSchema = z.object({
|
|
1837
1887
|
slotId: z.string().min(1, "slotId is required"),
|
|
1838
|
-
attribute: z.string().min(1, "attribute is required")
|
|
1888
|
+
attribute: z.string().min(1, "attribute is required"),
|
|
1889
|
+
relationConfig: RelationFieldConfigSchema
|
|
1839
1890
|
});
|
|
1840
1891
|
var FlowRowFieldSchema = z.object({
|
|
1841
1892
|
id: z.string().min(1),
|
|
@@ -1843,7 +1894,8 @@ var FlowRowFieldSchema = z.object({
|
|
|
1843
1894
|
attribute: z.string().min(1),
|
|
1844
1895
|
label: z.string().max(200).optional(),
|
|
1845
1896
|
tooltip: z.string().max(1e3).optional(),
|
|
1846
|
-
required: z.boolean().optional()
|
|
1897
|
+
required: z.boolean().optional(),
|
|
1898
|
+
relationConfig: RelationFieldConfigSchema
|
|
1847
1899
|
});
|
|
1848
1900
|
var FlowFieldsRowSchema = z.object({
|
|
1849
1901
|
id: z.string().min(1),
|
|
@@ -1924,6 +1976,35 @@ var AssignNodeSchema = z.object({
|
|
|
1924
1976
|
assignments: z.array(AssignmentMappingSchema).min(1),
|
|
1925
1977
|
next: z.string().nullish()
|
|
1926
1978
|
});
|
|
1979
|
+
var DocumentGenerationActionSchema = z.object({
|
|
1980
|
+
type: z.literal("document-generation"),
|
|
1981
|
+
templateId: z.string().min(1, "Template ID is required"),
|
|
1982
|
+
inputSlotIds: z.array(z.string().min(1)).min(1, "At least one input slot is required"),
|
|
1983
|
+
targetSlotIds: z.array(z.string().min(1)).min(1, "At least one target slot is required"),
|
|
1984
|
+
outputFormat: z.enum(["pdf", "docx"]),
|
|
1985
|
+
aiInstructions: z.string().nullish()
|
|
1986
|
+
});
|
|
1987
|
+
var CodeExecutionActionSchema = z.object({
|
|
1988
|
+
type: z.literal("code-execution"),
|
|
1989
|
+
code: z.string().min(1, "Code is required"),
|
|
1990
|
+
language: z.enum(["javascript", "typescript", "python"]),
|
|
1991
|
+
inputSlotIds: z.array(z.string().min(1)).optional(),
|
|
1992
|
+
outputVariable: z.string().optional(),
|
|
1993
|
+
packages: z.array(z.string()).optional()
|
|
1994
|
+
});
|
|
1995
|
+
var AIActionConfigSchema = z.discriminatedUnion("type", [
|
|
1996
|
+
DocumentGenerationActionSchema,
|
|
1997
|
+
CodeExecutionActionSchema
|
|
1998
|
+
]);
|
|
1999
|
+
var AINodeSchema = z.object({
|
|
2000
|
+
type: z.literal("ai"),
|
|
2001
|
+
id: z.string().min(1),
|
|
2002
|
+
label: z.string().min(1),
|
|
2003
|
+
description: z.string().nullish(),
|
|
2004
|
+
action: AIActionConfigSchema,
|
|
2005
|
+
timeoutMs: z.number().positive().optional(),
|
|
2006
|
+
next: z.string().nullish()
|
|
2007
|
+
});
|
|
1927
2008
|
var EndNodeSchema = z.object({
|
|
1928
2009
|
type: z.literal("end"),
|
|
1929
2010
|
id: z.string().min(1),
|
|
@@ -1935,6 +2016,7 @@ var WorkflowNodeSchema = z.discriminatedUnion("type", [
|
|
|
1935
2016
|
FormNodeSchema,
|
|
1936
2017
|
ConditionNodeSchema,
|
|
1937
2018
|
AssignNodeSchema,
|
|
2019
|
+
AINodeSchema,
|
|
1938
2020
|
EndNodeSchema
|
|
1939
2021
|
]);
|
|
1940
2022
|
var SlotModeSchema = z.enum(["create", "select", "optional"]);
|
|
@@ -2898,6 +2980,214 @@ function resolveSource(source, slotValues) {
|
|
|
2898
2980
|
}
|
|
2899
2981
|
}
|
|
2900
2982
|
|
|
2983
|
+
// src/runtime/executors/ai.executor.ts
|
|
2984
|
+
var AIExecutor = class {
|
|
2985
|
+
constructor(actionRegistry) {
|
|
2986
|
+
this.actionRegistry = actionRegistry;
|
|
2987
|
+
this.nodeType = "ai";
|
|
2988
|
+
}
|
|
2989
|
+
async execute(node, ctx) {
|
|
2990
|
+
if (!node.next) {
|
|
2991
|
+
return error("MISSING_NEXT", "AINode must have a 'next' target");
|
|
2992
|
+
}
|
|
2993
|
+
const handler = this.actionRegistry.get(node.action.type);
|
|
2994
|
+
if (!handler) {
|
|
2995
|
+
return error(
|
|
2996
|
+
"UNKNOWN_AI_ACTION",
|
|
2997
|
+
`No handler registered for AI action type: ${node.action.type}`
|
|
2998
|
+
);
|
|
2999
|
+
}
|
|
3000
|
+
const result = await handler.execute(node.action, ctx);
|
|
3001
|
+
if (!result.success) {
|
|
3002
|
+
return error("AI_ACTION_FAILED", result.error ?? "AI action failed", true);
|
|
3003
|
+
}
|
|
3004
|
+
return success(node.next, result.contextUpdates);
|
|
3005
|
+
}
|
|
3006
|
+
validate(node) {
|
|
3007
|
+
const errors = [];
|
|
3008
|
+
if (!node.label) errors.push("AINode must have a label");
|
|
3009
|
+
if (!node.action) errors.push("AINode must have an action");
|
|
3010
|
+
if (!node.next) errors.push("AINode must have a 'next' target");
|
|
3011
|
+
return errors;
|
|
3012
|
+
}
|
|
3013
|
+
};
|
|
3014
|
+
|
|
3015
|
+
// src/runtime/executors/ai-actions/types.ts
|
|
3016
|
+
var AIActionRegistry = class {
|
|
3017
|
+
constructor() {
|
|
3018
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
3019
|
+
}
|
|
3020
|
+
register(handler) {
|
|
3021
|
+
this.handlers.set(handler.actionType, handler);
|
|
3022
|
+
}
|
|
3023
|
+
get(actionType) {
|
|
3024
|
+
return this.handlers.get(actionType);
|
|
3025
|
+
}
|
|
3026
|
+
has(actionType) {
|
|
3027
|
+
return this.handlers.has(actionType);
|
|
3028
|
+
}
|
|
3029
|
+
};
|
|
3030
|
+
|
|
3031
|
+
// src/runtime/executors/ai-actions/document-generation.handler.ts
|
|
3032
|
+
var DocumentGenerationHandler = class {
|
|
3033
|
+
constructor(deps = null) {
|
|
3034
|
+
this.deps = deps;
|
|
3035
|
+
this.actionType = "document-generation";
|
|
3036
|
+
}
|
|
3037
|
+
async execute(action, ctx) {
|
|
3038
|
+
if (!this.deps) {
|
|
3039
|
+
return {
|
|
3040
|
+
success: false,
|
|
3041
|
+
error: "Document generation not configured. Provide sandbox, fileService, and storage in SchemaModule."
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
const { sandbox, fileService, storage } = this.deps;
|
|
3045
|
+
const file2 = await fileService.getFile(action.templateId);
|
|
3046
|
+
if (!file2) {
|
|
3047
|
+
return {
|
|
3048
|
+
success: false,
|
|
3049
|
+
error: `Template file not found: ${action.templateId}`
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
3052
|
+
if (!storage.download) {
|
|
3053
|
+
return {
|
|
3054
|
+
success: false,
|
|
3055
|
+
error: "StorageAdapter.download() not implemented. Required for document generation."
|
|
3056
|
+
};
|
|
3057
|
+
}
|
|
3058
|
+
let templateContent;
|
|
3059
|
+
try {
|
|
3060
|
+
const buffer = await storage.download(file2.storagePath);
|
|
3061
|
+
templateContent = new Uint8Array(buffer);
|
|
3062
|
+
} catch (err) {
|
|
3063
|
+
return {
|
|
3064
|
+
success: false,
|
|
3065
|
+
error: `Failed to download template "${file2.name}": ${err instanceof Error ? err.message : "unknown error"}`
|
|
3066
|
+
};
|
|
3067
|
+
}
|
|
3068
|
+
const slotData = {};
|
|
3069
|
+
for (const slotId of action.inputSlotIds) {
|
|
3070
|
+
slotData[slotId] = ctx.executionContext.slots[slotId] ?? {};
|
|
3071
|
+
}
|
|
3072
|
+
const instructions = [
|
|
3073
|
+
"Generate a professional document based on the provided template and data.",
|
|
3074
|
+
action.aiInstructions ?? "",
|
|
3075
|
+
"",
|
|
3076
|
+
"## Data Context",
|
|
3077
|
+
"```json",
|
|
3078
|
+
JSON.stringify(slotData, null, 2),
|
|
3079
|
+
"```",
|
|
3080
|
+
"",
|
|
3081
|
+
"## Instructions",
|
|
3082
|
+
"1. Unpack the template: python3 /workspace/scripts/office/unpack.py /workspace/template.docx /workspace/unpacked/",
|
|
3083
|
+
"2. Analyze the XML structure in /workspace/unpacked/word/document.xml",
|
|
3084
|
+
"3. Read the data from /workspace/data.json",
|
|
3085
|
+
"4. Modify the XML content using the provided data \u2014 replace placeholders, fill tables, update fields",
|
|
3086
|
+
"5. Pack: python3 /workspace/scripts/office/pack.py /workspace/unpacked/ /workspace/output.docx",
|
|
3087
|
+
"6. Validate: python3 /workspace/scripts/office/validate.py /workspace/output.docx",
|
|
3088
|
+
action.outputFormat === "pdf" ? "7. Convert to PDF: python3 /workspace/scripts/office/convert.py /workspace/output.docx pdf /workspace/" : ""
|
|
3089
|
+
].filter(Boolean).join("\n");
|
|
3090
|
+
const outputPath = action.outputFormat === "pdf" ? "/workspace/output.pdf" : "/workspace/output.docx";
|
|
3091
|
+
try {
|
|
3092
|
+
const result = await sandbox.executeAgent({
|
|
3093
|
+
instructions,
|
|
3094
|
+
template: "stndrds-pdf",
|
|
3095
|
+
inputFiles: [
|
|
3096
|
+
{
|
|
3097
|
+
path: "/workspace/template.docx",
|
|
3098
|
+
content: templateContent
|
|
3099
|
+
},
|
|
3100
|
+
{
|
|
3101
|
+
path: "/workspace/data.json",
|
|
3102
|
+
content: JSON.stringify(slotData, null, 2)
|
|
3103
|
+
}
|
|
3104
|
+
],
|
|
3105
|
+
expectedOutputs: [outputPath],
|
|
3106
|
+
timeoutMs: 6e5,
|
|
3107
|
+
maxIterations: 20
|
|
3108
|
+
});
|
|
3109
|
+
if (!result.success || result.artifacts.length === 0) {
|
|
3110
|
+
return {
|
|
3111
|
+
success: false,
|
|
3112
|
+
error: result.summary ?? "Agent failed to generate document"
|
|
3113
|
+
};
|
|
3114
|
+
}
|
|
3115
|
+
const contextUpdates = {};
|
|
3116
|
+
for (const slotId of action.targetSlotIds) {
|
|
3117
|
+
contextUpdates[slotId] = {
|
|
3118
|
+
...ctx.executionContext.slots[slotId] ?? {},
|
|
3119
|
+
_generatedDocuments: result.artifacts.map((a) => ({
|
|
3120
|
+
path: a.path,
|
|
3121
|
+
mimeType: a.mimeType
|
|
3122
|
+
}))
|
|
3123
|
+
};
|
|
3124
|
+
}
|
|
3125
|
+
return { success: true, contextUpdates };
|
|
3126
|
+
} catch (err) {
|
|
3127
|
+
return {
|
|
3128
|
+
success: false,
|
|
3129
|
+
error: err instanceof Error ? err.message : "Document generation failed"
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
};
|
|
3134
|
+
|
|
3135
|
+
// src/runtime/executors/ai-actions/code-execution.handler.ts
|
|
3136
|
+
var CodeExecutionHandler = class {
|
|
3137
|
+
constructor(sandbox = null) {
|
|
3138
|
+
this.sandbox = sandbox;
|
|
3139
|
+
this.actionType = "code-execution";
|
|
3140
|
+
}
|
|
3141
|
+
async execute(action, ctx) {
|
|
3142
|
+
if (!this.sandbox) {
|
|
3143
|
+
return {
|
|
3144
|
+
success: false,
|
|
3145
|
+
error: "Code execution handler not configured. Inject a SandboxExecutor via constructor."
|
|
3146
|
+
};
|
|
3147
|
+
}
|
|
3148
|
+
const env = {};
|
|
3149
|
+
for (const slotId of action.inputSlotIds ?? []) {
|
|
3150
|
+
const slotData = ctx.executionContext.slots[slotId] ?? {};
|
|
3151
|
+
env[`SLOT_${slotId.toUpperCase()}`] = JSON.stringify(slotData);
|
|
3152
|
+
}
|
|
3153
|
+
try {
|
|
3154
|
+
const result = await this.sandbox.executeCode({
|
|
3155
|
+
code: action.code,
|
|
3156
|
+
language: action.language,
|
|
3157
|
+
env,
|
|
3158
|
+
packages: action.packages,
|
|
3159
|
+
timeoutMs: 3e4
|
|
3160
|
+
// 30s for code mode
|
|
3161
|
+
});
|
|
3162
|
+
if (result.exitCode !== 0) {
|
|
3163
|
+
return {
|
|
3164
|
+
success: false,
|
|
3165
|
+
error: `Code execution failed (exit ${result.exitCode}): ${result.stderr}`
|
|
3166
|
+
};
|
|
3167
|
+
}
|
|
3168
|
+
const contextUpdates = {};
|
|
3169
|
+
if (action.outputVariable) {
|
|
3170
|
+
contextUpdates[action.outputVariable] = result.stdout.trim();
|
|
3171
|
+
}
|
|
3172
|
+
return { success: true, contextUpdates };
|
|
3173
|
+
} catch (err) {
|
|
3174
|
+
return {
|
|
3175
|
+
success: false,
|
|
3176
|
+
error: err instanceof Error ? err.message : "Code execution failed"
|
|
3177
|
+
};
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
};
|
|
3181
|
+
|
|
3182
|
+
// src/runtime/executors/ai-actions/index.ts
|
|
3183
|
+
function createDefaultAIActionRegistry(deps) {
|
|
3184
|
+
const registry2 = new AIActionRegistry();
|
|
3185
|
+
const docGenDeps = deps?.sandbox && deps?.fileService && deps?.storage ? { sandbox: deps.sandbox, fileService: deps.fileService, storage: deps.storage } : null;
|
|
3186
|
+
registry2.register(new DocumentGenerationHandler(docGenDeps));
|
|
3187
|
+
registry2.register(new CodeExecutionHandler(deps?.sandbox ?? null));
|
|
3188
|
+
return registry2;
|
|
3189
|
+
}
|
|
3190
|
+
|
|
2901
3191
|
// src/runtime/executors/start.executor.ts
|
|
2902
3192
|
var StartExecutor = class {
|
|
2903
3193
|
constructor() {
|
|
@@ -5822,6 +6112,9 @@ var FORBIDDEN_PROPERTY_TYPES = [
|
|
|
5822
6112
|
"document",
|
|
5823
6113
|
"richtext"
|
|
5824
6114
|
];
|
|
6115
|
+
function hasOptions2(attr) {
|
|
6116
|
+
return attr.type === "select" || attr.type === "status" || attr.type === "multiselect";
|
|
6117
|
+
}
|
|
5825
6118
|
|
|
5826
6119
|
// src/builders/attribute-validators.ts
|
|
5827
6120
|
import { ICONS } from "@stndrds/constants";
|
|
@@ -5926,6 +6219,20 @@ function validateOptions(options, attributeName) {
|
|
|
5926
6219
|
validateIconName(option.icon, `option "${option.id}" of "${attributeName}"`);
|
|
5927
6220
|
}
|
|
5928
6221
|
}
|
|
6222
|
+
for (const option of options) {
|
|
6223
|
+
if (option.inverse === void 0) continue;
|
|
6224
|
+
const inverseOption = options.find((o) => o.value === option.inverse);
|
|
6225
|
+
if (!inverseOption) {
|
|
6226
|
+
throw new Error(
|
|
6227
|
+
`[AttributeBuilder] Option "${option.value}" in "${attributeName}" has inverse "${option.inverse}" which does not match any option value.`
|
|
6228
|
+
);
|
|
6229
|
+
}
|
|
6230
|
+
if (inverseOption.inverse !== option.value) {
|
|
6231
|
+
throw new Error(
|
|
6232
|
+
`[AttributeBuilder] Inverse mismatch in "${attributeName}": "${option.value}" points to "${option.inverse}", but "${option.inverse}" points to "${inverseOption.inverse ?? "(none)"}". Inverse pairs must be symmetric.`
|
|
6233
|
+
);
|
|
6234
|
+
}
|
|
6235
|
+
}
|
|
5929
6236
|
}
|
|
5930
6237
|
|
|
5931
6238
|
// src/builders/attribute-builders.ts
|
|
@@ -7880,7 +8187,10 @@ var ListViewBuilder = class {
|
|
|
7880
8187
|
groupByAttribute: tab.groupByAttribute,
|
|
7881
8188
|
cardUserAttribute: tab.cardUserAttribute,
|
|
7882
8189
|
cardDateAttribute: tab.cardDateAttribute,
|
|
7883
|
-
createMode: tab.createMode
|
|
8190
|
+
createMode: tab.createMode,
|
|
8191
|
+
kanbanColumnOrder: tab.kanbanColumnOrder,
|
|
8192
|
+
kanbanColumnVisibility: tab.kanbanColumnVisibility,
|
|
8193
|
+
kanbanPinnedColumns: tab.kanbanPinnedColumns
|
|
7884
8194
|
}))
|
|
7885
8195
|
};
|
|
7886
8196
|
return {
|
|
@@ -7969,6 +8279,34 @@ var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
|
|
|
7969
8279
|
this.tabData.cardDateAttribute = attributeName;
|
|
7970
8280
|
return this;
|
|
7971
8281
|
}
|
|
8282
|
+
/**
|
|
8283
|
+
* Set the order of kanban columns by option values (for kanban layout only)
|
|
8284
|
+
* @param order - Array of option values in desired order
|
|
8285
|
+
* @example .kanbanColumnOrder(["new", "in_progress", "done"])
|
|
8286
|
+
*/
|
|
8287
|
+
kanbanColumnOrder(order) {
|
|
8288
|
+
this.tabData.kanbanColumnOrder = order;
|
|
8289
|
+
return this;
|
|
8290
|
+
}
|
|
8291
|
+
/**
|
|
8292
|
+
* Set the visibility of kanban columns by option values (for kanban layout only)
|
|
8293
|
+
* @param visibility - Record mapping option values to visibility (true = visible, false = hidden)
|
|
8294
|
+
* @example .kanbanColumnVisibility({ "new": true, "archived": false })
|
|
8295
|
+
*/
|
|
8296
|
+
kanbanColumnVisibility(visibility) {
|
|
8297
|
+
this.tabData.kanbanColumnVisibility = visibility;
|
|
8298
|
+
return this;
|
|
8299
|
+
}
|
|
8300
|
+
/**
|
|
8301
|
+
* Set pinned kanban columns by option values (for kanban layout only)
|
|
8302
|
+
* Pinned columns remain fixed during horizontal scrolling
|
|
8303
|
+
* @param pinnedColumns - Array of option values to pin
|
|
8304
|
+
* @example .kanbanPinnedColumns(["new", "done"])
|
|
8305
|
+
*/
|
|
8306
|
+
kanbanPinnedColumns(pinnedColumns) {
|
|
8307
|
+
this.tabData.kanbanPinnedColumns = pinnedColumns;
|
|
8308
|
+
return this;
|
|
8309
|
+
}
|
|
7972
8310
|
/**
|
|
7973
8311
|
* Set creation behavior when clicking "+"
|
|
7974
8312
|
* @param mode - "redirect" (navigate to detail), "inline" (empty row), or "modal" (stacked modal)
|
|
@@ -8085,12 +8423,55 @@ var WorkflowFormRowBuilder = class {
|
|
|
8085
8423
|
this.rowData.fields.push(field);
|
|
8086
8424
|
return this;
|
|
8087
8425
|
}
|
|
8426
|
+
/**
|
|
8427
|
+
* Add a relation field to the current row.
|
|
8428
|
+
* Use this for relation attributes that need specific configuration
|
|
8429
|
+
* (e.g., which qualified properties to display).
|
|
8430
|
+
*
|
|
8431
|
+
* @param slotId - The slot containing the relation attribute
|
|
8432
|
+
* @param attribute - The relation attribute name
|
|
8433
|
+
* @param options - Optional label, required flag, and relation config
|
|
8434
|
+
*/
|
|
8435
|
+
relationField(slotId, attribute, options) {
|
|
8436
|
+
const relationConfig = options?.visibleProperties || options?.allowCreate !== void 0 ? {
|
|
8437
|
+
visibleProperties: options?.visibleProperties,
|
|
8438
|
+
allowCreate: options?.allowCreate
|
|
8439
|
+
} : void 0;
|
|
8440
|
+
const field = {
|
|
8441
|
+
id: `${this.rowData.id}-${slotId}-${attribute}`,
|
|
8442
|
+
slotId,
|
|
8443
|
+
attribute,
|
|
8444
|
+
label: options?.label,
|
|
8445
|
+
required: options?.required,
|
|
8446
|
+
relationConfig
|
|
8447
|
+
};
|
|
8448
|
+
this.rowData.fields.push(field);
|
|
8449
|
+
return this;
|
|
8450
|
+
}
|
|
8088
8451
|
/**
|
|
8089
8452
|
* Start a new row
|
|
8090
8453
|
*/
|
|
8091
8454
|
row(id) {
|
|
8092
8455
|
return this.formBuilder._finalizeRow(this.rowData).row(id);
|
|
8093
8456
|
}
|
|
8457
|
+
/**
|
|
8458
|
+
* Add a heading row (finalizes the current field row first)
|
|
8459
|
+
*/
|
|
8460
|
+
heading(content, level) {
|
|
8461
|
+
return this.formBuilder._finalizeRow(this.rowData).heading(content, level);
|
|
8462
|
+
}
|
|
8463
|
+
/**
|
|
8464
|
+
* Add a visual separator (finalizes the current field row first)
|
|
8465
|
+
*/
|
|
8466
|
+
separator() {
|
|
8467
|
+
return this.formBuilder._finalizeRow(this.rowData).separator();
|
|
8468
|
+
}
|
|
8469
|
+
/**
|
|
8470
|
+
* Add a static text row (finalizes the current field row first)
|
|
8471
|
+
*/
|
|
8472
|
+
text(content) {
|
|
8473
|
+
return this.formBuilder._finalizeRow(this.rowData).text(content);
|
|
8474
|
+
}
|
|
8094
8475
|
/**
|
|
8095
8476
|
* Set the next node and finish this form
|
|
8096
8477
|
*/
|
|
@@ -8121,13 +8502,56 @@ var WorkflowFormBuilder = class {
|
|
|
8121
8502
|
this.rowOrder++;
|
|
8122
8503
|
return new WorkflowFormRowBuilder(this, id, this.rowOrder);
|
|
8123
8504
|
}
|
|
8505
|
+
/**
|
|
8506
|
+
* Add a heading row to the form
|
|
8507
|
+
*/
|
|
8508
|
+
heading(content, level) {
|
|
8509
|
+
this.rowOrder++;
|
|
8510
|
+
const row = {
|
|
8511
|
+
id: `heading-${this.rowOrder}`,
|
|
8512
|
+
order: this.rowOrder,
|
|
8513
|
+
type: "heading",
|
|
8514
|
+
content,
|
|
8515
|
+
level
|
|
8516
|
+
};
|
|
8517
|
+
this.rows.push(row);
|
|
8518
|
+
return this;
|
|
8519
|
+
}
|
|
8520
|
+
/**
|
|
8521
|
+
* Add a visual separator row to the form
|
|
8522
|
+
*/
|
|
8523
|
+
separator() {
|
|
8524
|
+
this.rowOrder++;
|
|
8525
|
+
const row = {
|
|
8526
|
+
id: `separator-${this.rowOrder}`,
|
|
8527
|
+
order: this.rowOrder,
|
|
8528
|
+
type: "separator"
|
|
8529
|
+
};
|
|
8530
|
+
this.rows.push(row);
|
|
8531
|
+
return this;
|
|
8532
|
+
}
|
|
8533
|
+
/**
|
|
8534
|
+
* Add a static text row to the form
|
|
8535
|
+
*/
|
|
8536
|
+
text(content) {
|
|
8537
|
+
this.rowOrder++;
|
|
8538
|
+
const row = {
|
|
8539
|
+
id: `text-${this.rowOrder}`,
|
|
8540
|
+
order: this.rowOrder,
|
|
8541
|
+
type: "text",
|
|
8542
|
+
content
|
|
8543
|
+
};
|
|
8544
|
+
this.rows.push(row);
|
|
8545
|
+
return this;
|
|
8546
|
+
}
|
|
8124
8547
|
/**
|
|
8125
8548
|
* Set the next node and complete the form definition
|
|
8126
8549
|
*/
|
|
8127
8550
|
next(nodeId) {
|
|
8128
|
-
|
|
8551
|
+
const hasFieldRows = this.rows.some((r) => !r.type || r.type === "fields");
|
|
8552
|
+
if (!hasFieldRows) {
|
|
8129
8553
|
throw new Error(
|
|
8130
|
-
`[WorkflowBuilder] Form "${this.nodeId}" has no rows. Use .row() to add
|
|
8554
|
+
`[WorkflowBuilder] Form "${this.nodeId}" has no field rows. Use .row() to add fields.`
|
|
8131
8555
|
);
|
|
8132
8556
|
}
|
|
8133
8557
|
return this.workflowBuilder._addFormNode({
|
|
@@ -8178,6 +8602,22 @@ var WorkflowSimpleFormBuilder = class {
|
|
|
8178
8602
|
}
|
|
8179
8603
|
return this;
|
|
8180
8604
|
}
|
|
8605
|
+
/**
|
|
8606
|
+
* Add a relation field with optional configuration.
|
|
8607
|
+
* Use this for relation attributes that need specific configuration
|
|
8608
|
+
* (e.g., which qualified properties to display).
|
|
8609
|
+
*/
|
|
8610
|
+
relationField(slotId, attribute, options) {
|
|
8611
|
+
this.fieldList.push({
|
|
8612
|
+
slotId,
|
|
8613
|
+
attribute,
|
|
8614
|
+
relationConfig: options ? {
|
|
8615
|
+
visibleProperties: options.visibleProperties,
|
|
8616
|
+
allowCreate: options.allowCreate
|
|
8617
|
+
} : void 0
|
|
8618
|
+
});
|
|
8619
|
+
return this;
|
|
8620
|
+
}
|
|
8181
8621
|
/**
|
|
8182
8622
|
* Set the next node and complete the form definition
|
|
8183
8623
|
*/
|
|
@@ -8319,6 +8759,68 @@ var WorkflowAssignBuilder = class {
|
|
|
8319
8759
|
});
|
|
8320
8760
|
}
|
|
8321
8761
|
};
|
|
8762
|
+
var WorkflowAIBuilder = class {
|
|
8763
|
+
/** @internal */
|
|
8764
|
+
constructor(workflowBuilder, nodeId, label) {
|
|
8765
|
+
this.action = null;
|
|
8766
|
+
this.workflowBuilder = workflowBuilder;
|
|
8767
|
+
this.nodeId = nodeId;
|
|
8768
|
+
this.label = label;
|
|
8769
|
+
}
|
|
8770
|
+
/**
|
|
8771
|
+
* Set the description for this AI node
|
|
8772
|
+
*/
|
|
8773
|
+
describe(description) {
|
|
8774
|
+
this.nodeDescription = description;
|
|
8775
|
+
return this;
|
|
8776
|
+
}
|
|
8777
|
+
/**
|
|
8778
|
+
* Set a custom timeout (default: 120_000ms)
|
|
8779
|
+
*/
|
|
8780
|
+
timeout(ms) {
|
|
8781
|
+
this.nodeTimeoutMs = ms;
|
|
8782
|
+
return this;
|
|
8783
|
+
}
|
|
8784
|
+
/**
|
|
8785
|
+
* Configure document generation action
|
|
8786
|
+
*/
|
|
8787
|
+
documentGeneration(config) {
|
|
8788
|
+
this.action = {
|
|
8789
|
+
type: "document-generation",
|
|
8790
|
+
...config
|
|
8791
|
+
};
|
|
8792
|
+
return this;
|
|
8793
|
+
}
|
|
8794
|
+
/**
|
|
8795
|
+
* Configure code execution action
|
|
8796
|
+
*/
|
|
8797
|
+
codeExecution(config) {
|
|
8798
|
+
this.action = {
|
|
8799
|
+
type: "code-execution",
|
|
8800
|
+
...config
|
|
8801
|
+
};
|
|
8802
|
+
return this;
|
|
8803
|
+
}
|
|
8804
|
+
/**
|
|
8805
|
+
* Set the next node and complete the AI node definition
|
|
8806
|
+
*/
|
|
8807
|
+
next(nodeId) {
|
|
8808
|
+
if (!this.action) {
|
|
8809
|
+
throw new Error(
|
|
8810
|
+
`[WorkflowBuilder] AI node "${this.nodeId}" must have an action. Use .documentGeneration() or .codeExecution() first.`
|
|
8811
|
+
);
|
|
8812
|
+
}
|
|
8813
|
+
return this.workflowBuilder._addNode({
|
|
8814
|
+
type: "ai",
|
|
8815
|
+
id: this.nodeId,
|
|
8816
|
+
label: this.label,
|
|
8817
|
+
description: this.nodeDescription,
|
|
8818
|
+
action: this.action,
|
|
8819
|
+
timeoutMs: this.nodeTimeoutMs,
|
|
8820
|
+
next: nodeId
|
|
8821
|
+
});
|
|
8822
|
+
}
|
|
8823
|
+
};
|
|
8322
8824
|
var WorkflowEndBuilder = class {
|
|
8323
8825
|
/** @internal */
|
|
8324
8826
|
constructor(workflowBuilder, nodeId) {
|
|
@@ -8490,6 +8992,12 @@ var WorkflowBuilder = class {
|
|
|
8490
8992
|
assign(id, label, targetSlotId) {
|
|
8491
8993
|
return new WorkflowAssignBuilder(this, id, label, targetSlotId);
|
|
8492
8994
|
}
|
|
8995
|
+
/**
|
|
8996
|
+
* Define an AI node (run an AI action like document generation or code execution)
|
|
8997
|
+
*/
|
|
8998
|
+
ai(id, label) {
|
|
8999
|
+
return new WorkflowAIBuilder(this, id, label);
|
|
9000
|
+
}
|
|
8493
9001
|
/**
|
|
8494
9002
|
* Define an end node
|
|
8495
9003
|
*/
|
|
@@ -10210,6 +10718,7 @@ var BilateralSyncService = class extends BaseService {
|
|
|
10210
10718
|
const addedIds = newData.ids.filter((id) => !oldData.ids.includes(id));
|
|
10211
10719
|
const removedIds = oldData.ids.filter((id) => !newData.ids.includes(id));
|
|
10212
10720
|
const commonIds = newData.ids.filter((id) => oldData.ids.includes(id));
|
|
10721
|
+
const inverseMappings = this.buildInverseMappings(sourceAttr);
|
|
10213
10722
|
await Promise.all([
|
|
10214
10723
|
// Add new relations
|
|
10215
10724
|
...addedIds.map(
|
|
@@ -10219,7 +10728,9 @@ var BilateralSyncService = class extends BaseService {
|
|
|
10219
10728
|
sourceRecordId,
|
|
10220
10729
|
sourceSchema.name,
|
|
10221
10730
|
sourceAttr.name,
|
|
10222
|
-
newData.properties.get(targetId)
|
|
10731
|
+
newData.properties.get(targetId),
|
|
10732
|
+
inverseMappings,
|
|
10733
|
+
bilateral
|
|
10223
10734
|
)
|
|
10224
10735
|
),
|
|
10225
10736
|
// Remove deleted relations
|
|
@@ -10235,7 +10746,9 @@ var BilateralSyncService = class extends BaseService {
|
|
|
10235
10746
|
sourceSchema.name,
|
|
10236
10747
|
sourceAttr.name,
|
|
10237
10748
|
newData.properties.get(targetId),
|
|
10238
|
-
oldData.properties.get(targetId)
|
|
10749
|
+
oldData.properties.get(targetId),
|
|
10750
|
+
inverseMappings,
|
|
10751
|
+
bilateral
|
|
10239
10752
|
)
|
|
10240
10753
|
)
|
|
10241
10754
|
]);
|
|
@@ -10279,7 +10792,7 @@ var BilateralSyncService = class extends BaseService {
|
|
|
10279
10792
|
* Add an ID to an inverse relation (with properties).
|
|
10280
10793
|
* @private
|
|
10281
10794
|
*/
|
|
10282
|
-
async addInverseRelation(targetRecordId, inverseAttr, sourceRecordId, sourceObject, sourceAttribute, properties) {
|
|
10795
|
+
async addInverseRelation(targetRecordId, inverseAttr, sourceRecordId, sourceObject, sourceAttribute, properties, inverseMappings, bilateral) {
|
|
10283
10796
|
const targetRecord = await this.adapter.objectRecords.findById(targetRecordId);
|
|
10284
10797
|
if (!targetRecord) {
|
|
10285
10798
|
return;
|
|
@@ -10310,14 +10823,27 @@ var BilateralSyncService = class extends BaseService {
|
|
|
10310
10823
|
this.adapter
|
|
10311
10824
|
);
|
|
10312
10825
|
}
|
|
10826
|
+
if (inverseMappings && bilateral) {
|
|
10827
|
+
const invertedProps = this.invertProperties(properties, inverseMappings);
|
|
10828
|
+
const targetSchemaObj = await this.schemaService.getObjectSchemaByName(bilateral.object);
|
|
10829
|
+
if (targetSchemaObj) {
|
|
10830
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
10831
|
+
targetSchemaObj,
|
|
10832
|
+
targetRecordId,
|
|
10833
|
+
bilateral.attribute,
|
|
10834
|
+
[{ id: sourceRecordId, props: invertedProps }],
|
|
10835
|
+
this.adapter
|
|
10836
|
+
);
|
|
10837
|
+
}
|
|
10838
|
+
}
|
|
10313
10839
|
}
|
|
10314
10840
|
}
|
|
10315
10841
|
/**
|
|
10316
10842
|
* Update properties of an existing inverse relation.
|
|
10317
10843
|
* @private
|
|
10318
10844
|
*/
|
|
10319
|
-
async updateInverseRelationProperties(targetRecordId, _inverseAttr, sourceRecordId, sourceObject, sourceAttribute, newProperties, oldProperties) {
|
|
10320
|
-
if (
|
|
10845
|
+
async updateInverseRelationProperties(targetRecordId, _inverseAttr, sourceRecordId, sourceObject, sourceAttribute, newProperties, oldProperties, inverseMappings, bilateral) {
|
|
10846
|
+
if (deepEqual(newProperties, oldProperties)) {
|
|
10321
10847
|
return;
|
|
10322
10848
|
}
|
|
10323
10849
|
if (!this.adapter.relationAttributes) {
|
|
@@ -10335,12 +10861,32 @@ var BilateralSyncService = class extends BaseService {
|
|
|
10335
10861
|
[{ id: targetRecordId, props: newProperties }],
|
|
10336
10862
|
this.adapter
|
|
10337
10863
|
);
|
|
10864
|
+
if (inverseMappings && bilateral) {
|
|
10865
|
+
const invertedProps = this.invertProperties(newProperties, inverseMappings);
|
|
10866
|
+
const targetSchemaObj = await this.schemaService.getObjectSchemaByName(bilateral.object);
|
|
10867
|
+
if (targetSchemaObj) {
|
|
10868
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
10869
|
+
targetSchemaObj,
|
|
10870
|
+
targetRecordId,
|
|
10871
|
+
bilateral.attribute,
|
|
10872
|
+
[{ id: sourceRecordId, props: invertedProps }],
|
|
10873
|
+
this.adapter
|
|
10874
|
+
);
|
|
10875
|
+
}
|
|
10876
|
+
}
|
|
10338
10877
|
} else {
|
|
10339
10878
|
await this.adapter.relationAttributes.deleteBySource(
|
|
10340
10879
|
sourceObject,
|
|
10341
10880
|
sourceRecordId,
|
|
10342
10881
|
sourceAttribute
|
|
10343
10882
|
);
|
|
10883
|
+
if (bilateral) {
|
|
10884
|
+
await this.adapter.relationAttributes.deleteBySource(
|
|
10885
|
+
bilateral.object,
|
|
10886
|
+
targetRecordId,
|
|
10887
|
+
bilateral.attribute
|
|
10888
|
+
);
|
|
10889
|
+
}
|
|
10344
10890
|
}
|
|
10345
10891
|
}
|
|
10346
10892
|
/**
|
|
@@ -10372,6 +10918,54 @@ var BilateralSyncService = class extends BaseService {
|
|
|
10372
10918
|
});
|
|
10373
10919
|
await this.invalidateTargetRecordCaches(targetRecordId, targetRecord.objectId);
|
|
10374
10920
|
}
|
|
10921
|
+
/**
|
|
10922
|
+
* Build inverse value mappings from property definitions.
|
|
10923
|
+
* Scans all select/status properties for options with `inverse` field.
|
|
10924
|
+
* @returns Map<propertyName, Map<sourceValue, inverseValue>>
|
|
10925
|
+
* @private
|
|
10926
|
+
*/
|
|
10927
|
+
buildInverseMappings(sourceAttr) {
|
|
10928
|
+
const mappings = /* @__PURE__ */ new Map();
|
|
10929
|
+
const definitions = sourceAttr.properties?.definitions;
|
|
10930
|
+
if (!definitions) return mappings;
|
|
10931
|
+
for (const def of definitions) {
|
|
10932
|
+
if (!hasOptions2(def)) continue;
|
|
10933
|
+
const options = def.options;
|
|
10934
|
+
const valueMap = /* @__PURE__ */ new Map();
|
|
10935
|
+
for (const option of options) {
|
|
10936
|
+
if (option.inverse) {
|
|
10937
|
+
valueMap.set(option.value, option.inverse);
|
|
10938
|
+
}
|
|
10939
|
+
}
|
|
10940
|
+
if (valueMap.size > 0) {
|
|
10941
|
+
mappings.set(def.name, valueMap);
|
|
10942
|
+
}
|
|
10943
|
+
}
|
|
10944
|
+
return mappings;
|
|
10945
|
+
}
|
|
10946
|
+
/**
|
|
10947
|
+
* Apply inverse mappings to a set of properties.
|
|
10948
|
+
* Properties without a mapping are copied as-is.
|
|
10949
|
+
* @private
|
|
10950
|
+
*/
|
|
10951
|
+
invertProperties(props, mappings) {
|
|
10952
|
+
const result = {};
|
|
10953
|
+
for (const [key, value] of Object.entries(props)) {
|
|
10954
|
+
const valueMap = mappings.get(key);
|
|
10955
|
+
if (!valueMap) {
|
|
10956
|
+
result[key] = value;
|
|
10957
|
+
} else if (typeof value === "string") {
|
|
10958
|
+
result[key] = valueMap.get(value) ?? value;
|
|
10959
|
+
} else if (Array.isArray(value)) {
|
|
10960
|
+
result[key] = value.map(
|
|
10961
|
+
(v) => typeof v === "string" ? valueMap.get(v) ?? v : v
|
|
10962
|
+
);
|
|
10963
|
+
} else {
|
|
10964
|
+
result[key] = value;
|
|
10965
|
+
}
|
|
10966
|
+
}
|
|
10967
|
+
return result;
|
|
10968
|
+
}
|
|
10375
10969
|
/**
|
|
10376
10970
|
* Normalize a relation value to an array of IDs.
|
|
10377
10971
|
* @private
|
|
@@ -12454,7 +13048,7 @@ var RecordService = class extends BaseService {
|
|
|
12454
13048
|
}
|
|
12455
13049
|
}
|
|
12456
13050
|
}
|
|
12457
|
-
for (const [attrName, value] of Object.entries(
|
|
13051
|
+
for (const [attrName, value] of Object.entries(dataWithDefaults)) {
|
|
12458
13052
|
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
12459
13053
|
if (attr?.type === "relation" && isBilateralRelation(attr)) {
|
|
12460
13054
|
await this.bilateralSyncService.syncBilateralRelation(
|
|
@@ -12666,7 +13260,7 @@ var RecordService = class extends BaseService {
|
|
|
12666
13260
|
}
|
|
12667
13261
|
}
|
|
12668
13262
|
}
|
|
12669
|
-
for (const [attrName, value] of Object.entries(
|
|
13263
|
+
for (const [attrName, value] of Object.entries(dataToUpdate)) {
|
|
12670
13264
|
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
12671
13265
|
if (attr?.type === "relation" && isBilateralRelation(attr)) {
|
|
12672
13266
|
const oldValue = bilateralOldValues[attrName];
|
|
@@ -13526,7 +14120,7 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13526
14120
|
* Start a new workflow instance
|
|
13527
14121
|
*/
|
|
13528
14122
|
async startWorkflow(input) {
|
|
13529
|
-
|
|
14123
|
+
let workflow2 = await this.workflowService.getWorkflow(input.workflowName);
|
|
13530
14124
|
if (!workflow2) {
|
|
13531
14125
|
throw new SchemaError(
|
|
13532
14126
|
`Workflow "${input.workflowName}" not found`,
|
|
@@ -13539,6 +14133,20 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13539
14133
|
SchemaErrorCode.VALIDATION_FAILED
|
|
13540
14134
|
);
|
|
13541
14135
|
}
|
|
14136
|
+
if (workflow2.system && this.adapter.workflows) {
|
|
14137
|
+
const dbWorkflow = await this.adapter.workflows.upsert({
|
|
14138
|
+
name: workflow2.name,
|
|
14139
|
+
label: workflow2.label ?? workflow2.name,
|
|
14140
|
+
description: workflow2.description,
|
|
14141
|
+
status: "published",
|
|
14142
|
+
version: workflow2.version,
|
|
14143
|
+
slots: workflow2.slots ?? [],
|
|
14144
|
+
nodes: workflow2.nodes,
|
|
14145
|
+
startNodeId: workflow2.startNodeId,
|
|
14146
|
+
system: true
|
|
14147
|
+
});
|
|
14148
|
+
workflow2 = { ...workflow2, id: dbWorkflow.id };
|
|
14149
|
+
}
|
|
13542
14150
|
const context = createEmptyContext();
|
|
13543
14151
|
if (input.initialSlots) {
|
|
13544
14152
|
for (const [slotId, data] of Object.entries(input.initialSlots)) {
|
|
@@ -16956,6 +17564,74 @@ var PermissionService = class extends BaseService {
|
|
|
16956
17564
|
// ============================================================================
|
|
16957
17565
|
// INITIALIZATION
|
|
16958
17566
|
// ============================================================================
|
|
17567
|
+
/**
|
|
17568
|
+
* Reset all roles and permissions to their default configuration.
|
|
17569
|
+
*
|
|
17570
|
+
* This will:
|
|
17571
|
+
* 1. Delete all custom (non-system) roles and reassign their users to the default member role
|
|
17572
|
+
* 2. Reset permissions on the default roles (owner, member) back to defaults
|
|
17573
|
+
* 3. Invalidate all permission caches
|
|
17574
|
+
*
|
|
17575
|
+
* @example
|
|
17576
|
+
* ```typescript
|
|
17577
|
+
* const service = new PermissionService(adapter);
|
|
17578
|
+
* await service.resetToDefaults();
|
|
17579
|
+
* ```
|
|
17580
|
+
*/
|
|
17581
|
+
async resetToDefaults() {
|
|
17582
|
+
const { DEFAULT_ROLES, DEFAULT_ROLE_PERMISSIONS } = await import("./default-roles-6D3HQ3DQ.mjs");
|
|
17583
|
+
await this.initializeDefaultRoles();
|
|
17584
|
+
const allRoles = await this.getRoles();
|
|
17585
|
+
const memberRole = allRoles.find((r) => r.name === DEFAULT_ROLES.MEMBER);
|
|
17586
|
+
if (!memberRole) {
|
|
17587
|
+
throw new Error("Default member role not found after initialization");
|
|
17588
|
+
}
|
|
17589
|
+
const customRoles = allRoles.filter(
|
|
17590
|
+
(r) => !Object.values(DEFAULT_ROLES).includes(
|
|
17591
|
+
r.name
|
|
17592
|
+
)
|
|
17593
|
+
);
|
|
17594
|
+
for (const role of customRoles) {
|
|
17595
|
+
const usersWithRole = await this.permissionsRepo.countUsersWithRole(role.name);
|
|
17596
|
+
if (usersWithRole > 0) {
|
|
17597
|
+
}
|
|
17598
|
+
await this.permissionsRepo.deleteRole(role.id);
|
|
17599
|
+
}
|
|
17600
|
+
for (const roleName of Object.values(DEFAULT_ROLES)) {
|
|
17601
|
+
const role = allRoles.find((r) => r.name === roleName);
|
|
17602
|
+
if (!role) continue;
|
|
17603
|
+
const permConfig = DEFAULT_ROLE_PERMISSIONS[roleName];
|
|
17604
|
+
const permissionInputs = [];
|
|
17605
|
+
for (const perm of permConfig.system) {
|
|
17606
|
+
permissionInputs.push({
|
|
17607
|
+
scope: "system",
|
|
17608
|
+
target: perm.target,
|
|
17609
|
+
actions: perm.actions
|
|
17610
|
+
});
|
|
17611
|
+
}
|
|
17612
|
+
for (const perm of permConfig.object) {
|
|
17613
|
+
permissionInputs.push({
|
|
17614
|
+
scope: "object",
|
|
17615
|
+
target: perm.target,
|
|
17616
|
+
actions: perm.actions
|
|
17617
|
+
});
|
|
17618
|
+
}
|
|
17619
|
+
await this.permissionsRepo.setPermissions(role.id, permissionInputs);
|
|
17620
|
+
}
|
|
17621
|
+
await this.invalidateAllCache();
|
|
17622
|
+
if (this.auditService && this.userId) {
|
|
17623
|
+
await this.auditService.logRoleAction({
|
|
17624
|
+
action: "role.updated",
|
|
17625
|
+
actorId: this.userId,
|
|
17626
|
+
roleId: "all",
|
|
17627
|
+
roleLabel: "All roles",
|
|
17628
|
+
metadata: {
|
|
17629
|
+
resetToDefaults: true,
|
|
17630
|
+
customRolesDeleted: customRoles.length
|
|
17631
|
+
}
|
|
17632
|
+
});
|
|
17633
|
+
}
|
|
17634
|
+
}
|
|
16959
17635
|
/**
|
|
16960
17636
|
* Initialize default roles for the tenant if they don't exist.
|
|
16961
17637
|
*
|
|
@@ -18015,6 +18691,7 @@ export {
|
|
|
18015
18691
|
RESERVED_ATTRIBUTE_NAMES,
|
|
18016
18692
|
PolicyViolationError,
|
|
18017
18693
|
FORBIDDEN_PROPERTY_TYPES,
|
|
18694
|
+
hasOptions2 as hasOptions,
|
|
18018
18695
|
SYSTEM_ATTRIBUTES,
|
|
18019
18696
|
getSystemAttributeList,
|
|
18020
18697
|
isSystemAttribute,
|
|
@@ -18031,6 +18708,7 @@ export {
|
|
|
18031
18708
|
isFormNode,
|
|
18032
18709
|
isConditionNode,
|
|
18033
18710
|
isAssignNode,
|
|
18711
|
+
isAINode,
|
|
18034
18712
|
isEndNode,
|
|
18035
18713
|
isConditionRule,
|
|
18036
18714
|
isConditionGroup,
|
|
@@ -18081,6 +18759,10 @@ export {
|
|
|
18081
18759
|
AssignmentSourceSchema,
|
|
18082
18760
|
AssignmentMappingSchema,
|
|
18083
18761
|
AssignNodeSchema,
|
|
18762
|
+
DocumentGenerationActionSchema,
|
|
18763
|
+
CodeExecutionActionSchema,
|
|
18764
|
+
AIActionConfigSchema,
|
|
18765
|
+
AINodeSchema,
|
|
18084
18766
|
EndNodeSchema,
|
|
18085
18767
|
WorkflowNodeSchema,
|
|
18086
18768
|
SlotModeSchema,
|
|
@@ -18178,6 +18860,7 @@ export {
|
|
|
18178
18860
|
WorkflowSimpleFormBuilder,
|
|
18179
18861
|
WorkflowConditionBuilder,
|
|
18180
18862
|
WorkflowAssignBuilder,
|
|
18863
|
+
WorkflowAIBuilder,
|
|
18181
18864
|
WorkflowEndBuilder,
|
|
18182
18865
|
WorkflowStartBuilder,
|
|
18183
18866
|
WorkflowBuilder,
|
|
@@ -18231,6 +18914,11 @@ export {
|
|
|
18231
18914
|
EndExecutor,
|
|
18232
18915
|
FormExecutor,
|
|
18233
18916
|
AssignExecutor,
|
|
18917
|
+
AIExecutor,
|
|
18918
|
+
AIActionRegistry,
|
|
18919
|
+
DocumentGenerationHandler,
|
|
18920
|
+
CodeExecutionHandler,
|
|
18921
|
+
createDefaultAIActionRegistry,
|
|
18234
18922
|
StartExecutor,
|
|
18235
18923
|
createDefaultExecutorRegistry,
|
|
18236
18924
|
getDefaultExecutorRegistry,
|