@lunnoa/client 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +40 -1
- package/dist/index.cjs +117 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -4
- package/dist/index.d.ts +55 -4
- package/dist/index.js +117 -21
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +40 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +53 -2
- package/dist/react.d.ts +53 -2
- package/dist/react.js +40 -1
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/skills/lunnoa-client/SKILL.md +37 -1
- package/skills/lunnoa-solution-design/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -249,7 +249,7 @@ Re-run codegen whenever entity types, workflows, or agents change on the deploym
|
|
|
249
249
|
|
|
250
250
|
## Define, run, and CLI deploy
|
|
251
251
|
|
|
252
|
-
Author local definitions with `defineWorkflow` / `defineAgent` / `defineEntityType`, run linear chains with `lunnoa.runs.start`, and upsert with the CLI (prefer CLI over calling upsert from app code). Agent and workflow upsert is by slug inside the workspace on the API key. An entity type slug is unique on the deployment. Deploy grants that type to the API key's workspace when the slug is new, and will not rewrite a type already granted to other workspaces. Instance writes reject unknown attribute keys unless `allowUnknownAttributes` is true — use the reserved `extensions` object for flexible bags:
|
|
252
|
+
Author local definitions with `defineWorkflow` / `defineAgent` / `defineEntityType`, run linear chains with `lunnoa.runs.start`, branch deployed workflows with `paths` on Request Approval or Conditional Paths, and upsert with the CLI (prefer CLI over calling upsert from app code). Agent and workflow upsert is by slug inside the workspace on the API key. An entity type slug is unique on the deployment. Deploy grants that type to the API key's workspace when the slug is new, and will not rewrite a type already granted to other workspaces. Instance writes reject unknown attribute keys unless `allowUnknownAttributes` is true — use the reserved `extensions` object for flexible bags:
|
|
253
253
|
|
|
254
254
|
```bash
|
|
255
255
|
npx @lunnoa/client entity-types deploy ./human.ts --url https://lunnoa.example --api-key lna_...
|
package/dist/cli.js
CHANGED
|
@@ -546,6 +546,33 @@ var DEFINE_KINDS = {
|
|
|
546
546
|
agent: "agent",
|
|
547
547
|
entityType: "entityType"
|
|
548
548
|
};
|
|
549
|
+
var PATH_CONDITIONS = [
|
|
550
|
+
"contains",
|
|
551
|
+
"does_not_contain",
|
|
552
|
+
"equals",
|
|
553
|
+
"does_not_equal",
|
|
554
|
+
"exists",
|
|
555
|
+
"does_not_exist",
|
|
556
|
+
"starts_with",
|
|
557
|
+
"ends_with",
|
|
558
|
+
"is_empty",
|
|
559
|
+
"is_not_empty",
|
|
560
|
+
"comes_before",
|
|
561
|
+
"comes_after",
|
|
562
|
+
"is_in_the_past",
|
|
563
|
+
"is_in_the_future",
|
|
564
|
+
"is_true",
|
|
565
|
+
"is_false",
|
|
566
|
+
"is_truthy",
|
|
567
|
+
"is_falsey",
|
|
568
|
+
"is_greater_than",
|
|
569
|
+
"is_less_than",
|
|
570
|
+
"is_greater_than_or_equal_to",
|
|
571
|
+
"is_less_than_or_equal_to",
|
|
572
|
+
"matches_regex",
|
|
573
|
+
"does_not_match_regex"
|
|
574
|
+
];
|
|
575
|
+
var PATH_CONDITION_SET = new Set(PATH_CONDITIONS);
|
|
549
576
|
function resolveActionAppId(action) {
|
|
550
577
|
if (action.appId?.trim()) {
|
|
551
578
|
return action.appId.trim();
|
|
@@ -1805,6 +1832,11 @@ function stepFromDefinition(step) {
|
|
|
1805
1832
|
...step.name ? { name: step.name } : {}
|
|
1806
1833
|
};
|
|
1807
1834
|
}
|
|
1835
|
+
if (step.paths?.length) {
|
|
1836
|
+
throw new Error(
|
|
1837
|
+
"runs.start runs straight lines only. Deploy workflows with paths, then execute them."
|
|
1838
|
+
);
|
|
1839
|
+
}
|
|
1808
1840
|
const use = step.use;
|
|
1809
1841
|
const input = {
|
|
1810
1842
|
...use.input ?? {},
|
|
@@ -2037,7 +2069,14 @@ function stepToUpsertInput(step) {
|
|
|
2037
2069
|
...step.input ?? {}
|
|
2038
2070
|
},
|
|
2039
2071
|
name: step.name ?? use.name,
|
|
2040
|
-
description: use.description
|
|
2072
|
+
description: use.description,
|
|
2073
|
+
...step.paths?.length ? {
|
|
2074
|
+
paths: step.paths.map((path) => ({
|
|
2075
|
+
label: path.label,
|
|
2076
|
+
...path.when ? { when: path.when } : {},
|
|
2077
|
+
steps: path.steps.map(stepToUpsertInput)
|
|
2078
|
+
}))
|
|
2079
|
+
} : {}
|
|
2041
2080
|
};
|
|
2042
2081
|
}
|
|
2043
2082
|
function workflowDefinitionToUpsert(def) {
|
package/dist/index.cjs
CHANGED
|
@@ -542,6 +542,32 @@ var DEFINE_KINDS = {
|
|
|
542
542
|
agent: "agent",
|
|
543
543
|
entityType: "entityType"
|
|
544
544
|
};
|
|
545
|
+
var PATH_CONDITIONS = [
|
|
546
|
+
"contains",
|
|
547
|
+
"does_not_contain",
|
|
548
|
+
"equals",
|
|
549
|
+
"does_not_equal",
|
|
550
|
+
"exists",
|
|
551
|
+
"does_not_exist",
|
|
552
|
+
"starts_with",
|
|
553
|
+
"ends_with",
|
|
554
|
+
"is_empty",
|
|
555
|
+
"is_not_empty",
|
|
556
|
+
"comes_before",
|
|
557
|
+
"comes_after",
|
|
558
|
+
"is_in_the_past",
|
|
559
|
+
"is_in_the_future",
|
|
560
|
+
"is_true",
|
|
561
|
+
"is_false",
|
|
562
|
+
"is_truthy",
|
|
563
|
+
"is_falsey",
|
|
564
|
+
"is_greater_than",
|
|
565
|
+
"is_less_than",
|
|
566
|
+
"is_greater_than_or_equal_to",
|
|
567
|
+
"is_less_than_or_equal_to",
|
|
568
|
+
"matches_regex",
|
|
569
|
+
"does_not_match_regex"
|
|
570
|
+
];
|
|
545
571
|
function defineConnection(config = {}) {
|
|
546
572
|
return { kind: DEFINE_KINDS.connection, ...config };
|
|
547
573
|
}
|
|
@@ -603,32 +629,44 @@ function collectRefs(value, out) {
|
|
|
603
629
|
Object.values(value).forEach((item) => collectRefs(item, out));
|
|
604
630
|
}
|
|
605
631
|
}
|
|
632
|
+
var CONDITIONAL_PATHS_ID = "flow-control_action_conditional-paths";
|
|
633
|
+
var APPROVAL_ID = "flow-control_action_request-approval";
|
|
634
|
+
var BRANCHING_ACTION_IDS = /* @__PURE__ */ new Set([
|
|
635
|
+
CONDITIONAL_PATHS_ID,
|
|
636
|
+
"flow-control_action_manually-decide-paths",
|
|
637
|
+
APPROVAL_ID
|
|
638
|
+
]);
|
|
639
|
+
var PATH_CONDITION_SET = new Set(PATH_CONDITIONS);
|
|
640
|
+
var SINGLE_REF_PATTERN = /^={{step:[^}]*}}$/;
|
|
641
|
+
function collectKeys(steps, seen) {
|
|
642
|
+
for (const step of steps) {
|
|
643
|
+
if (step.key !== void 0) {
|
|
644
|
+
if (!STEP_KEY_PATTERN.test(step.key) || step.key === TRIGGER_KEY) {
|
|
645
|
+
throw new Error(
|
|
646
|
+
`Step key "${step.key}" must start with a letter, use letters, digits, - or _, and not be "${TRIGGER_KEY}".`
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
if (seen.has(step.key)) {
|
|
650
|
+
throw new Error(`Step key "${step.key}" is used twice.`);
|
|
651
|
+
}
|
|
652
|
+
seen.add(step.key);
|
|
653
|
+
}
|
|
654
|
+
for (const path of step.paths ?? []) collectKeys(path.steps ?? [], seen);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
606
657
|
function assertStepRefs(config) {
|
|
607
658
|
const triggerId = config.trigger?.id.trim() ?? MANUAL_TRIGGER_ID;
|
|
608
659
|
const triggerFields = triggerId === MANUAL_TRIGGER_ID ? new Set((config.trigger?.inputs ?? []).map((f) => f.id.trim())) : void 0;
|
|
609
660
|
const allKeys = /* @__PURE__ */ new Set();
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
if (!STEP_KEY_PATTERN.test(step.key) || step.key === TRIGGER_KEY) {
|
|
613
|
-
throw new Error(
|
|
614
|
-
`Step key "${step.key}" must start with a letter, use letters, digits, - or _, and not be "${TRIGGER_KEY}".`
|
|
615
|
-
);
|
|
616
|
-
}
|
|
617
|
-
if (allKeys.has(step.key)) {
|
|
618
|
-
throw new Error(`Step key "${step.key}" is used twice.`);
|
|
619
|
-
}
|
|
620
|
-
allKeys.add(step.key);
|
|
621
|
-
}
|
|
622
|
-
const earlier = /* @__PURE__ */ new Set([TRIGGER_KEY]);
|
|
623
|
-
config.steps.forEach((step, index) => {
|
|
661
|
+
collectKeys(config.steps, allKeys);
|
|
662
|
+
const checkRefs = (value, earlier, where) => {
|
|
624
663
|
const refs = [];
|
|
625
|
-
collectRefs(
|
|
626
|
-
const where = `Step "${step.key ?? step.name ?? index + 1}"`;
|
|
664
|
+
collectRefs(value, refs);
|
|
627
665
|
for (const [key = "", ...path] of refs) {
|
|
628
666
|
const shown = `={{step:${[key, ...path].join(",")}}}`;
|
|
629
667
|
if (!earlier.has(key)) {
|
|
630
668
|
throw new Error(
|
|
631
|
-
allKeys.has(key) ? `${where}: ${shown} refers to itself or a
|
|
669
|
+
allKeys.has(key) ? `${where}: ${shown} refers to itself, a later step, or a step on another path. Use the trigger or an earlier step on the same path.` : `${where}: ${shown} names unknown key "${key}". Use "trigger" or an earlier step's key.`
|
|
632
670
|
);
|
|
633
671
|
}
|
|
634
672
|
if (key === TRIGGER_KEY && triggerFields && !triggerFields.has(path[0] ?? "")) {
|
|
@@ -637,8 +675,54 @@ function assertStepRefs(config) {
|
|
|
637
675
|
);
|
|
638
676
|
}
|
|
639
677
|
}
|
|
640
|
-
|
|
641
|
-
|
|
678
|
+
};
|
|
679
|
+
const checkChain = (steps, visible) => {
|
|
680
|
+
const earlier = new Set(visible);
|
|
681
|
+
steps.forEach((step, index) => {
|
|
682
|
+
const where = `Step "${step.key ?? step.name ?? index + 1}"`;
|
|
683
|
+
checkRefs([step.use?.input, step.input], earlier, where);
|
|
684
|
+
if (step.key) earlier.add(step.key);
|
|
685
|
+
if (!step.paths?.length) return;
|
|
686
|
+
const actionId = step.use ? resolveActionId(step.use) : "";
|
|
687
|
+
if (!BRANCHING_ACTION_IDS.has(actionId)) {
|
|
688
|
+
throw new Error(`${where}: paths only work on ${[...BRANCHING_ACTION_IDS].join(", ")}.`);
|
|
689
|
+
}
|
|
690
|
+
if (index !== steps.length - 1) {
|
|
691
|
+
throw new Error(
|
|
692
|
+
`${where}: a step with paths must be the last step in its list. Put later steps inside each path.`
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
if (actionId === APPROVAL_ID && step.paths.length > 2) {
|
|
696
|
+
throw new Error(`${where}: Request Approval takes at most two paths (approved, then rejected).`);
|
|
697
|
+
}
|
|
698
|
+
const labels = /* @__PURE__ */ new Set();
|
|
699
|
+
for (const path of step.paths) {
|
|
700
|
+
const label = path?.label?.trim();
|
|
701
|
+
if (!label) throw new Error(`${where}: every path needs a label.`);
|
|
702
|
+
if (labels.has(label)) throw new Error(`${where}: path label "${label}" is used twice.`);
|
|
703
|
+
labels.add(label);
|
|
704
|
+
if (path.when !== void 0 && actionId !== CONDITIONAL_PATHS_ID) {
|
|
705
|
+
throw new Error(`${where}: "when" only works on Conditional Paths.`);
|
|
706
|
+
}
|
|
707
|
+
for (const condition of (path.when ?? []).flat()) {
|
|
708
|
+
if (!SINGLE_REF_PATTERN.test(condition?.field?.trim() ?? "")) {
|
|
709
|
+
throw new Error(
|
|
710
|
+
`${where}, path "${label}": a condition's field must be one ref.trigger(...) or ref.step(...).`
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
if (!PATH_CONDITION_SET.has(condition.condition)) {
|
|
714
|
+
throw new Error(
|
|
715
|
+
`${where}, path "${label}": condition "${condition.condition}" is not supported. Use one of: ${PATH_CONDITIONS.join(", ")}.`
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
checkRefs(path.when, earlier, `${where}, path "${label}"`);
|
|
720
|
+
if (!path.steps?.length) throw new Error(`${where}: path "${label}" needs at least one step.`);
|
|
721
|
+
checkChain(path.steps, earlier);
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
};
|
|
725
|
+
checkChain(config.steps, /* @__PURE__ */ new Set([TRIGGER_KEY]));
|
|
642
726
|
}
|
|
643
727
|
function defineWorkflow(config) {
|
|
644
728
|
if (!config.slug?.trim()) {
|
|
@@ -1937,6 +2021,11 @@ function stepFromDefinition(step) {
|
|
|
1937
2021
|
...step.name ? { name: step.name } : {}
|
|
1938
2022
|
};
|
|
1939
2023
|
}
|
|
2024
|
+
if (step.paths?.length) {
|
|
2025
|
+
throw new Error(
|
|
2026
|
+
"runs.start runs straight lines only. Deploy workflows with paths, then execute them."
|
|
2027
|
+
);
|
|
2028
|
+
}
|
|
1940
2029
|
const use = step.use;
|
|
1941
2030
|
const input = {
|
|
1942
2031
|
...use.input ?? {},
|
|
@@ -2169,7 +2258,14 @@ function stepToUpsertInput(step) {
|
|
|
2169
2258
|
...step.input ?? {}
|
|
2170
2259
|
},
|
|
2171
2260
|
name: step.name ?? use.name,
|
|
2172
|
-
description: use.description
|
|
2261
|
+
description: use.description,
|
|
2262
|
+
...step.paths?.length ? {
|
|
2263
|
+
paths: step.paths.map((path) => ({
|
|
2264
|
+
label: path.label,
|
|
2265
|
+
...path.when ? { when: path.when } : {},
|
|
2266
|
+
steps: path.steps.map(stepToUpsertInput)
|
|
2267
|
+
}))
|
|
2268
|
+
} : {}
|
|
2173
2269
|
};
|
|
2174
2270
|
}
|
|
2175
2271
|
function workflowDefinitionToUpsert(def) {
|
|
@@ -2397,6 +2493,7 @@ exports.HttpClient = HttpClient;
|
|
|
2397
2493
|
exports.KnowledgeResource = KnowledgeResource;
|
|
2398
2494
|
exports.LunnoaApiError = LunnoaApiError;
|
|
2399
2495
|
exports.LunnoaClient = LunnoaClient;
|
|
2496
|
+
exports.PATH_CONDITIONS = PATH_CONDITIONS;
|
|
2400
2497
|
exports.QueueItemsResource = QueueItemsResource;
|
|
2401
2498
|
exports.QueuesResource = QueuesResource;
|
|
2402
2499
|
exports.RunsResource = RunsResource;
|