@gravity-rail/sdk 0.14.0 → 0.16.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/dist/agui.cjs +13 -1
- package/dist/agui.cjs.map +1 -1
- package/dist/agui.d.cts +5 -1
- package/dist/agui.d.ts +5 -1
- package/dist/agui.js +12 -1
- package/dist/agui.js.map +1 -1
- package/dist/{chunk-V7ZKEH4V.js → chunk-2YLKG4TT.js} +1 -1
- package/dist/chunk-2YLKG4TT.js.map +1 -0
- package/dist/{chunk-K4MDFGMO.js → chunk-4B7T6MBH.js} +267 -8
- package/dist/chunk-4B7T6MBH.js.map +1 -0
- package/dist/{client-CKudWmUT.d.cts → client-3xYGmF3t.d.ts} +1335 -18
- package/dist/{client-EAvh7w0y.d.ts → client-BhO_UFFz.d.cts} +1335 -18
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +593 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +164 -9
- package/dist/index.d.ts +164 -9
- package/dist/index.js +334 -23
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +296 -7
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +301 -6
- package/dist/internal.d.ts +301 -6
- package/dist/internal.js +35 -2
- package/dist/internal.js.map +1 -1
- package/dist/{revision-state-BUBt9Rir.d.ts → revision-state-Dma10N9s.d.ts} +23 -3
- package/dist/{revision-state-CY4LBdfa.d.cts → revision-state-Dx8gCQIj.d.cts} +23 -3
- package/dist/schemas.cjs +44 -21
- package/dist/schemas.cjs.map +1 -1
- package/dist/schemas.d.cts +54 -23
- package/dist/schemas.d.ts +54 -23
- package/dist/schemas.js +42 -21
- package/dist/schemas.js.map +1 -1
- package/dist/{tasks-iRrM4SaF.d.cts → tasks-vupYoJgG.d.cts} +82 -15
- package/dist/{tasks-iRrM4SaF.d.ts → tasks-vupYoJgG.d.ts} +82 -15
- package/package.json +2 -2
- package/dist/chunk-K4MDFGMO.js.map +0 -1
- package/dist/chunk-V7ZKEH4V.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
PIDS_SOURCES,
|
|
66
66
|
POSITIVE_RATING_THRESHOLD,
|
|
67
67
|
ProductType,
|
|
68
|
+
PromoCodeStatus,
|
|
68
69
|
QUERY_VALUELESS_OPS,
|
|
69
70
|
QueriesApi,
|
|
70
71
|
REALTIME_MODEL_CUSTOM,
|
|
@@ -98,6 +99,7 @@ import {
|
|
|
98
99
|
TemplatesApi,
|
|
99
100
|
ToolkitState,
|
|
100
101
|
WIDGET_SLUGS,
|
|
102
|
+
WORKFLOW_IMPLICIT_USE_SCOPE,
|
|
101
103
|
WorkflowAccessWarningResourceType,
|
|
102
104
|
WorkspaceFeature,
|
|
103
105
|
WorkspaceProvisionStatus,
|
|
@@ -131,9 +133,12 @@ import {
|
|
|
131
133
|
isRegistryInitialized,
|
|
132
134
|
isSMSDeliveryFailureStatus,
|
|
133
135
|
requiresAssistantParticipant,
|
|
136
|
+
roleCanUseWorkflow,
|
|
137
|
+
roleImplicitWorkflowUseScope,
|
|
138
|
+
roleWorkflowAccess,
|
|
134
139
|
usesBuiltinAssistant,
|
|
135
140
|
validateFeatureDependencies
|
|
136
|
-
} from "./chunk-
|
|
141
|
+
} from "./chunk-4B7T6MBH.js";
|
|
137
142
|
import {
|
|
138
143
|
AttendeeResponseStatus,
|
|
139
144
|
AttendeeStatus,
|
|
@@ -148,7 +153,7 @@ import {
|
|
|
148
153
|
DataSensitivity,
|
|
149
154
|
DataTypeRecordScope,
|
|
150
155
|
IndexStatus
|
|
151
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-2YLKG4TT.js";
|
|
152
157
|
import {
|
|
153
158
|
ApiError,
|
|
154
159
|
BaseApiClient,
|
|
@@ -191,6 +196,14 @@ var WorkspaceBuilderResource = class {
|
|
|
191
196
|
}
|
|
192
197
|
return this._uuid;
|
|
193
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* True for resources the server creates on our behalf (currently a
|
|
201
|
+
* journey's `Start` step). They are kept in the resource list so edges can
|
|
202
|
+
* reference them, but they are never created, printed, or counted.
|
|
203
|
+
*/
|
|
204
|
+
get isImplicit() {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
194
207
|
matchKey() {
|
|
195
208
|
return void 0;
|
|
196
209
|
}
|
|
@@ -213,6 +226,19 @@ function resolveRefValue(value) {
|
|
|
213
226
|
}
|
|
214
227
|
return out;
|
|
215
228
|
}
|
|
229
|
+
function resolveIdRefs(value) {
|
|
230
|
+
return resolveIdRefValue(value);
|
|
231
|
+
}
|
|
232
|
+
function resolveIdRefValue(value) {
|
|
233
|
+
if (value instanceof WorkspaceBuilderResource) return value.id;
|
|
234
|
+
if (Array.isArray(value)) return value.map(resolveIdRefValue);
|
|
235
|
+
if (!isPlainRecord(value)) return value;
|
|
236
|
+
const out = {};
|
|
237
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
238
|
+
out[key] = resolveIdRefValue(nestedValue);
|
|
239
|
+
}
|
|
240
|
+
return out;
|
|
241
|
+
}
|
|
216
242
|
|
|
217
243
|
// src/workspace-builder/automation.ts
|
|
218
244
|
var MemberFilterBuilder = class extends WorkspaceBuilderResource {
|
|
@@ -226,7 +252,12 @@ var MemberFilterBuilder = class extends WorkspaceBuilderResource {
|
|
|
226
252
|
description;
|
|
227
253
|
/** Query-engine predicate (JSON IR) authored on MemberFilter.query. */
|
|
228
254
|
query = null;
|
|
229
|
-
/**
|
|
255
|
+
/**
|
|
256
|
+
* Set the filter's query-engine predicate (JSON IR).
|
|
257
|
+
*
|
|
258
|
+
* Anywhere the IR wants a numeric id you may pass the builder that will own
|
|
259
|
+
* it (e.g. a label in a `member.labelId` value); refs resolve at apply time.
|
|
260
|
+
*/
|
|
230
261
|
setQuery(query) {
|
|
231
262
|
this.query = query;
|
|
232
263
|
return this;
|
|
@@ -235,10 +266,12 @@ var MemberFilterBuilder = class extends WorkspaceBuilderResource {
|
|
|
235
266
|
return `MemberFilter: ${this.name}${this.query ? " (query)" : ""}`;
|
|
236
267
|
}
|
|
237
268
|
async apply(client) {
|
|
269
|
+
if (this._existed) return;
|
|
238
270
|
const payload = {
|
|
239
271
|
name: this.name,
|
|
240
272
|
description: this.description,
|
|
241
|
-
|
|
273
|
+
// Builder refs inside the IR become ids here; see resolveIdRefs.
|
|
274
|
+
query: resolveIdRefs(this.query)
|
|
242
275
|
};
|
|
243
276
|
const result = await client.createMemberFilter(payload);
|
|
244
277
|
this._id = result.id;
|
|
@@ -533,35 +566,134 @@ var MemberLabelBuilder = class extends WorkspaceBuilderResource {
|
|
|
533
566
|
};
|
|
534
567
|
|
|
535
568
|
// src/workspace-builder/journeys.ts
|
|
569
|
+
var SECONDS_PER_DAY = 86400;
|
|
570
|
+
function edgeKey(parentId, childId) {
|
|
571
|
+
return `${parentId}:${childId}`;
|
|
572
|
+
}
|
|
573
|
+
function edgeCondition(options) {
|
|
574
|
+
const clauses = [];
|
|
575
|
+
if (options.afterDays !== void 0) {
|
|
576
|
+
clauses.push(`days_since(parent_step.completed_at) >= ${options.afterDays}`);
|
|
577
|
+
}
|
|
578
|
+
if (options.when) clauses.push(`(${options.when})`);
|
|
579
|
+
if (!clauses.length) return void 0;
|
|
580
|
+
return clauses.join(" && ");
|
|
581
|
+
}
|
|
536
582
|
var JourneyStepBuilder = class extends WorkspaceBuilderResource {
|
|
537
583
|
// journey-decoupling Phase 7: a Journey step no longer links to a Workflow.
|
|
538
584
|
// A step nudges via EventRule actions instead of running a Workflow, so the
|
|
539
585
|
// builder no longer accepts or emits a workflow reference.
|
|
540
|
-
constructor(name, journey, order = 0, description = "") {
|
|
586
|
+
constructor(name, journey, order = 0, description = "", options = {}) {
|
|
541
587
|
super();
|
|
542
588
|
this.name = name;
|
|
543
589
|
this.journey = journey;
|
|
544
590
|
this.order = order;
|
|
545
591
|
this.description = description;
|
|
592
|
+
this.assigneeId = options.assigneeId;
|
|
593
|
+
this.posX = options.posX;
|
|
594
|
+
this.posY = options.posY;
|
|
546
595
|
}
|
|
547
596
|
name;
|
|
548
597
|
journey;
|
|
549
598
|
order;
|
|
550
599
|
description;
|
|
551
600
|
connections = [];
|
|
552
|
-
|
|
553
|
-
|
|
601
|
+
rules = [];
|
|
602
|
+
assigneeId;
|
|
603
|
+
posX;
|
|
604
|
+
posY;
|
|
605
|
+
/** Wire an edge to `child` and return the CHILD, so chains read linearly. */
|
|
606
|
+
connectsTo(child, options = {}) {
|
|
607
|
+
if (child === this) {
|
|
608
|
+
throw new Error(`Journey step '${this.name}' cannot connect to itself`);
|
|
609
|
+
}
|
|
610
|
+
const abandonSeconds = options.abandonAfterDays !== void 0 ? options.abandonAfterDays * SECONDS_PER_DAY : options.timeoutSeconds;
|
|
611
|
+
this.connections.push({
|
|
612
|
+
parent: this,
|
|
613
|
+
child,
|
|
614
|
+
condition: edgeCondition(options),
|
|
615
|
+
required: options.required ?? false,
|
|
616
|
+
timeoutSeconds: abandonSeconds,
|
|
617
|
+
order: options.order,
|
|
618
|
+
filterId: options.filterId
|
|
619
|
+
});
|
|
620
|
+
return child;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Attach a `JOURNEY_STEP_EXECUTE` action — what this step actually DOES
|
|
624
|
+
* when a member reaches it. A step with no rules is inert: the member
|
|
625
|
+
* lands on it, nothing is sent, and the journey moves on.
|
|
626
|
+
*/
|
|
627
|
+
onExecute(actionType, params = {}, options = {}) {
|
|
628
|
+
this.rules.push({
|
|
629
|
+
uuid: crypto.randomUUID(),
|
|
630
|
+
actionType,
|
|
631
|
+
actionParams: params,
|
|
632
|
+
options
|
|
633
|
+
});
|
|
554
634
|
return this;
|
|
555
635
|
}
|
|
636
|
+
/**
|
|
637
|
+
* Text the member. `phoneNumberUUID` is a workspace PhoneNumber with SMS
|
|
638
|
+
* enabled. Pass `workflowUUID` to start an SMS workflow chat, or
|
|
639
|
+
* `messageTemplate` for a one-off send.
|
|
640
|
+
*/
|
|
641
|
+
sendsSms(params, options = {}) {
|
|
642
|
+
return this.onExecute("sms:send" /* SMS_SEND */, params, options);
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Call the member. Both the workspace PhoneNumber uuid (voice enabled) and
|
|
646
|
+
* the Workflow uuid that drives the call are required.
|
|
647
|
+
*/
|
|
648
|
+
callsMember(params, options = {}) {
|
|
649
|
+
return this.onExecute("phone:call" /* PHONE_CALL */, params, options);
|
|
650
|
+
}
|
|
651
|
+
/** Email the member from a workspace inbox. */
|
|
652
|
+
sendsEmail(params, options = {}) {
|
|
653
|
+
return this.onExecute("email:send" /* EMAIL_SEND */, params, options);
|
|
654
|
+
}
|
|
655
|
+
/** Label the member on arrival — pass label builders, not ids. */
|
|
656
|
+
addsLabels(labels, options = {}) {
|
|
657
|
+
return this.onExecute(
|
|
658
|
+
"member:label" /* MEMBER_LABEL_ACTION */,
|
|
659
|
+
{ addLabelIds: labels },
|
|
660
|
+
options
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
/** True once this step has something to do when a member reaches it. */
|
|
664
|
+
get hasOutreach() {
|
|
665
|
+
return this.rules.length > 0;
|
|
666
|
+
}
|
|
667
|
+
eventRuleInputs() {
|
|
668
|
+
return this.rules.map((rule) => ({
|
|
669
|
+
uuid: rule.uuid,
|
|
670
|
+
eventType: "journey_step:execute" /* JOURNEY_STEP_EXECUTE */,
|
|
671
|
+
actionType: rule.actionType,
|
|
672
|
+
actionParams: resolveRefs(rule.actionParams),
|
|
673
|
+
...rule.options.name ? { name: rule.options.name } : {},
|
|
674
|
+
...rule.options.when ? { conditions: rule.options.when } : {},
|
|
675
|
+
...rule.options.delaySeconds ? { delay: rule.options.delaySeconds } : {},
|
|
676
|
+
active: rule.options.active ?? true
|
|
677
|
+
}));
|
|
678
|
+
}
|
|
556
679
|
planLine() {
|
|
557
|
-
|
|
680
|
+
const actions = this.rules.map((rule) => rule.actionType).join(" + ");
|
|
681
|
+
return `Step: ${this.name}${actions ? ` (${actions})` : ""}`;
|
|
558
682
|
}
|
|
559
683
|
async apply(client) {
|
|
684
|
+
if (this._existed) return;
|
|
560
685
|
if (this.journey._id === void 0) return;
|
|
686
|
+
const rules = this.eventRuleInputs();
|
|
561
687
|
const payload = {
|
|
562
688
|
name: this.name,
|
|
563
689
|
description: this.description,
|
|
564
|
-
order: this.order
|
|
690
|
+
order: this.order,
|
|
691
|
+
...this.assigneeId !== void 0 ? { assigneeId: this.assigneeId } : {},
|
|
692
|
+
...this.posX !== void 0 ? { posX: this.posX } : {},
|
|
693
|
+
...this.posY !== void 0 ? { posY: this.posY } : {},
|
|
694
|
+
// Saved atomically with the step, so a partial failure cannot leave
|
|
695
|
+
// an inert step behind.
|
|
696
|
+
...rules.length ? { eventRules: rules } : {}
|
|
565
697
|
};
|
|
566
698
|
const result = await client.createStep(this.journey._id, payload);
|
|
567
699
|
this._id = result.id;
|
|
@@ -569,26 +701,59 @@ var JourneyStepBuilder = class extends WorkspaceBuilderResource {
|
|
|
569
701
|
this._created = true;
|
|
570
702
|
}
|
|
571
703
|
};
|
|
704
|
+
var StartStepBuilder = class extends JourneyStepBuilder {
|
|
705
|
+
get isImplicit() {
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
708
|
+
planLine() {
|
|
709
|
+
return "Step: Start (auto-created)";
|
|
710
|
+
}
|
|
711
|
+
async apply() {
|
|
712
|
+
}
|
|
713
|
+
};
|
|
572
714
|
var JourneyBuilder = class extends WorkspaceBuilderResource {
|
|
573
715
|
constructor(name, options = {}) {
|
|
574
716
|
super();
|
|
575
717
|
this.name = name;
|
|
576
718
|
this.description = options.description ?? "";
|
|
719
|
+
this.start = new StartStepBuilder("Start", this, 0);
|
|
720
|
+
this.steps.push(this.start);
|
|
577
721
|
}
|
|
578
722
|
name;
|
|
579
723
|
description;
|
|
580
724
|
steps = [];
|
|
581
725
|
goals = [];
|
|
726
|
+
/** The auto-created `Start` step — connect the first real step to it. */
|
|
727
|
+
start;
|
|
728
|
+
/** `parentId:childId` for every edge the server already has (see `adopt`). */
|
|
729
|
+
existingEdges = /* @__PURE__ */ new Set();
|
|
582
730
|
step(name, options = {}) {
|
|
583
731
|
const step = new JourneyStepBuilder(
|
|
584
732
|
name,
|
|
585
733
|
this,
|
|
586
|
-
options.order ??
|
|
587
|
-
options.description ?? ""
|
|
734
|
+
options.order ?? this.steps.length,
|
|
735
|
+
options.description ?? "",
|
|
736
|
+
options
|
|
588
737
|
);
|
|
589
738
|
this.steps.push(step);
|
|
590
739
|
return step;
|
|
591
740
|
}
|
|
741
|
+
/**
|
|
742
|
+
* Declare a linear cadence: `Start → steps[0] → steps[1] → …`, each edge
|
|
743
|
+
* carrying the matching entry from `spacing`.
|
|
744
|
+
*
|
|
745
|
+
* Chaining is not optional polish. A step created with no incoming edge is
|
|
746
|
+
* a ROOT, and every root fires the moment a member enrols — a "three
|
|
747
|
+
* follow-ups over four days" journey built without edges sends all three
|
|
748
|
+
* at once.
|
|
749
|
+
*/
|
|
750
|
+
sequence(steps, spacing = []) {
|
|
751
|
+
let parent = this.start;
|
|
752
|
+
steps.forEach((step, index) => {
|
|
753
|
+
parent = parent.connectsTo(step, spacing[index] ?? {});
|
|
754
|
+
});
|
|
755
|
+
return this;
|
|
756
|
+
}
|
|
592
757
|
goal(name, options = {}) {
|
|
593
758
|
this.goals.push({
|
|
594
759
|
name,
|
|
@@ -596,17 +761,85 @@ var JourneyBuilder = class extends WorkspaceBuilderResource {
|
|
|
596
761
|
step: options.step,
|
|
597
762
|
completionCel: options.completionCel ?? options.completion_cel,
|
|
598
763
|
value: options.value,
|
|
599
|
-
order: options.order ??
|
|
764
|
+
order: options.order ?? this.goals.length
|
|
600
765
|
});
|
|
601
766
|
return this;
|
|
602
767
|
}
|
|
768
|
+
/**
|
|
769
|
+
* Authoring problems that make a journey silently misbehave at runtime.
|
|
770
|
+
* Reported at plan/preview time, before anything is written.
|
|
771
|
+
*/
|
|
772
|
+
validate() {
|
|
773
|
+
const problems = [];
|
|
774
|
+
const withParents = /* @__PURE__ */ new Set();
|
|
775
|
+
for (const step of this.steps) {
|
|
776
|
+
for (const connection of step.connections) withParents.add(connection.child);
|
|
777
|
+
}
|
|
778
|
+
for (const step of this.steps) {
|
|
779
|
+
if (step === this.start) continue;
|
|
780
|
+
if (!withParents.has(step)) {
|
|
781
|
+
problems.push(
|
|
782
|
+
`step '${step.name}' has no incoming edge \u2014 it is a root and fires for every member the moment they enrol. Connect it from journey.start or a prior step.`
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
if (!step.hasOutreach) {
|
|
786
|
+
problems.push(
|
|
787
|
+
`step '${step.name}' has no JOURNEY_STEP_EXECUTE action \u2014 a member reaching it gets nothing. Add one with .sendsSms / .callsMember / .sendsEmail / .onExecute.`
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
if (!this.goals.length) {
|
|
792
|
+
problems.push(`journey '${this.name}' has no goals \u2014 nothing measures whether it works.`);
|
|
793
|
+
}
|
|
794
|
+
return problems;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Adopt an existing journey, its steps, and its EDGES, matched by name.
|
|
798
|
+
*
|
|
799
|
+
* Re-running a builder script is normal — a program is usually built in
|
|
800
|
+
* stages as provisioning lands — and without adoption the second run would
|
|
801
|
+
* create a duplicate journey and a duplicate set of steps beside the live
|
|
802
|
+
* one, with members enrolled in neither.
|
|
803
|
+
*
|
|
804
|
+
* The edge set is recorded from the server's own `childConnections` rather
|
|
805
|
+
* than inferred from "both steps exist". A first run that created the steps
|
|
806
|
+
* and then failed before writing an edge leaves exactly that state, and
|
|
807
|
+
* inferring would skip the missing edge on every subsequent run — leaving a
|
|
808
|
+
* permanent root step that fires for every member at enrolment, silently.
|
|
809
|
+
* The journey detail read eager-loads connections, so the real answer is
|
|
810
|
+
* already in hand; there is no reason to guess.
|
|
811
|
+
*/
|
|
812
|
+
adopt(existing) {
|
|
813
|
+
super.adopt(existing);
|
|
814
|
+
const existingSteps = existing.steps ?? [];
|
|
815
|
+
const byName = new Map(existingSteps.map((step) => [step.name, step]));
|
|
816
|
+
const startStep = existingSteps.find((step) => step.id === existing.startStepId) ?? byName.get("Start");
|
|
817
|
+
if (startStep) this.start.adopt(startStep);
|
|
818
|
+
for (const step of this.steps) {
|
|
819
|
+
if (step === this.start) continue;
|
|
820
|
+
const match = byName.get(step.name);
|
|
821
|
+
if (match) step.adopt(match);
|
|
822
|
+
}
|
|
823
|
+
for (const step of existingSteps) {
|
|
824
|
+
for (const edge of step.childConnections ?? []) {
|
|
825
|
+
this.existingEdges.add(edgeKey(edge.parentStepId, edge.childStepId));
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
/** True when the server already has this exact edge. */
|
|
830
|
+
hasEdge(parent, child) {
|
|
831
|
+
if (parent._id === void 0 || child._id === void 0) return false;
|
|
832
|
+
return this.existingEdges.has(edgeKey(parent._id, child._id));
|
|
833
|
+
}
|
|
603
834
|
planLine() {
|
|
604
835
|
const parts = [];
|
|
605
|
-
|
|
836
|
+
const real = this.steps.filter((step) => step !== this.start);
|
|
837
|
+
if (real.length) parts.push(`${real.length} steps`);
|
|
606
838
|
if (this.goals.length) parts.push(`${this.goals.length} goals`);
|
|
607
839
|
return `Journey: ${this.name}${parts.length ? ` (${parts.join(", ")})` : ""}`;
|
|
608
840
|
}
|
|
609
841
|
async apply(client) {
|
|
842
|
+
if (this._existed) return;
|
|
610
843
|
const result = await client.createJourney({
|
|
611
844
|
name: this.name,
|
|
612
845
|
description: this.description
|
|
@@ -614,6 +847,15 @@ var JourneyBuilder = class extends WorkspaceBuilderResource {
|
|
|
614
847
|
this._id = result.id;
|
|
615
848
|
this._uuid = result.uuid;
|
|
616
849
|
this._created = true;
|
|
850
|
+
const startStep = (result.steps ?? []).find(
|
|
851
|
+
(step) => step.id === result.startStepId || step.name === "Start"
|
|
852
|
+
);
|
|
853
|
+
if (!startStep) {
|
|
854
|
+
throw new Error(
|
|
855
|
+
`Journey '${this.name}' was created without a Start step; edges from journey.start cannot be wired.`
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
this.start.adopt(startStep);
|
|
617
859
|
}
|
|
618
860
|
};
|
|
619
861
|
function buildJourneyConnectionPayload(connection) {
|
|
@@ -623,7 +865,9 @@ function buildJourneyConnectionPayload(connection) {
|
|
|
623
865
|
childStepUuid: connection.child._uuid,
|
|
624
866
|
...connection.condition ? { celCondition: connection.condition } : {},
|
|
625
867
|
...connection.required ? { required: true } : {},
|
|
626
|
-
...connection.timeoutSeconds ? { timeoutSeconds: connection.timeoutSeconds } : {}
|
|
868
|
+
...connection.timeoutSeconds ? { timeoutSeconds: connection.timeoutSeconds } : {},
|
|
869
|
+
...connection.order !== void 0 ? { order: connection.order } : {},
|
|
870
|
+
...connection.filterId !== void 0 ? { filterId: connection.filterId } : {}
|
|
627
871
|
};
|
|
628
872
|
}
|
|
629
873
|
function buildJourneyGoalPayload(goal) {
|
|
@@ -909,6 +1153,15 @@ var PHASES = /* @__PURE__ */ new Map([
|
|
|
909
1153
|
[JourneyBuilder, 7],
|
|
910
1154
|
[JourneyStepBuilder, 8]
|
|
911
1155
|
]);
|
|
1156
|
+
function phaseFor(resource) {
|
|
1157
|
+
let ctor = resource.constructor;
|
|
1158
|
+
while (ctor) {
|
|
1159
|
+
const phase = PHASES.get(ctor);
|
|
1160
|
+
if (phase !== void 0) return phase;
|
|
1161
|
+
ctor = Object.getPrototypeOf(ctor);
|
|
1162
|
+
}
|
|
1163
|
+
return 99;
|
|
1164
|
+
}
|
|
912
1165
|
var WorkspaceBuilder = class {
|
|
913
1166
|
constructor(client) {
|
|
914
1167
|
this.client = client;
|
|
@@ -971,7 +1224,8 @@ var WorkspaceBuilder = class {
|
|
|
971
1224
|
${"=".repeat(50)}`);
|
|
972
1225
|
writeLine("Plan");
|
|
973
1226
|
writeLine("=".repeat(50));
|
|
974
|
-
|
|
1227
|
+
const declared = resources.filter((resource) => !resource.isImplicit);
|
|
1228
|
+
for (const resource of declared) {
|
|
975
1229
|
writeLine(` + ${resource.planLine()}`);
|
|
976
1230
|
}
|
|
977
1231
|
const wiring = this.collectWiringSummary(resources);
|
|
@@ -979,8 +1233,9 @@ ${"=".repeat(50)}`);
|
|
|
979
1233
|
writeLine("\n Wiring:");
|
|
980
1234
|
for (const line of wiring) writeLine(` ${line}`);
|
|
981
1235
|
}
|
|
1236
|
+
this.reportJourneyWarnings();
|
|
982
1237
|
writeLine(`
|
|
983
|
-
Total: ${
|
|
1238
|
+
Total: ${declared.length} resources, ${wiring.length} connections`);
|
|
984
1239
|
writeLine(`${"=".repeat(50)}
|
|
985
1240
|
`);
|
|
986
1241
|
}
|
|
@@ -991,7 +1246,8 @@ ${"=".repeat(50)}`);
|
|
|
991
1246
|
${"=".repeat(50)}`);
|
|
992
1247
|
writeLine("Preview");
|
|
993
1248
|
writeLine("=".repeat(50));
|
|
994
|
-
|
|
1249
|
+
const declared = resources.filter((resource) => !resource.isImplicit);
|
|
1250
|
+
for (const resource of declared) {
|
|
995
1251
|
if (resource._existed) {
|
|
996
1252
|
writeLine(` = ${resource.planLine()} (exists, id=${resource._id})`);
|
|
997
1253
|
} else {
|
|
@@ -1003,8 +1259,9 @@ ${"=".repeat(50)}`);
|
|
|
1003
1259
|
writeLine("\n Wiring:");
|
|
1004
1260
|
for (const line of wiring) writeLine(` ${line}`);
|
|
1005
1261
|
}
|
|
1006
|
-
|
|
1007
|
-
const
|
|
1262
|
+
this.reportJourneyWarnings();
|
|
1263
|
+
const toCreate = declared.filter((resource) => !resource._existed);
|
|
1264
|
+
const existing = declared.filter((resource) => resource._existed);
|
|
1008
1265
|
writeLine(
|
|
1009
1266
|
`
|
|
1010
1267
|
Total: ${toCreate.length} to create, ${existing.length} existing, ${wiring.length} connections`
|
|
@@ -1012,6 +1269,18 @@ ${"=".repeat(50)}`);
|
|
|
1012
1269
|
writeLine(`${"=".repeat(50)}
|
|
1013
1270
|
`);
|
|
1014
1271
|
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Print journey authoring problems that only bite at runtime — a step with
|
|
1274
|
+
* no incoming edge fires for every member at enrolment, and a step with no
|
|
1275
|
+
* action does nothing at all. Both look fine in the editor, so they are
|
|
1276
|
+
* surfaced before the write rather than discovered from a member's phone.
|
|
1277
|
+
*/
|
|
1278
|
+
reportJourneyWarnings() {
|
|
1279
|
+
const problems = this.resources.filter((resource) => resource instanceof JourneyBuilder).flatMap((journey) => journey.validate());
|
|
1280
|
+
if (!problems.length) return;
|
|
1281
|
+
writeLine("\n Journey warnings:");
|
|
1282
|
+
for (const problem of problems) writeLine(` ! ${problem}`);
|
|
1283
|
+
}
|
|
1015
1284
|
async apply() {
|
|
1016
1285
|
const resources = this.sortedResources();
|
|
1017
1286
|
await this.resolveExisting(resources);
|
|
@@ -1019,6 +1288,7 @@ ${"=".repeat(50)}`);
|
|
|
1019
1288
|
writeLine("Applying...");
|
|
1020
1289
|
for (const resource of resources) {
|
|
1021
1290
|
try {
|
|
1291
|
+
if (resource.isImplicit) continue;
|
|
1022
1292
|
if (resource._existed) {
|
|
1023
1293
|
const key = resourceKey(resource);
|
|
1024
1294
|
summary[key] ??= [];
|
|
@@ -1076,6 +1346,29 @@ Done! Created ${count} resources.`);
|
|
|
1076
1346
|
}
|
|
1077
1347
|
}
|
|
1078
1348
|
}
|
|
1349
|
+
const filterNames = new Map(
|
|
1350
|
+
resources.filter(
|
|
1351
|
+
(resource) => resource instanceof MemberFilterBuilder
|
|
1352
|
+
).map((resource) => [resource.name, resource])
|
|
1353
|
+
);
|
|
1354
|
+
if (filterNames.size) {
|
|
1355
|
+
for (const existing of await this.client.getMemberFilters()) {
|
|
1356
|
+
if (existing.name && filterNames.has(existing.name)) {
|
|
1357
|
+
filterNames.get(existing.name).adopt(existing);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
const journeyNames = new Map(
|
|
1362
|
+
resources.filter((resource) => resource instanceof JourneyBuilder).map((resource) => [resource.name, resource])
|
|
1363
|
+
);
|
|
1364
|
+
if (journeyNames.size) {
|
|
1365
|
+
const existingJourneys = await this.client.getJourneys();
|
|
1366
|
+
for (const existing of existingJourneys.items) {
|
|
1367
|
+
if (!existing.name || !journeyNames.has(existing.name)) continue;
|
|
1368
|
+
const detail = await this.client.getJourney(existing.id);
|
|
1369
|
+
journeyNames.get(existing.name).adopt(detail);
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1079
1372
|
if (!workflowNames.size) return;
|
|
1080
1373
|
const existingWorkflows = await this.client.getWorkflows();
|
|
1081
1374
|
for (const { workflow: existing } of existingWorkflows.items) {
|
|
@@ -1126,9 +1419,7 @@ Done! Created ${count} resources.`);
|
|
|
1126
1419
|
all.push(...resource.steps);
|
|
1127
1420
|
}
|
|
1128
1421
|
}
|
|
1129
|
-
return all.sort(
|
|
1130
|
-
(a, b) => (PHASES.get(a.constructor) ?? 99) - (PHASES.get(b.constructor) ?? 99)
|
|
1131
|
-
);
|
|
1422
|
+
return all.sort((a, b) => phaseFor(a) - phaseFor(b));
|
|
1132
1423
|
}
|
|
1133
1424
|
collectWiringSummary(resources) {
|
|
1134
1425
|
const lines = [];
|
|
@@ -1149,7 +1440,11 @@ Done! Created ${count} resources.`);
|
|
|
1149
1440
|
lines.push(`${rule.actionType} rule on '${resource.name}'`);
|
|
1150
1441
|
} else if (resource instanceof JourneyStepBuilder) {
|
|
1151
1442
|
for (const connection of resource.connections) {
|
|
1152
|
-
|
|
1443
|
+
const guard = connection.condition ? ` [${connection.condition}]` : "";
|
|
1444
|
+
lines.push(`${connection.parent.name} -> ${connection.child.name}${guard}`);
|
|
1445
|
+
}
|
|
1446
|
+
for (const rule of resource.rules) {
|
|
1447
|
+
lines.push(`${rule.actionType} on step '${resource.name}'`);
|
|
1153
1448
|
}
|
|
1154
1449
|
} else if (resource instanceof JourneyBuilder) {
|
|
1155
1450
|
for (const goal of resource.goals) lines.push(`Goal: ${goal.name}`);
|
|
@@ -1265,6 +1560,10 @@ Done! Created ${count} resources.`);
|
|
|
1265
1560
|
if (!(resource instanceof JourneyStepBuilder)) continue;
|
|
1266
1561
|
for (const connection of resource.connections) {
|
|
1267
1562
|
if (resource.journey._id === void 0) continue;
|
|
1563
|
+
if (resource.journey.hasEdge(connection.parent, connection.child)) {
|
|
1564
|
+
writeLine(` Exists: ${connection.parent.name} -> ${connection.child.name}`);
|
|
1565
|
+
continue;
|
|
1566
|
+
}
|
|
1268
1567
|
const payload = buildJourneyConnectionPayload(connection);
|
|
1269
1568
|
if (!payload) continue;
|
|
1270
1569
|
await this.client.createConnection(resource.journey._id, payload);
|
|
@@ -1275,6 +1574,12 @@ Done! Created ${count} resources.`);
|
|
|
1275
1574
|
async applyJourneyGoals(resources) {
|
|
1276
1575
|
for (const resource of resources) {
|
|
1277
1576
|
if (!(resource instanceof JourneyBuilder) || resource._id === void 0) continue;
|
|
1577
|
+
if (resource._existed) {
|
|
1578
|
+
for (const goal of resource.goals) {
|
|
1579
|
+
writeLine(` Skipped (journey already exists): Goal: ${goal.name}`);
|
|
1580
|
+
}
|
|
1581
|
+
continue;
|
|
1582
|
+
}
|
|
1278
1583
|
for (const goal of resource.goals) {
|
|
1279
1584
|
await this.client.createGoal(resource._id, buildJourneyGoalPayload(goal));
|
|
1280
1585
|
writeLine(` Created goal: ${goal.name}`);
|
|
@@ -1575,6 +1880,7 @@ export {
|
|
|
1575
1880
|
PIDS_SOURCES,
|
|
1576
1881
|
POSITIVE_RATING_THRESHOLD,
|
|
1577
1882
|
ProductType,
|
|
1883
|
+
PromoCodeStatus,
|
|
1578
1884
|
QUERY_VALUELESS_OPS,
|
|
1579
1885
|
QueriesApi,
|
|
1580
1886
|
REALTIME_MODEL_CUSTOM,
|
|
@@ -1611,10 +1917,12 @@ export {
|
|
|
1611
1917
|
TemplatesApi,
|
|
1612
1918
|
ToolkitState,
|
|
1613
1919
|
WIDGET_SLUGS,
|
|
1920
|
+
WORKFLOW_IMPLICIT_USE_SCOPE,
|
|
1614
1921
|
WorkflowAccessWarningResourceType,
|
|
1615
1922
|
WorkflowBuilder,
|
|
1616
1923
|
WorkflowAccessWarningResourceType as WorkflowResourceType,
|
|
1617
1924
|
WorkspaceBuilder,
|
|
1925
|
+
WorkspaceBuilderResource,
|
|
1618
1926
|
WorkspaceFeature,
|
|
1619
1927
|
WorkspaceProvisionStatus,
|
|
1620
1928
|
areDependenciesSatisfied,
|
|
@@ -1649,6 +1957,9 @@ export {
|
|
|
1649
1957
|
isSMSDeliveryFailureStatus,
|
|
1650
1958
|
parseOrgAuthChallenge,
|
|
1651
1959
|
requiresAssistantParticipant,
|
|
1960
|
+
roleCanUseWorkflow,
|
|
1961
|
+
roleImplicitWorkflowUseScope,
|
|
1962
|
+
roleWorkflowAccess,
|
|
1652
1963
|
runWorkspaceScript,
|
|
1653
1964
|
usesBuiltinAssistant,
|
|
1654
1965
|
validateFeatureDependencies
|