@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.
Files changed (39) hide show
  1. package/dist/agui.cjs +13 -1
  2. package/dist/agui.cjs.map +1 -1
  3. package/dist/agui.d.cts +5 -1
  4. package/dist/agui.d.ts +5 -1
  5. package/dist/agui.js +12 -1
  6. package/dist/agui.js.map +1 -1
  7. package/dist/{chunk-V7ZKEH4V.js → chunk-2YLKG4TT.js} +1 -1
  8. package/dist/chunk-2YLKG4TT.js.map +1 -0
  9. package/dist/{chunk-K4MDFGMO.js → chunk-4B7T6MBH.js} +267 -8
  10. package/dist/chunk-4B7T6MBH.js.map +1 -0
  11. package/dist/{client-CKudWmUT.d.cts → client-3xYGmF3t.d.ts} +1335 -18
  12. package/dist/{client-EAvh7w0y.d.ts → client-BhO_UFFz.d.cts} +1335 -18
  13. package/dist/helpers.d.cts +2 -2
  14. package/dist/helpers.d.ts +2 -2
  15. package/dist/index.cjs +593 -28
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +164 -9
  18. package/dist/index.d.ts +164 -9
  19. package/dist/index.js +334 -23
  20. package/dist/index.js.map +1 -1
  21. package/dist/internal.cjs +296 -7
  22. package/dist/internal.cjs.map +1 -1
  23. package/dist/internal.d.cts +301 -6
  24. package/dist/internal.d.ts +301 -6
  25. package/dist/internal.js +35 -2
  26. package/dist/internal.js.map +1 -1
  27. package/dist/{revision-state-BUBt9Rir.d.ts → revision-state-Dma10N9s.d.ts} +23 -3
  28. package/dist/{revision-state-CY4LBdfa.d.cts → revision-state-Dx8gCQIj.d.cts} +23 -3
  29. package/dist/schemas.cjs +44 -21
  30. package/dist/schemas.cjs.map +1 -1
  31. package/dist/schemas.d.cts +54 -23
  32. package/dist/schemas.d.ts +54 -23
  33. package/dist/schemas.js +42 -21
  34. package/dist/schemas.js.map +1 -1
  35. package/dist/{tasks-iRrM4SaF.d.cts → tasks-vupYoJgG.d.cts} +82 -15
  36. package/dist/{tasks-iRrM4SaF.d.ts → tasks-vupYoJgG.d.ts} +82 -15
  37. package/package.json +2 -2
  38. package/dist/chunk-K4MDFGMO.js.map +0 -1
  39. 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-K4MDFGMO.js";
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-V7ZKEH4V.js";
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
- /** Set the filter's query-engine predicate (JSON IR). */
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
- query: this.query
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
- connectsTo(child, condition, required = false, timeoutSeconds) {
553
- this.connections.push({ parent: this, child, condition, required, timeoutSeconds });
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
- return `Step: ${this.name}`;
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 ?? 0,
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 ?? 0
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
- if (this.steps.length) parts.push(`${this.steps.length} steps`);
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
- for (const resource of resources) {
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: ${resources.length} resources, ${wiring.length} connections`);
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
- for (const resource of resources) {
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
- const toCreate = resources.filter((resource) => !resource._existed);
1007
- const existing = resources.filter((resource) => resource._existed);
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
- lines.push(`${connection.parent.name} -> ${connection.child.name}`);
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