@gravity-rail/sdk 0.15.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/index.cjs CHANGED
@@ -110,6 +110,7 @@ __export(src_exports, {
110
110
  PIDS_SOURCES: () => PIDS_SOURCES,
111
111
  POSITIVE_RATING_THRESHOLD: () => POSITIVE_RATING_THRESHOLD,
112
112
  ProductType: () => ProductType,
113
+ PromoCodeStatus: () => PromoCodeStatus,
113
114
  QUERY_VALUELESS_OPS: () => QUERY_VALUELESS_OPS,
114
115
  QueriesApi: () => QueriesApi,
115
116
  REALTIME_MODEL_CUSTOM: () => REALTIME_MODEL_CUSTOM,
@@ -151,6 +152,7 @@ __export(src_exports, {
151
152
  WorkflowBuilder: () => WorkflowBuilder,
152
153
  WorkflowResourceType: () => WorkflowAccessWarningResourceType,
153
154
  WorkspaceBuilder: () => WorkspaceBuilder,
155
+ WorkspaceBuilderResource: () => WorkspaceBuilderResource,
154
156
  WorkspaceFeature: () => WorkspaceFeature,
155
157
  WorkspaceProvisionStatus: () => WorkspaceProvisionStatus,
156
158
  areDependenciesSatisfied: () => areDependenciesSatisfied,
@@ -924,6 +926,18 @@ var AIModelsApi = class extends BaseApiClient {
924
926
  const url = queryString ? `ai-models/realtime?${queryString}` : "ai-models/realtime";
925
927
  return this.fetch(url);
926
928
  }
929
+ /**
930
+ * Get the voice presets offered by the simplified voice picker.
931
+ *
932
+ * A preset bundles a realtime speech-to-speech model with one of its native
933
+ * voices and the settings recommended alongside it, so choosing a voice is
934
+ * a single decision. Apply one by assigning its `config` wholesale; compare
935
+ * against it to tell a preset selection from a customised ("Custom") one.
936
+ * The full engine/voice/settings matrix lives on `getRealtimeModels`.
937
+ */
938
+ async getVoicePresets() {
939
+ return this.fetch("ai-models/voice-presets");
940
+ }
927
941
  /**
928
942
  * Get available voice models with metadata
929
943
  */
@@ -2053,6 +2067,10 @@ var ChatsApi = class extends BaseApiClient {
2053
2067
  `w/${wid}/chats/${chatId}/skills`
2054
2068
  );
2055
2069
  }
2070
+ /** List built-in skills that can be selected before starting a Manager Chat. */
2071
+ async getManagerSkills(wid) {
2072
+ return this.fetch(`w/${wid}/chats/manager/skills`);
2073
+ }
2056
2074
  /** List chat IDs that need a response. */
2057
2075
  async getChatsNeedsResponse(wid) {
2058
2076
  return this.fetch(`w/${wid}/chats/needs-response`);
@@ -3680,9 +3698,9 @@ var DocumoFaxApi = class extends BaseApiClient {
3680
3698
  params?.status?.forEach((value) => query.append("status", value));
3681
3699
  if (params?.receivedAfter) query.set("receivedAfter", params.receivedAfter);
3682
3700
  if (params?.receivedBefore) query.set("receivedBefore", params.receivedBefore);
3683
- const suffix = query.toString() === "" ? "" : `?${query.toString()}`;
3701
+ const suffix2 = query.toString() === "" ? "" : `?${query.toString()}`;
3684
3702
  return this.fetch(
3685
- `w/${wid}/app-connections/documo-fax/faxes${suffix}`
3703
+ `w/${wid}/app-connections/documo-fax/faxes${suffix2}`
3686
3704
  );
3687
3705
  }
3688
3706
  /**
@@ -5756,15 +5774,19 @@ var OrgApi = class extends BaseApiClient {
5756
5774
  async getA2PStatus(orgUuid) {
5757
5775
  return this.fetch(`o/${orgUuid}/phone-numbers/a2p/status`);
5758
5776
  }
5777
+ /** Return fixed phone-number and outbound-messaging prices. */
5778
+ async getPhoneBillingPricing(orgUuid) {
5779
+ return this.fetch(`o/${orgUuid}/phone-numbers/pricing`);
5780
+ }
5759
5781
  /**
5760
5782
  * Start A2P brand registration under a legal entity. `legalEntityUuid`
5761
5783
  * is required — brands register per legal entity (Customer Profile);
5762
5784
  * there is no primary-entity fallback.
5763
5785
  */
5764
- async startA2PRegistration(orgUuid, legalEntityUuid, brandName, brandDescription) {
5786
+ async startA2PRegistration(orgUuid, legalEntityUuid, brandName, brandDescription, brandUuid = null) {
5765
5787
  return this.fetch(`o/${orgUuid}/phone-numbers/a2p/start`, {
5766
5788
  method: "POST",
5767
- body: JSON.stringify({ legalEntityUuid, brandName, brandDescription })
5789
+ body: JSON.stringify({ legalEntityUuid, brandName, brandDescription, brandUuid })
5768
5790
  });
5769
5791
  }
5770
5792
  /**
@@ -5970,14 +5992,34 @@ var OrgApi = class extends BaseApiClient {
5970
5992
  );
5971
5993
  }
5972
5994
  /**
5973
- * The brand-addressable enrollment form URL (carries `?brand=…`). Outreach
5974
- * appends each patient's `external_id`. `url` is null until a Site is linked.
5995
+ * The brand's enrollment-form template URL (carries `?brand=…`, no
5996
+ * credential). `url` is null until a Site is linked. Do not append a
5997
+ * patient identifier to this URL — use {@link mintA2PBrandEnrollmentLink}
5998
+ * to get a patient-ready link instead.
5975
5999
  */
5976
6000
  async getA2PBrandEnrollmentUrl(orgUuid, brandUuid) {
5977
6001
  return this.fetch(
5978
6002
  `o/${orgUuid}/a2p-brands/${brandUuid}/enrollment-url`
5979
6003
  );
5980
6004
  }
6005
+ /**
6006
+ * Mint a patient-ready enrollment link for one patient.
6007
+ *
6008
+ * The returned URL carries a fresh, expiring, single-use `?grant=…` bound to
6009
+ * the member that `externalId` resolves to. `externalId` (the patient's
6010
+ * CRM/EHR identifier) travels in the request body, never the query string,
6011
+ * so it stays out of access logs. When it matches no member, the
6012
+ * credential-free template URL is returned rather than an error.
6013
+ */
6014
+ async mintA2PBrandEnrollmentLink(orgUuid, brandUuid, externalId) {
6015
+ return this.fetch(
6016
+ `o/${orgUuid}/a2p-brands/${brandUuid}/enrollment-url`,
6017
+ {
6018
+ method: "POST",
6019
+ body: JSON.stringify({ externalId })
6020
+ }
6021
+ );
6022
+ }
5981
6023
  /**
5982
6024
  * List available member roles for a workspace in the organization.
5983
6025
  */
@@ -7780,6 +7822,118 @@ var ToolkitsApi = class extends BaseApiClient {
7780
7822
  }
7781
7823
  };
7782
7824
 
7825
+ // src/api/tracked-links.ts
7826
+ function withFilters(params, options) {
7827
+ if (options.dateFrom) params.append("dateFrom", options.dateFrom);
7828
+ if (options.dateTo) params.append("dateTo", options.dateTo);
7829
+ if (options.workflowId !== void 0) params.append("workflowId", String(options.workflowId));
7830
+ return params;
7831
+ }
7832
+ function suffix(params) {
7833
+ const query = params.toString();
7834
+ return query ? `?${query}` : "";
7835
+ }
7836
+ var TrackedLinksApi = class extends BaseApiClient {
7837
+ /** Header counters plus whether shortening is configured and enabled. */
7838
+ async getTrackedLinkSummary(wid, options = {}) {
7839
+ const params = withFilters(new URLSearchParams(), options);
7840
+ return this.fetch(
7841
+ `w/${wid}/tracked-links/summary${suffix(params)}`
7842
+ );
7843
+ }
7844
+ /**
7845
+ * Known destination URLs, most recent first. Powers the "Clicked link"
7846
+ * member-filter autocomplete, so it stays unaggregated and cheap.
7847
+ */
7848
+ async getTrackedLinkDestinations(wid, options = {}) {
7849
+ const params = new URLSearchParams();
7850
+ if (options.q) params.append("q", options.q);
7851
+ if (options.limit !== void 0) params.append("limit", String(options.limit));
7852
+ return this.fetch(
7853
+ `w/${wid}/tracked-links/destinations${suffix(params)}`
7854
+ );
7855
+ }
7856
+ /**
7857
+ * Register a destination an author can reference as `{{links.<key>}}`.
7858
+ *
7859
+ * The URL is deduplicated server-side, so registering one the workspace
7860
+ * already knows adopts that destination — including a row the retired
7861
+ * auto-harvest left unnamed, whose click history then carries forward
7862
+ * under the new key. Registering a URL that already has a *different* key
7863
+ * is a 409: renaming is what `updateTrackedLinkDestination` is for.
7864
+ *
7865
+ * Keys use the same grammar as snippet keys: lowercase letters, digits,
7866
+ * underscores and dots, starting with a letter (`intake_form`,
7867
+ * `docs.privacy`). No hyphens — Jinja2 reads `links.spring-2026` as
7868
+ * subtraction.
7869
+ */
7870
+ async createTrackedLinkDestination(wid, data) {
7871
+ return this.fetch(`w/${wid}/tracked-links/destinations`, {
7872
+ method: "POST",
7873
+ body: JSON.stringify(data)
7874
+ });
7875
+ }
7876
+ /**
7877
+ * Re-key or relabel a destination.
7878
+ *
7879
+ * Changing `key` breaks templates: `{{links.old}}` stops resolving and the
7880
+ * message ships without its link. Relabelling (`name`) is always safe.
7881
+ * Passing `key: null` releases the handle so another destination can take
7882
+ * it — the non-destructive alternative to deleting, which would take the
7883
+ * click history with it. The URL is not editable.
7884
+ */
7885
+ async updateTrackedLinkDestination(wid, destinationId, data) {
7886
+ return this.fetch(
7887
+ `w/${wid}/tracked-links/destinations/${destinationId}`,
7888
+ { method: "PUT", body: JSON.stringify(data) }
7889
+ );
7890
+ }
7891
+ /** Per-destination sent / clicks / unique clickers / CTR for the window. */
7892
+ async getTrackedLinkStats(wid, options = {}) {
7893
+ const params = withFilters(new URLSearchParams(), options);
7894
+ if (options.page !== void 0) params.append("page", String(options.page));
7895
+ if (options.pageSize !== void 0) params.append("pageSize", String(options.pageSize));
7896
+ if (options.q) params.append("q", options.q);
7897
+ if (options.sortBy) params.append("sortBy", options.sortBy);
7898
+ if (options.sortOrder) params.append("sortOrder", options.sortOrder);
7899
+ return this.fetch(
7900
+ `w/${wid}/tracked-links${suffix(params)}`
7901
+ );
7902
+ }
7903
+ /** Clicks over time for the current filter selection. */
7904
+ async getTrackedLinkTimeseries(wid, options = {}) {
7905
+ const params = withFilters(new URLSearchParams(), options);
7906
+ if (options.destinationId !== void 0) {
7907
+ params.append("destinationId", String(options.destinationId));
7908
+ }
7909
+ if (options.granularity) params.append("granularity", options.granularity);
7910
+ if (options.tz) params.append("tz", options.tz);
7911
+ return this.fetch(
7912
+ `w/${wid}/tracked-links/timeseries${suffix(params)}`
7913
+ );
7914
+ }
7915
+ /**
7916
+ * Delete one destination: its short links stop resolving and its recorded
7917
+ * clicks are removed.
7918
+ *
7919
+ * Turning the workspace setting off only stops NEW links being minted —
7920
+ * links already delivered to members keep working. This is the deliberate
7921
+ * way to break them.
7922
+ */
7923
+ async deleteTrackedLinkDestination(wid, destinationId) {
7924
+ return this.fetch(
7925
+ `w/${wid}/tracked-links/destinations/${destinationId}`,
7926
+ { method: "DELETE" }
7927
+ );
7928
+ }
7929
+ /** Delete every destination, its links, and its clicks. Irreversible. */
7930
+ async clearTrackedLinkDestinations(wid) {
7931
+ return this.fetch(`w/${wid}/tracked-links/destinations`, {
7932
+ method: "DELETE"
7933
+ });
7934
+ }
7935
+ };
7936
+
7783
7937
  // src/api/journeys.ts
7784
7938
  var JourneysApi = class extends BaseApiClient {
7785
7939
  /**
@@ -8605,6 +8759,7 @@ var EventRuleEventType = /* @__PURE__ */ ((EventRuleEventType2) => {
8605
8759
  EventRuleEventType2["DATA_RECORD_UPDATED"] = "data_record:updated";
8606
8760
  EventRuleEventType2["DATA_RECORD_CHANGED"] = "data_record:changed";
8607
8761
  EventRuleEventType2["CHAT_CREATED"] = "chat:created";
8762
+ EventRuleEventType2["CHAT_SUMMARY"] = "chat:summary";
8608
8763
  EventRuleEventType2["CHAT_CALLBACK"] = "chat:callback";
8609
8764
  EventRuleEventType2["MEMBER_UPDATED"] = "member:updated";
8610
8765
  EventRuleEventType2["ROUTINE_TRIGGERED"] = "routine:triggered";
@@ -9370,6 +9525,20 @@ var WorkspacesApi = class extends BaseApiClient {
9370
9525
  if (featured !== void 0) params.set("featured", String(featured));
9371
9526
  return this.fetch(`products?${params.toString()}`);
9372
9527
  }
9528
+ /**
9529
+ * Check whether a promo code is usable, without redeeming it.
9530
+ *
9531
+ * Reserves nothing, so it is safe to call as a form field settles. Redemption
9532
+ * happens server-side after checkout completes, when the organization and its
9533
+ * subscription exist.
9534
+ */
9535
+ async previewPromoCode(code, options) {
9536
+ return this.fetch("promo-codes/preview", {
9537
+ method: "POST",
9538
+ body: JSON.stringify({ code }),
9539
+ signal: options?.signal
9540
+ });
9541
+ }
9373
9542
  /** Get a publicly accessible product by ID. */
9374
9543
  async getPublicProduct(id) {
9375
9544
  return this.fetch(`products/${id}`);
@@ -9589,6 +9758,7 @@ function createApiModules(apiKey, baseUrl, customFetch) {
9589
9758
  members: new MembersApi(apiKey, baseUrl, customFetch),
9590
9759
  milestones: new MilestonesApi(apiKey, baseUrl, customFetch),
9591
9760
  motd: new MotdApi(apiKey, baseUrl, customFetch),
9761
+ trackedLinks: new TrackedLinksApi(apiKey, baseUrl, customFetch),
9592
9762
  confluence: new ConfluenceApi(apiKey, baseUrl, customFetch),
9593
9763
  mondayIntegration: new MondayIntegrationApi(apiKey, baseUrl, customFetch),
9594
9764
  notificationRules: new NotificationRulesApi(apiKey, baseUrl, customFetch),
@@ -9654,6 +9824,7 @@ var WORKSPACE_METHOD_NAMES = [
9654
9824
  "checkSiteSlugAvailability",
9655
9825
  "clearConnectionMemberExclusion",
9656
9826
  "clearMemberSwitch",
9827
+ "clearTrackedLinkDestinations",
9657
9828
  "clickWorkspaceSupportRequestResource",
9658
9829
  "cloneDataType",
9659
9830
  "cloneTask",
@@ -9729,6 +9900,7 @@ var WORKSPACE_METHOD_NAMES = [
9729
9900
  "createSupervisor",
9730
9901
  "createTask",
9731
9902
  "createTeamsApp",
9903
+ "createTrackedLinkDestination",
9732
9904
  "createWorkflow",
9733
9905
  "createWorkflowContributor",
9734
9906
  "createWorkflowFromTemplate",
@@ -9794,6 +9966,7 @@ var WORKSPACE_METHOD_NAMES = [
9794
9966
  "deleteSupervisor",
9795
9967
  "deleteTask",
9796
9968
  "deleteTeamsApp",
9969
+ "deleteTrackedLinkDestination",
9797
9970
  "deleteWidgetDomain",
9798
9971
  "deleteWorkflow",
9799
9972
  "deleteWorkflowContributor",
@@ -9918,6 +10091,7 @@ var WORKSPACE_METHOD_NAMES = [
9918
10091
  "getChatModelOverride",
9919
10092
  "getChatPhoneCalls",
9920
10093
  "getChatSkills",
10094
+ "getManagerSkills",
9921
10095
  "getChatTodos",
9922
10096
  "getChatTokenUsage",
9923
10097
  "getChatToolCallMessages",
@@ -10098,6 +10272,7 @@ var WORKSPACE_METHOD_NAMES = [
10098
10272
  "getPublicFolder",
10099
10273
  "getPublicFolderFiles",
10100
10274
  "getPublicProducts",
10275
+ "previewPromoCode",
10101
10276
  "getQualification",
10102
10277
  "getQualifications",
10103
10278
  "getRecordingInfo",
@@ -10144,6 +10319,10 @@ var WORKSPACE_METHOD_NAMES = [
10144
10319
  "getTool",
10145
10320
  "getToolCallNames",
10146
10321
  "getToolkits",
10322
+ "getTrackedLinkDestinations",
10323
+ "getTrackedLinkStats",
10324
+ "getTrackedLinkSummary",
10325
+ "getTrackedLinkTimeseries",
10147
10326
  "getUnreadNotificationCount",
10148
10327
  "getUsageDashboard",
10149
10328
  "getVariableRegistry",
@@ -10378,6 +10557,7 @@ var WORKSPACE_METHOD_NAMES = [
10378
10557
  "updateTask",
10379
10558
  "updateTeamsApp",
10380
10559
  "updateThemeSettings",
10560
+ "updateTrackedLinkDestination",
10381
10561
  "uploadFile",
10382
10562
  "updateVoicemailStatus",
10383
10563
  "updateWorkflow",
@@ -10475,6 +10655,7 @@ function bindChatsMethods(target, chats) {
10475
10655
  target.getChatTokenUsage = chats.getChatTokenUsage.bind(chats);
10476
10656
  target.getChatTodos = chats.getChatTodos.bind(chats);
10477
10657
  target.getChatSkills = chats.getChatSkills.bind(chats);
10658
+ target.getManagerSkills = chats.getManagerSkills.bind(chats);
10478
10659
  target.getChatsNeedsResponse = chats.getChatsNeedsResponse.bind(chats);
10479
10660
  target.getChatsDailyCreationStats = chats.getChatsDailyCreationStats.bind(chats);
10480
10661
  target.getToolCallNames = chats.getToolCallNames.bind(chats);
@@ -10548,6 +10729,18 @@ function bindMotdMethods(target, motd) {
10548
10729
  target.getMotd = motd.getMotd.bind(motd);
10549
10730
  }
10550
10731
 
10732
+ // src/client/bindings/tracked-links.ts
10733
+ function bindTrackedLinksMethods(target, trackedLinks) {
10734
+ target.getTrackedLinkSummary = trackedLinks.getTrackedLinkSummary.bind(trackedLinks);
10735
+ target.getTrackedLinkDestinations = trackedLinks.getTrackedLinkDestinations.bind(trackedLinks);
10736
+ target.getTrackedLinkStats = trackedLinks.getTrackedLinkStats.bind(trackedLinks);
10737
+ target.getTrackedLinkTimeseries = trackedLinks.getTrackedLinkTimeseries.bind(trackedLinks);
10738
+ target.createTrackedLinkDestination = trackedLinks.createTrackedLinkDestination.bind(trackedLinks);
10739
+ target.updateTrackedLinkDestination = trackedLinks.updateTrackedLinkDestination.bind(trackedLinks);
10740
+ target.deleteTrackedLinkDestination = trackedLinks.deleteTrackedLinkDestination.bind(trackedLinks);
10741
+ target.clearTrackedLinkDestinations = trackedLinks.clearTrackedLinkDestinations.bind(trackedLinks);
10742
+ }
10743
+
10551
10744
  // src/client/bindings/data-types.ts
10552
10745
  function bindDataTypesMethods(target, dataTypes) {
10553
10746
  target.getDataTypes = dataTypes.getDataTypes.bind(dataTypes);
@@ -11043,6 +11236,7 @@ function bindToolkitsMethods(target, toolkits, templates, aiModels, customToolki
11043
11236
  target.getSTTModels = aiModels.getSTTModels.bind(aiModels);
11044
11237
  target.getTTSModels = aiModels.getTTSModels.bind(aiModels);
11045
11238
  target.getVoiceModels = aiModels.getVoiceModels.bind(aiModels);
11239
+ target.getVoicePresets = aiModels.getVoicePresets.bind(aiModels);
11046
11240
  target.getAllModels = aiModels.getAllModels.bind(aiModels);
11047
11241
  target.getCustomToolkits = customToolkits.getCustomToolkits.bind(customToolkits);
11048
11242
  target.getCustomToolkit = customToolkits.getCustomToolkit.bind(customToolkits);
@@ -11514,6 +11708,7 @@ var GravityRailClient = class {
11514
11708
  getChatTokenUsage;
11515
11709
  getChatTodos;
11516
11710
  getChatSkills;
11711
+ getManagerSkills;
11517
11712
  getChatsNeedsResponse;
11518
11713
  getChatsDailyCreationStats;
11519
11714
  getToolCallNames;
@@ -11701,6 +11896,15 @@ var GravityRailClient = class {
11701
11896
  getDashboardWorkflowAssignmentStats;
11702
11897
  // MOTD API
11703
11898
  getMotd;
11899
+ // Tracked Links analytics (#10934)
11900
+ getTrackedLinkSummary;
11901
+ getTrackedLinkDestinations;
11902
+ getTrackedLinkStats;
11903
+ getTrackedLinkTimeseries;
11904
+ createTrackedLinkDestination;
11905
+ updateTrackedLinkDestination;
11906
+ deleteTrackedLinkDestination;
11907
+ clearTrackedLinkDestinations;
11704
11908
  // Journeys API
11705
11909
  getJourneys;
11706
11910
  getJourney;
@@ -11805,6 +12009,7 @@ var GravityRailClient = class {
11805
12009
  getProduct;
11806
12010
  getWorkspaceProduct;
11807
12011
  getPublicProducts;
12012
+ previewPromoCode;
11808
12013
  getPublicProduct;
11809
12014
  createProduct;
11810
12015
  updateProduct;
@@ -12159,6 +12364,7 @@ var GravityRailClient = class {
12159
12364
  getSTTModels;
12160
12365
  getTTSModels;
12161
12366
  getVoiceModels;
12367
+ getVoicePresets;
12162
12368
  getAllModels;
12163
12369
  getCustomToolkits;
12164
12370
  getCustomToolkit;
@@ -12489,6 +12695,7 @@ var GravityRailClient = class {
12489
12695
  bindQueriesMethods(this, apis.queries);
12490
12696
  bindDashboardsMethods(this, apis.dashboards);
12491
12697
  bindMotdMethods(this, apis.motd);
12698
+ bindTrackedLinksMethods(this, apis.trackedLinks);
12492
12699
  bindJourneysMethods(this, apis.journeys);
12493
12700
  bindExperimentsMethods(this, apis.experiments);
12494
12701
  bindOperatorMethods(this, apis.operatorGroups);
@@ -12681,6 +12888,14 @@ var WorkspaceBuilderResource = class {
12681
12888
  }
12682
12889
  return this._uuid;
12683
12890
  }
12891
+ /**
12892
+ * True for resources the server creates on our behalf (currently a
12893
+ * journey's `Start` step). They are kept in the resource list so edges can
12894
+ * reference them, but they are never created, printed, or counted.
12895
+ */
12896
+ get isImplicit() {
12897
+ return false;
12898
+ }
12684
12899
  matchKey() {
12685
12900
  return void 0;
12686
12901
  }
@@ -12703,6 +12918,19 @@ function resolveRefValue(value) {
12703
12918
  }
12704
12919
  return out;
12705
12920
  }
12921
+ function resolveIdRefs(value) {
12922
+ return resolveIdRefValue(value);
12923
+ }
12924
+ function resolveIdRefValue(value) {
12925
+ if (value instanceof WorkspaceBuilderResource) return value.id;
12926
+ if (Array.isArray(value)) return value.map(resolveIdRefValue);
12927
+ if (!isPlainRecord(value)) return value;
12928
+ const out = {};
12929
+ for (const [key, nestedValue] of Object.entries(value)) {
12930
+ out[key] = resolveIdRefValue(nestedValue);
12931
+ }
12932
+ return out;
12933
+ }
12706
12934
 
12707
12935
  // src/workspace-builder/automation.ts
12708
12936
  var MemberFilterBuilder = class extends WorkspaceBuilderResource {
@@ -12716,7 +12944,12 @@ var MemberFilterBuilder = class extends WorkspaceBuilderResource {
12716
12944
  description;
12717
12945
  /** Query-engine predicate (JSON IR) authored on MemberFilter.query. */
12718
12946
  query = null;
12719
- /** Set the filter's query-engine predicate (JSON IR). */
12947
+ /**
12948
+ * Set the filter's query-engine predicate (JSON IR).
12949
+ *
12950
+ * Anywhere the IR wants a numeric id you may pass the builder that will own
12951
+ * it (e.g. a label in a `member.labelId` value); refs resolve at apply time.
12952
+ */
12720
12953
  setQuery(query) {
12721
12954
  this.query = query;
12722
12955
  return this;
@@ -12725,10 +12958,12 @@ var MemberFilterBuilder = class extends WorkspaceBuilderResource {
12725
12958
  return `MemberFilter: ${this.name}${this.query ? " (query)" : ""}`;
12726
12959
  }
12727
12960
  async apply(client) {
12961
+ if (this._existed) return;
12728
12962
  const payload = {
12729
12963
  name: this.name,
12730
12964
  description: this.description,
12731
- query: this.query
12965
+ // Builder refs inside the IR become ids here; see resolveIdRefs.
12966
+ query: resolveIdRefs(this.query)
12732
12967
  };
12733
12968
  const result = await client.createMemberFilter(payload);
12734
12969
  this._id = result.id;
@@ -13023,35 +13258,134 @@ var MemberLabelBuilder = class extends WorkspaceBuilderResource {
13023
13258
  };
13024
13259
 
13025
13260
  // src/workspace-builder/journeys.ts
13261
+ var SECONDS_PER_DAY = 86400;
13262
+ function edgeKey(parentId, childId) {
13263
+ return `${parentId}:${childId}`;
13264
+ }
13265
+ function edgeCondition(options) {
13266
+ const clauses = [];
13267
+ if (options.afterDays !== void 0) {
13268
+ clauses.push(`days_since(parent_step.completed_at) >= ${options.afterDays}`);
13269
+ }
13270
+ if (options.when) clauses.push(`(${options.when})`);
13271
+ if (!clauses.length) return void 0;
13272
+ return clauses.join(" && ");
13273
+ }
13026
13274
  var JourneyStepBuilder = class extends WorkspaceBuilderResource {
13027
13275
  // journey-decoupling Phase 7: a Journey step no longer links to a Workflow.
13028
13276
  // A step nudges via EventRule actions instead of running a Workflow, so the
13029
13277
  // builder no longer accepts or emits a workflow reference.
13030
- constructor(name, journey, order = 0, description = "") {
13278
+ constructor(name, journey, order = 0, description = "", options = {}) {
13031
13279
  super();
13032
13280
  this.name = name;
13033
13281
  this.journey = journey;
13034
13282
  this.order = order;
13035
13283
  this.description = description;
13284
+ this.assigneeId = options.assigneeId;
13285
+ this.posX = options.posX;
13286
+ this.posY = options.posY;
13036
13287
  }
13037
13288
  name;
13038
13289
  journey;
13039
13290
  order;
13040
13291
  description;
13041
13292
  connections = [];
13042
- connectsTo(child, condition, required = false, timeoutSeconds) {
13043
- this.connections.push({ parent: this, child, condition, required, timeoutSeconds });
13293
+ rules = [];
13294
+ assigneeId;
13295
+ posX;
13296
+ posY;
13297
+ /** Wire an edge to `child` and return the CHILD, so chains read linearly. */
13298
+ connectsTo(child, options = {}) {
13299
+ if (child === this) {
13300
+ throw new Error(`Journey step '${this.name}' cannot connect to itself`);
13301
+ }
13302
+ const abandonSeconds = options.abandonAfterDays !== void 0 ? options.abandonAfterDays * SECONDS_PER_DAY : options.timeoutSeconds;
13303
+ this.connections.push({
13304
+ parent: this,
13305
+ child,
13306
+ condition: edgeCondition(options),
13307
+ required: options.required ?? false,
13308
+ timeoutSeconds: abandonSeconds,
13309
+ order: options.order,
13310
+ filterId: options.filterId
13311
+ });
13312
+ return child;
13313
+ }
13314
+ /**
13315
+ * Attach a `JOURNEY_STEP_EXECUTE` action — what this step actually DOES
13316
+ * when a member reaches it. A step with no rules is inert: the member
13317
+ * lands on it, nothing is sent, and the journey moves on.
13318
+ */
13319
+ onExecute(actionType, params = {}, options = {}) {
13320
+ this.rules.push({
13321
+ uuid: crypto.randomUUID(),
13322
+ actionType,
13323
+ actionParams: params,
13324
+ options
13325
+ });
13044
13326
  return this;
13045
13327
  }
13328
+ /**
13329
+ * Text the member. `phoneNumberUUID` is a workspace PhoneNumber with SMS
13330
+ * enabled. Pass `workflowUUID` to start an SMS workflow chat, or
13331
+ * `messageTemplate` for a one-off send.
13332
+ */
13333
+ sendsSms(params, options = {}) {
13334
+ return this.onExecute("sms:send" /* SMS_SEND */, params, options);
13335
+ }
13336
+ /**
13337
+ * Call the member. Both the workspace PhoneNumber uuid (voice enabled) and
13338
+ * the Workflow uuid that drives the call are required.
13339
+ */
13340
+ callsMember(params, options = {}) {
13341
+ return this.onExecute("phone:call" /* PHONE_CALL */, params, options);
13342
+ }
13343
+ /** Email the member from a workspace inbox. */
13344
+ sendsEmail(params, options = {}) {
13345
+ return this.onExecute("email:send" /* EMAIL_SEND */, params, options);
13346
+ }
13347
+ /** Label the member on arrival — pass label builders, not ids. */
13348
+ addsLabels(labels, options = {}) {
13349
+ return this.onExecute(
13350
+ "member:label" /* MEMBER_LABEL_ACTION */,
13351
+ { addLabelIds: labels },
13352
+ options
13353
+ );
13354
+ }
13355
+ /** True once this step has something to do when a member reaches it. */
13356
+ get hasOutreach() {
13357
+ return this.rules.length > 0;
13358
+ }
13359
+ eventRuleInputs() {
13360
+ return this.rules.map((rule) => ({
13361
+ uuid: rule.uuid,
13362
+ eventType: "journey_step:execute" /* JOURNEY_STEP_EXECUTE */,
13363
+ actionType: rule.actionType,
13364
+ actionParams: resolveRefs(rule.actionParams),
13365
+ ...rule.options.name ? { name: rule.options.name } : {},
13366
+ ...rule.options.when ? { conditions: rule.options.when } : {},
13367
+ ...rule.options.delaySeconds ? { delay: rule.options.delaySeconds } : {},
13368
+ active: rule.options.active ?? true
13369
+ }));
13370
+ }
13046
13371
  planLine() {
13047
- return `Step: ${this.name}`;
13372
+ const actions = this.rules.map((rule) => rule.actionType).join(" + ");
13373
+ return `Step: ${this.name}${actions ? ` (${actions})` : ""}`;
13048
13374
  }
13049
13375
  async apply(client) {
13376
+ if (this._existed) return;
13050
13377
  if (this.journey._id === void 0) return;
13378
+ const rules = this.eventRuleInputs();
13051
13379
  const payload = {
13052
13380
  name: this.name,
13053
13381
  description: this.description,
13054
- order: this.order
13382
+ order: this.order,
13383
+ ...this.assigneeId !== void 0 ? { assigneeId: this.assigneeId } : {},
13384
+ ...this.posX !== void 0 ? { posX: this.posX } : {},
13385
+ ...this.posY !== void 0 ? { posY: this.posY } : {},
13386
+ // Saved atomically with the step, so a partial failure cannot leave
13387
+ // an inert step behind.
13388
+ ...rules.length ? { eventRules: rules } : {}
13055
13389
  };
13056
13390
  const result = await client.createStep(this.journey._id, payload);
13057
13391
  this._id = result.id;
@@ -13059,26 +13393,59 @@ var JourneyStepBuilder = class extends WorkspaceBuilderResource {
13059
13393
  this._created = true;
13060
13394
  }
13061
13395
  };
13396
+ var StartStepBuilder = class extends JourneyStepBuilder {
13397
+ get isImplicit() {
13398
+ return true;
13399
+ }
13400
+ planLine() {
13401
+ return "Step: Start (auto-created)";
13402
+ }
13403
+ async apply() {
13404
+ }
13405
+ };
13062
13406
  var JourneyBuilder = class extends WorkspaceBuilderResource {
13063
13407
  constructor(name, options = {}) {
13064
13408
  super();
13065
13409
  this.name = name;
13066
13410
  this.description = options.description ?? "";
13411
+ this.start = new StartStepBuilder("Start", this, 0);
13412
+ this.steps.push(this.start);
13067
13413
  }
13068
13414
  name;
13069
13415
  description;
13070
13416
  steps = [];
13071
13417
  goals = [];
13418
+ /** The auto-created `Start` step — connect the first real step to it. */
13419
+ start;
13420
+ /** `parentId:childId` for every edge the server already has (see `adopt`). */
13421
+ existingEdges = /* @__PURE__ */ new Set();
13072
13422
  step(name, options = {}) {
13073
13423
  const step = new JourneyStepBuilder(
13074
13424
  name,
13075
13425
  this,
13076
- options.order ?? 0,
13077
- options.description ?? ""
13426
+ options.order ?? this.steps.length,
13427
+ options.description ?? "",
13428
+ options
13078
13429
  );
13079
13430
  this.steps.push(step);
13080
13431
  return step;
13081
13432
  }
13433
+ /**
13434
+ * Declare a linear cadence: `Start → steps[0] → steps[1] → …`, each edge
13435
+ * carrying the matching entry from `spacing`.
13436
+ *
13437
+ * Chaining is not optional polish. A step created with no incoming edge is
13438
+ * a ROOT, and every root fires the moment a member enrols — a "three
13439
+ * follow-ups over four days" journey built without edges sends all three
13440
+ * at once.
13441
+ */
13442
+ sequence(steps, spacing = []) {
13443
+ let parent = this.start;
13444
+ steps.forEach((step, index) => {
13445
+ parent = parent.connectsTo(step, spacing[index] ?? {});
13446
+ });
13447
+ return this;
13448
+ }
13082
13449
  goal(name, options = {}) {
13083
13450
  this.goals.push({
13084
13451
  name,
@@ -13086,17 +13453,85 @@ var JourneyBuilder = class extends WorkspaceBuilderResource {
13086
13453
  step: options.step,
13087
13454
  completionCel: options.completionCel ?? options.completion_cel,
13088
13455
  value: options.value,
13089
- order: options.order ?? 0
13456
+ order: options.order ?? this.goals.length
13090
13457
  });
13091
13458
  return this;
13092
13459
  }
13460
+ /**
13461
+ * Authoring problems that make a journey silently misbehave at runtime.
13462
+ * Reported at plan/preview time, before anything is written.
13463
+ */
13464
+ validate() {
13465
+ const problems = [];
13466
+ const withParents = /* @__PURE__ */ new Set();
13467
+ for (const step of this.steps) {
13468
+ for (const connection of step.connections) withParents.add(connection.child);
13469
+ }
13470
+ for (const step of this.steps) {
13471
+ if (step === this.start) continue;
13472
+ if (!withParents.has(step)) {
13473
+ problems.push(
13474
+ `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.`
13475
+ );
13476
+ }
13477
+ if (!step.hasOutreach) {
13478
+ problems.push(
13479
+ `step '${step.name}' has no JOURNEY_STEP_EXECUTE action \u2014 a member reaching it gets nothing. Add one with .sendsSms / .callsMember / .sendsEmail / .onExecute.`
13480
+ );
13481
+ }
13482
+ }
13483
+ if (!this.goals.length) {
13484
+ problems.push(`journey '${this.name}' has no goals \u2014 nothing measures whether it works.`);
13485
+ }
13486
+ return problems;
13487
+ }
13488
+ /**
13489
+ * Adopt an existing journey, its steps, and its EDGES, matched by name.
13490
+ *
13491
+ * Re-running a builder script is normal — a program is usually built in
13492
+ * stages as provisioning lands — and without adoption the second run would
13493
+ * create a duplicate journey and a duplicate set of steps beside the live
13494
+ * one, with members enrolled in neither.
13495
+ *
13496
+ * The edge set is recorded from the server's own `childConnections` rather
13497
+ * than inferred from "both steps exist". A first run that created the steps
13498
+ * and then failed before writing an edge leaves exactly that state, and
13499
+ * inferring would skip the missing edge on every subsequent run — leaving a
13500
+ * permanent root step that fires for every member at enrolment, silently.
13501
+ * The journey detail read eager-loads connections, so the real answer is
13502
+ * already in hand; there is no reason to guess.
13503
+ */
13504
+ adopt(existing) {
13505
+ super.adopt(existing);
13506
+ const existingSteps = existing.steps ?? [];
13507
+ const byName = new Map(existingSteps.map((step) => [step.name, step]));
13508
+ const startStep = existingSteps.find((step) => step.id === existing.startStepId) ?? byName.get("Start");
13509
+ if (startStep) this.start.adopt(startStep);
13510
+ for (const step of this.steps) {
13511
+ if (step === this.start) continue;
13512
+ const match = byName.get(step.name);
13513
+ if (match) step.adopt(match);
13514
+ }
13515
+ for (const step of existingSteps) {
13516
+ for (const edge of step.childConnections ?? []) {
13517
+ this.existingEdges.add(edgeKey(edge.parentStepId, edge.childStepId));
13518
+ }
13519
+ }
13520
+ }
13521
+ /** True when the server already has this exact edge. */
13522
+ hasEdge(parent, child) {
13523
+ if (parent._id === void 0 || child._id === void 0) return false;
13524
+ return this.existingEdges.has(edgeKey(parent._id, child._id));
13525
+ }
13093
13526
  planLine() {
13094
13527
  const parts = [];
13095
- if (this.steps.length) parts.push(`${this.steps.length} steps`);
13528
+ const real = this.steps.filter((step) => step !== this.start);
13529
+ if (real.length) parts.push(`${real.length} steps`);
13096
13530
  if (this.goals.length) parts.push(`${this.goals.length} goals`);
13097
13531
  return `Journey: ${this.name}${parts.length ? ` (${parts.join(", ")})` : ""}`;
13098
13532
  }
13099
13533
  async apply(client) {
13534
+ if (this._existed) return;
13100
13535
  const result = await client.createJourney({
13101
13536
  name: this.name,
13102
13537
  description: this.description
@@ -13104,6 +13539,15 @@ var JourneyBuilder = class extends WorkspaceBuilderResource {
13104
13539
  this._id = result.id;
13105
13540
  this._uuid = result.uuid;
13106
13541
  this._created = true;
13542
+ const startStep = (result.steps ?? []).find(
13543
+ (step) => step.id === result.startStepId || step.name === "Start"
13544
+ );
13545
+ if (!startStep) {
13546
+ throw new Error(
13547
+ `Journey '${this.name}' was created without a Start step; edges from journey.start cannot be wired.`
13548
+ );
13549
+ }
13550
+ this.start.adopt(startStep);
13107
13551
  }
13108
13552
  };
13109
13553
  function buildJourneyConnectionPayload(connection) {
@@ -13113,7 +13557,9 @@ function buildJourneyConnectionPayload(connection) {
13113
13557
  childStepUuid: connection.child._uuid,
13114
13558
  ...connection.condition ? { celCondition: connection.condition } : {},
13115
13559
  ...connection.required ? { required: true } : {},
13116
- ...connection.timeoutSeconds ? { timeoutSeconds: connection.timeoutSeconds } : {}
13560
+ ...connection.timeoutSeconds ? { timeoutSeconds: connection.timeoutSeconds } : {},
13561
+ ...connection.order !== void 0 ? { order: connection.order } : {},
13562
+ ...connection.filterId !== void 0 ? { filterId: connection.filterId } : {}
13117
13563
  };
13118
13564
  }
13119
13565
  function buildJourneyGoalPayload(goal) {
@@ -13399,6 +13845,15 @@ var PHASES = /* @__PURE__ */ new Map([
13399
13845
  [JourneyBuilder, 7],
13400
13846
  [JourneyStepBuilder, 8]
13401
13847
  ]);
13848
+ function phaseFor(resource) {
13849
+ let ctor = resource.constructor;
13850
+ while (ctor) {
13851
+ const phase = PHASES.get(ctor);
13852
+ if (phase !== void 0) return phase;
13853
+ ctor = Object.getPrototypeOf(ctor);
13854
+ }
13855
+ return 99;
13856
+ }
13402
13857
  var WorkspaceBuilder = class {
13403
13858
  constructor(client) {
13404
13859
  this.client = client;
@@ -13461,7 +13916,8 @@ var WorkspaceBuilder = class {
13461
13916
  ${"=".repeat(50)}`);
13462
13917
  writeLine("Plan");
13463
13918
  writeLine("=".repeat(50));
13464
- for (const resource of resources) {
13919
+ const declared = resources.filter((resource) => !resource.isImplicit);
13920
+ for (const resource of declared) {
13465
13921
  writeLine(` + ${resource.planLine()}`);
13466
13922
  }
13467
13923
  const wiring = this.collectWiringSummary(resources);
@@ -13469,8 +13925,9 @@ ${"=".repeat(50)}`);
13469
13925
  writeLine("\n Wiring:");
13470
13926
  for (const line of wiring) writeLine(` ${line}`);
13471
13927
  }
13928
+ this.reportJourneyWarnings();
13472
13929
  writeLine(`
13473
- Total: ${resources.length} resources, ${wiring.length} connections`);
13930
+ Total: ${declared.length} resources, ${wiring.length} connections`);
13474
13931
  writeLine(`${"=".repeat(50)}
13475
13932
  `);
13476
13933
  }
@@ -13481,7 +13938,8 @@ ${"=".repeat(50)}`);
13481
13938
  ${"=".repeat(50)}`);
13482
13939
  writeLine("Preview");
13483
13940
  writeLine("=".repeat(50));
13484
- for (const resource of resources) {
13941
+ const declared = resources.filter((resource) => !resource.isImplicit);
13942
+ for (const resource of declared) {
13485
13943
  if (resource._existed) {
13486
13944
  writeLine(` = ${resource.planLine()} (exists, id=${resource._id})`);
13487
13945
  } else {
@@ -13493,8 +13951,9 @@ ${"=".repeat(50)}`);
13493
13951
  writeLine("\n Wiring:");
13494
13952
  for (const line of wiring) writeLine(` ${line}`);
13495
13953
  }
13496
- const toCreate = resources.filter((resource) => !resource._existed);
13497
- const existing = resources.filter((resource) => resource._existed);
13954
+ this.reportJourneyWarnings();
13955
+ const toCreate = declared.filter((resource) => !resource._existed);
13956
+ const existing = declared.filter((resource) => resource._existed);
13498
13957
  writeLine(
13499
13958
  `
13500
13959
  Total: ${toCreate.length} to create, ${existing.length} existing, ${wiring.length} connections`
@@ -13502,6 +13961,18 @@ ${"=".repeat(50)}`);
13502
13961
  writeLine(`${"=".repeat(50)}
13503
13962
  `);
13504
13963
  }
13964
+ /**
13965
+ * Print journey authoring problems that only bite at runtime — a step with
13966
+ * no incoming edge fires for every member at enrolment, and a step with no
13967
+ * action does nothing at all. Both look fine in the editor, so they are
13968
+ * surfaced before the write rather than discovered from a member's phone.
13969
+ */
13970
+ reportJourneyWarnings() {
13971
+ const problems = this.resources.filter((resource) => resource instanceof JourneyBuilder).flatMap((journey) => journey.validate());
13972
+ if (!problems.length) return;
13973
+ writeLine("\n Journey warnings:");
13974
+ for (const problem of problems) writeLine(` ! ${problem}`);
13975
+ }
13505
13976
  async apply() {
13506
13977
  const resources = this.sortedResources();
13507
13978
  await this.resolveExisting(resources);
@@ -13509,6 +13980,7 @@ ${"=".repeat(50)}`);
13509
13980
  writeLine("Applying...");
13510
13981
  for (const resource of resources) {
13511
13982
  try {
13983
+ if (resource.isImplicit) continue;
13512
13984
  if (resource._existed) {
13513
13985
  const key = resourceKey(resource);
13514
13986
  summary[key] ??= [];
@@ -13566,6 +14038,29 @@ Done! Created ${count} resources.`);
13566
14038
  }
13567
14039
  }
13568
14040
  }
14041
+ const filterNames = new Map(
14042
+ resources.filter(
14043
+ (resource) => resource instanceof MemberFilterBuilder
14044
+ ).map((resource) => [resource.name, resource])
14045
+ );
14046
+ if (filterNames.size) {
14047
+ for (const existing of await this.client.getMemberFilters()) {
14048
+ if (existing.name && filterNames.has(existing.name)) {
14049
+ filterNames.get(existing.name).adopt(existing);
14050
+ }
14051
+ }
14052
+ }
14053
+ const journeyNames = new Map(
14054
+ resources.filter((resource) => resource instanceof JourneyBuilder).map((resource) => [resource.name, resource])
14055
+ );
14056
+ if (journeyNames.size) {
14057
+ const existingJourneys = await this.client.getJourneys();
14058
+ for (const existing of existingJourneys.items) {
14059
+ if (!existing.name || !journeyNames.has(existing.name)) continue;
14060
+ const detail = await this.client.getJourney(existing.id);
14061
+ journeyNames.get(existing.name).adopt(detail);
14062
+ }
14063
+ }
13569
14064
  if (!workflowNames.size) return;
13570
14065
  const existingWorkflows = await this.client.getWorkflows();
13571
14066
  for (const { workflow: existing } of existingWorkflows.items) {
@@ -13616,9 +14111,7 @@ Done! Created ${count} resources.`);
13616
14111
  all.push(...resource.steps);
13617
14112
  }
13618
14113
  }
13619
- return all.sort(
13620
- (a, b) => (PHASES.get(a.constructor) ?? 99) - (PHASES.get(b.constructor) ?? 99)
13621
- );
14114
+ return all.sort((a, b) => phaseFor(a) - phaseFor(b));
13622
14115
  }
13623
14116
  collectWiringSummary(resources) {
13624
14117
  const lines = [];
@@ -13639,7 +14132,11 @@ Done! Created ${count} resources.`);
13639
14132
  lines.push(`${rule.actionType} rule on '${resource.name}'`);
13640
14133
  } else if (resource instanceof JourneyStepBuilder) {
13641
14134
  for (const connection of resource.connections) {
13642
- lines.push(`${connection.parent.name} -> ${connection.child.name}`);
14135
+ const guard = connection.condition ? ` [${connection.condition}]` : "";
14136
+ lines.push(`${connection.parent.name} -> ${connection.child.name}${guard}`);
14137
+ }
14138
+ for (const rule of resource.rules) {
14139
+ lines.push(`${rule.actionType} on step '${resource.name}'`);
13643
14140
  }
13644
14141
  } else if (resource instanceof JourneyBuilder) {
13645
14142
  for (const goal of resource.goals) lines.push(`Goal: ${goal.name}`);
@@ -13755,6 +14252,10 @@ Done! Created ${count} resources.`);
13755
14252
  if (!(resource instanceof JourneyStepBuilder)) continue;
13756
14253
  for (const connection of resource.connections) {
13757
14254
  if (resource.journey._id === void 0) continue;
14255
+ if (resource.journey.hasEdge(connection.parent, connection.child)) {
14256
+ writeLine(` Exists: ${connection.parent.name} -> ${connection.child.name}`);
14257
+ continue;
14258
+ }
13758
14259
  const payload = buildJourneyConnectionPayload(connection);
13759
14260
  if (!payload) continue;
13760
14261
  await this.client.createConnection(resource.journey._id, payload);
@@ -13765,6 +14266,12 @@ Done! Created ${count} resources.`);
13765
14266
  async applyJourneyGoals(resources) {
13766
14267
  for (const resource of resources) {
13767
14268
  if (!(resource instanceof JourneyBuilder) || resource._id === void 0) continue;
14269
+ if (resource._existed) {
14270
+ for (const goal of resource.goals) {
14271
+ writeLine(` Skipped (journey already exists): Goal: ${goal.name}`);
14272
+ }
14273
+ continue;
14274
+ }
13768
14275
  for (const goal of resource.goals) {
13769
14276
  await this.client.createGoal(resource._id, buildJourneyGoalPayload(goal));
13770
14277
  writeLine(` Created goal: ${goal.name}`);
@@ -14191,6 +14698,15 @@ var WorkflowAccessWarningResourceType = {
14191
14698
  // src/types/widget-domain-types.ts
14192
14699
  var WIDGET_SLUGS = ["chat", "operator", "operator-tools", "chat-app"];
14193
14700
 
14701
+ // src/types/generated/promo_code_service.ts
14702
+ var PromoCodeStatus = {
14703
+ active: "active",
14704
+ scheduled: "scheduled",
14705
+ expired: "expired",
14706
+ inactive: "inactive",
14707
+ exhausted: "exhausted"
14708
+ };
14709
+
14194
14710
  // src/features/registry.ts
14195
14711
  var FeatureCategory = /* @__PURE__ */ ((FeatureCategory2) => {
14196
14712
  FeatureCategory2["COMMUNICATION"] = "communication";
@@ -15203,6 +15719,7 @@ function getRevisionState(workflow, revision) {
15203
15719
  PIDS_SOURCES,
15204
15720
  POSITIVE_RATING_THRESHOLD,
15205
15721
  ProductType,
15722
+ PromoCodeStatus,
15206
15723
  QUERY_VALUELESS_OPS,
15207
15724
  QueriesApi,
15208
15725
  REALTIME_MODEL_CUSTOM,
@@ -15244,6 +15761,7 @@ function getRevisionState(workflow, revision) {
15244
15761
  WorkflowBuilder,
15245
15762
  WorkflowResourceType,
15246
15763
  WorkspaceBuilder,
15764
+ WorkspaceBuilderResource,
15247
15765
  WorkspaceFeature,
15248
15766
  WorkspaceProvisionStatus,
15249
15767
  areDependenciesSatisfied,