@usergist/sdk-core 0.1.0 → 0.1.2

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
@@ -27,6 +27,16 @@ function err(code, message, details) {
27
27
  };
28
28
  }
29
29
 
30
+ // src/types/workspace.ts
31
+ function defaultOnboardingMessage(appName) {
32
+ return {
33
+ title: `Welcome to ${appName.trim() || "our app"}`,
34
+ body: "Glad you\u2019re here. Take a look around and make yourself at home.",
35
+ buttonLabel: "Got it",
36
+ format: "modal"
37
+ };
38
+ }
39
+
30
40
  // src/types/survey.ts
31
41
  var SURVEY_END_SENTINEL = "__end__";
32
42
 
@@ -270,8 +280,8 @@ var THEME_PRESETS = [
270
280
  swatches: ["#8B5CF6", "#EC4899", "#E9D5FF"]
271
281
  }
272
282
  ];
273
- function getThemePresetById(id) {
274
- return THEME_PRESETS.find((preset) => preset.id === id);
283
+ function getThemePresetById(id2) {
284
+ return THEME_PRESETS.find((preset) => preset.id === id2);
275
285
  }
276
286
  function defaultThemePreset() {
277
287
  return THEME_PRESETS[0];
@@ -322,7 +332,7 @@ var USER_IDENTIFIED_EVENT_NAME = "$user_identified";
322
332
  function camelize(value) {
323
333
  return value.replace(/_([a-z])/g, (_match, letter) => letter.toUpperCase());
324
334
  }
325
- var ids = (...keys) => Object.fromEntries(keys.map((key) => [key, [key, camelize(key)]]));
335
+ var ids = (...keys) => Object.fromEntries(keys.map((key2) => [key2, [key2, camelize(key2)]]));
326
336
  var pushEvents = [
327
337
  ["$push_sent", "UserGist Push Sent"],
328
338
  ["$push_delivered", "UserGist Push Delivered"],
@@ -379,8 +389,8 @@ var CORE_INTEGRATION_EVENTS = [
379
389
  { key: "$inapp_dismissed", name: "UserGist In-App Message Dismissed", category: "inapp", subjectRole: "actor", properties: { ...ids("message_id", "dismiss_reason") } },
380
390
  { key: "$inapp_auto_dismissed", name: "UserGist In-App Message Auto-Dismissed", category: "inapp", subjectRole: "actor", properties: { ...ids("message_id", "dismiss_reason") } },
381
391
  { key: "$inapp_cta_clicked", name: "UserGist In-App Message CTA Clicked", category: "inapp", subjectRole: "actor", properties: { ...ids("message_id", "cta_id", "cta_index"), action: ["action", "cta_action"] } },
382
- ...pushEvents.map(([key, name]) => ({
383
- key,
392
+ ...pushEvents.map(([key2, name]) => ({
393
+ key: key2,
384
394
  name,
385
395
  category: "push",
386
396
  subjectRole: "actor",
@@ -389,11 +399,11 @@ var CORE_INTEGRATION_EVENTS = [
389
399
  action_id: ["action_id", "actionId", "action_button", "actionButton"]
390
400
  }
391
401
  })),
392
- ...requestEvents.map(([key, name, subjectRole]) => ({ key, name, category: "requests", subjectRole, properties: { ...ids("request_id", "comment_id", "source", "old_status", "new_status", "deleted_by"), usergist_actor_type: ["usergist_actor_type", "actor_type"] } }))
402
+ ...requestEvents.map(([key2, name, subjectRole]) => ({ key: key2, name, category: "requests", subjectRole, properties: { ...ids("request_id", "comment_id", "source", "old_status", "new_status", "deleted_by"), usergist_actor_type: ["usergist_actor_type", "actor_type"] } }))
393
403
  ];
394
404
  var CORE_EVENT_BY_KEY = new Map(CORE_INTEGRATION_EVENTS.map((event) => [event.key, event]));
395
- function getCoreIntegrationEvent(key) {
396
- return CORE_EVENT_BY_KEY.get(key) ?? null;
405
+ function getCoreIntegrationEvent(key2) {
406
+ return CORE_EVENT_BY_KEY.get(key2) ?? null;
397
407
  }
398
408
  function sanitizeCoreIntegrationProperties(definition, input) {
399
409
  if (!input) return {};
@@ -500,15 +510,15 @@ function evaluateGroup(group, user, now) {
500
510
  }
501
511
  return group.predicates.some((p) => evaluateNode(p, user, now));
502
512
  }
503
- function evaluateNode(node, user, now) {
504
- if ("combinator" in node) return evaluateGroup(node, user, now);
505
- switch (node.kind) {
513
+ function evaluateNode(node2, user, now) {
514
+ if ("combinator" in node2) return evaluateGroup(node2, user, now);
515
+ switch (node2.kind) {
506
516
  case "user_property":
507
- return evaluateUserProperty(node, user);
517
+ return evaluateUserProperty(node2, user);
508
518
  case "event_count":
509
- return evaluateEventCount(node, user);
519
+ return evaluateEventCount(node2, user);
510
520
  case "event_occurred":
511
- return evaluateEventOccurred(node, user, now);
521
+ return evaluateEventOccurred(node2, user, now);
512
522
  }
513
523
  }
514
524
  function evaluateUserProperty(p, user) {
@@ -662,15 +672,15 @@ function reachableQuestions(flow, startId) {
662
672
  const visited = /* @__PURE__ */ new Set();
663
673
  const stack = [start];
664
674
  while (stack.length > 0) {
665
- const id = stack.pop();
666
- if (id === void 0) continue;
667
- if (visited.has(id)) continue;
668
- visited.add(id);
669
- const outgoing = flow.branches.filter((b) => b.fromQuestionId === id);
675
+ const id2 = stack.pop();
676
+ if (id2 === void 0) continue;
677
+ if (visited.has(id2)) continue;
678
+ visited.add(id2);
679
+ const outgoing = flow.branches.filter((b) => b.fromQuestionId === id2);
670
680
  for (const b of outgoing) {
671
681
  if (b.toQuestionId !== SURVEY_END_SENTINEL) stack.push(b.toQuestionId);
672
682
  }
673
- const idx = flow.questions.findIndex((q) => q.id === id);
683
+ const idx = flow.questions.findIndex((q) => q.id === id2);
674
684
  if (idx >= 0 && idx < flow.questions.length - 1) {
675
685
  const next = flow.questions[idx + 1];
676
686
  if (next) stack.push(next.id);
@@ -709,7 +719,7 @@ function tzOffsetMinutes(at, tz) {
709
719
  function startCandidate(schedule, now, tz) {
710
720
  const localNow = wallClock(now, tz);
711
721
  const target = new Date(localNow);
712
- target.setHours(schedule.hourLocal, schedule.minuteLocal, 0, 0);
722
+ target.setUTCHours(schedule.hourLocal, schedule.minuteLocal, 0, 0);
713
723
  return localToUtc(target, tz);
714
724
  }
715
725
  function walkForward(candidate, schedule, now, tz) {
@@ -727,30 +737,30 @@ function walkForward(candidate, schedule, now, tz) {
727
737
  function matchesFrequency(local, schedule) {
728
738
  if (schedule.frequency === "daily") return true;
729
739
  if (schedule.frequency === "weekly") {
730
- return schedule.weekday === void 0 || local.getDay() === schedule.weekday;
740
+ return schedule.weekday === void 0 || local.getUTCDay() === schedule.weekday;
731
741
  }
732
- return schedule.dayOfMonth === void 0 || local.getDate() === schedule.dayOfMonth;
742
+ return schedule.dayOfMonth === void 0 || local.getUTCDate() === schedule.dayOfMonth;
733
743
  }
734
744
  function step(cursor, cursorLocal, schedule, tz) {
735
745
  if (schedule.frequency === "daily" || schedule.frequency === "weekly") {
736
746
  return addDays(cursor, 1);
737
747
  }
738
748
  const next = new Date(cursorLocal);
739
- next.setMonth(next.getMonth() + 1);
749
+ next.setUTCMonth(next.getUTCMonth() + 1);
740
750
  if (schedule.dayOfMonth !== void 0) {
741
- const lastDay = lastDayOfMonth(next.getFullYear(), next.getMonth());
742
- next.setDate(Math.min(schedule.dayOfMonth, lastDay));
751
+ const lastDay = lastDayOfMonth(next.getUTCFullYear(), next.getUTCMonth());
752
+ next.setUTCDate(Math.min(schedule.dayOfMonth, lastDay));
743
753
  }
744
- next.setHours(schedule.hourLocal, schedule.minuteLocal, 0, 0);
754
+ next.setUTCHours(schedule.hourLocal, schedule.minuteLocal, 0, 0);
745
755
  return localToUtc(next, tz);
746
756
  }
747
757
  function addDays(d, days) {
748
758
  const next = new Date(d.getTime());
749
- next.setDate(next.getDate() + days);
759
+ next.setUTCDate(next.getUTCDate() + days);
750
760
  return next;
751
761
  }
752
762
  function lastDayOfMonth(year, monthIndex) {
753
- return new Date(year, monthIndex + 1, 0).getDate();
763
+ return new Date(Date.UTC(year, monthIndex + 1, 0)).getUTCDate();
754
764
  }
755
765
  function wallClock(d, tz) {
756
766
  const offsetMin = tzOffsetMinutes(d, tz);
@@ -778,11 +788,151 @@ function getFormatter(tz) {
778
788
  return fmt;
779
789
  }
780
790
 
791
+ // src/timezone.ts
792
+ var PARTS_FORMATTER_CACHE = /* @__PURE__ */ new Map();
793
+ function isValidIanaTimeZone(value) {
794
+ if (!value.trim()) return false;
795
+ try {
796
+ new Intl.DateTimeFormat("en-US", { timeZone: value }).format();
797
+ return true;
798
+ } catch {
799
+ return false;
800
+ }
801
+ }
802
+ function zonedDateTimeParts(instant, timeZone) {
803
+ if (!isValidIanaTimeZone(timeZone)) {
804
+ throw new RangeError(`Invalid IANA timezone: ${timeZone}`);
805
+ }
806
+ if (!Number.isFinite(instant.getTime())) {
807
+ throw new RangeError("Invalid date");
808
+ }
809
+ const formatter = getPartsFormatter(timeZone);
810
+ const parts = formatter.formatToParts(instant).reduce(
811
+ (result, part) => {
812
+ if (part.type !== "literal") result[part.type] = part.value;
813
+ return result;
814
+ },
815
+ {}
816
+ );
817
+ const year = Number(parts.year);
818
+ const month = Number(parts.month);
819
+ const day = Number(parts.day);
820
+ const hour = Number(parts.hour);
821
+ const minute = Number(parts.minute);
822
+ return {
823
+ date: `${year}-${pad2(month)}-${pad2(day)}`,
824
+ time: `${pad2(hour)}:${pad2(minute)}`,
825
+ weekday: new Date(Date.UTC(year, month - 1, day)).getUTCDay(),
826
+ dayOfMonth: day
827
+ };
828
+ }
829
+ function zonedDateTimeToUtc(date, time, timeZone) {
830
+ if (!isValidIanaTimeZone(timeZone)) {
831
+ throw new RangeError(`Invalid IANA timezone: ${timeZone}`);
832
+ }
833
+ const dateMatch = /^(\d{4})-(\d{2})-(\d{2})$/.exec(date);
834
+ const timeMatch = /^(\d{2}):(\d{2})$/.exec(time);
835
+ if (!dateMatch || !timeMatch) throw new RangeError("Invalid local date or time");
836
+ const year = Number(dateMatch[1]);
837
+ const month = Number(dateMatch[2]);
838
+ const day = Number(dateMatch[3]);
839
+ const hour = Number(timeMatch[1]);
840
+ const minute = Number(timeMatch[2]);
841
+ const naive = Date.UTC(year, month - 1, day, hour, minute, 0, 0);
842
+ const calendarCheck = new Date(naive);
843
+ if (calendarCheck.getUTCFullYear() !== year || calendarCheck.getUTCMonth() !== month - 1 || calendarCheck.getUTCDate() !== day || hour > 23 || minute > 59) {
844
+ throw new RangeError("Invalid local date or time");
845
+ }
846
+ const offsets = new Set(
847
+ [-36, -12, 0, 12, 36].map(
848
+ (hours) => timeZoneOffsetMinutes(new Date(naive + hours * 36e5), timeZone)
849
+ )
850
+ );
851
+ const candidates = [...offsets].map((offset) => new Date(naive - offset * 6e4)).filter((candidate2) => {
852
+ const roundTrip = zonedDateTimeParts(candidate2, timeZone);
853
+ return roundTrip.date === date && roundTrip.time === time;
854
+ }).sort((left, right) => left.getTime() - right.getTime());
855
+ const candidate = candidates[0];
856
+ if (!candidate) {
857
+ throw new RangeError("This local time does not exist in the selected timezone");
858
+ }
859
+ return candidate;
860
+ }
861
+ function zonedDateEndToUtc(date, timeZone) {
862
+ const lastMinute = zonedDateTimeToUtc(date, "23:59", timeZone);
863
+ return new Date(lastMinute.getTime() + 59999);
864
+ }
865
+ function timeZoneOffsetMinutes(instant, timeZone) {
866
+ const parts = getPartsFormatter(timeZone).formatToParts(instant).reduce((result, part) => {
867
+ if (part.type !== "literal") result[part.type] = part.value;
868
+ return result;
869
+ }, {});
870
+ const asUtc = Date.UTC(
871
+ Number(parts.year),
872
+ Number(parts.month) - 1,
873
+ Number(parts.day),
874
+ Number(parts.hour),
875
+ Number(parts.minute),
876
+ Number(parts.second)
877
+ );
878
+ return Math.round((asUtc - instant.getTime()) / 6e4);
879
+ }
880
+ function getPartsFormatter(timeZone) {
881
+ const cached = PARTS_FORMATTER_CACHE.get(timeZone);
882
+ if (cached) return cached;
883
+ const formatter = new Intl.DateTimeFormat("en-US", {
884
+ timeZone,
885
+ hourCycle: "h23",
886
+ year: "numeric",
887
+ month: "2-digit",
888
+ day: "2-digit",
889
+ hour: "2-digit",
890
+ minute: "2-digit",
891
+ second: "2-digit"
892
+ });
893
+ PARTS_FORMATTER_CACHE.set(timeZone, formatter);
894
+ return formatter;
895
+ }
896
+ function pad2(value) {
897
+ return String(value).padStart(2, "0");
898
+ }
899
+
781
900
  // src/contract/endpoints.ts
782
901
  var endpoints = {
902
+ "GET /v1/apps/:appId/search": {},
903
+ "POST /v1/apps/:appId/delivery-diagnostics": {},
904
+ "GET /v1/workspaces/:wid/portal": {},
905
+ "PUT /v1/workspaces/:wid/portal": {},
906
+ "GET /v1/workspaces/:wid/portal/slug-available": {},
907
+ "PUT /v1/workspaces/:wid/portal/apps/:appId": {},
908
+ "POST /v1/workspaces/:wid/portal/publish": {},
909
+ "POST /v1/workspaces/:wid/portal/unpublish": {},
910
+ "GET /v1/workspaces/:wid/portal/preview/:appId": {},
911
+ "PATCH /v1/apps/:appId/requests/portal-visibility": {},
912
+ "GET /v1/portal/:portalSlug": {},
913
+ "GET /v1/portal/:portalSlug/apps/:appSlug/requests": {},
914
+ "GET /v1/portal/:portalSlug/apps/:appSlug/requests/counts": {},
915
+ "GET /v1/portal/:portalSlug/apps/:appSlug/requests/:requestId": {},
916
+ "POST /v1/portal/:portalSlug/auth/start": {},
917
+ "POST /v1/portal/:portalSlug/auth/verify": {},
918
+ "GET /v1/portal/:portalSlug/session": {},
919
+ "DELETE /v1/portal/:portalSlug/session": {},
920
+ "GET /v1/portal/:portalSlug/apps/:appSlug/votes": {},
921
+ "POST /v1/portal/:portalSlug/apps/:appSlug/requests": {},
922
+ "PUT /v1/portal/:portalSlug/apps/:appSlug/requests/:requestId/vote": {},
923
+ "POST /v1/sdk/clients": {},
924
+ "POST /v1/sdk/clients/:id/end": {},
925
+ "GET /v1/sdk/clients/:id/instructions": {},
926
+ "POST /v1/sdk/presentations/authorize": {},
927
+ "POST /v1/sdk/presentations/:id/receipt": {},
783
928
  "GET /v1/me": {},
929
+ "PATCH /v1/me": {},
930
+ "PATCH /v1/me/onboarding": {},
931
+ "GET /v1/features": {},
932
+ "GET /v1/signup-status": {},
784
933
  "GET /v1/workspaces": {},
785
934
  "POST /v1/workspaces": {},
935
+ "PATCH /v1/workspaces/:wid": {},
786
936
  "GET /v1/workspaces/:wid/members": {},
787
937
  "GET /v1/workspaces/:wid/invites": {},
788
938
  "POST /v1/workspaces/:wid/invites": {},
@@ -791,11 +941,18 @@ var endpoints = {
791
941
  "GET /v1/workspaces/:wid/apps": {},
792
942
  "POST /v1/workspaces/:wid/apps": {},
793
943
  "GET /v1/workspaces/:wid/api-tokens": {},
944
+ "GET /v1/workspaces/:wid/ai-connections": {},
945
+ "PATCH /v1/workspaces/:wid/ai-connections/:id": {},
946
+ "POST /v1/workspaces/:wid/ai-connections/:id/revoke": {},
947
+ "GET /v1/workspaces/:wid/ai-connections/:id/activity": {},
948
+ "POST /v1/mcp/consent": {},
794
949
  "POST /v1/workspaces/:wid/api-tokens": {},
795
950
  "DELETE /v1/workspaces/:wid/api-tokens/:tokenId": {},
796
951
  "GET /v1/apps/:appId": {},
797
952
  "PATCH /v1/apps/:appId": {},
798
953
  "DELETE /v1/apps/:appId": {},
954
+ "GET /v1/apps/:appId/onboarding": {},
955
+ "PATCH /v1/apps/:appId/onboarding": {},
799
956
  "POST /v1/apps/:appId/sdk/subject-tokens": {},
800
957
  // ---------- outbound analytics integrations ----------
801
958
  "GET /v1/apps/:appId/integrations": {},
@@ -852,6 +1009,10 @@ var endpoints = {
852
1009
  "POST /v1/sdk/ingest": {},
853
1010
  "GET /v1/sdk/armed-triggers": {},
854
1011
  "POST /v1/sdk/consent": {},
1012
+ "PATCH /v1/apps/:appId/users/properties": {},
1013
+ "POST /v1/sdk/user-properties": {},
1014
+ "GET /v1/apps/:appId/personalization/fields": {},
1015
+ "POST /v1/apps/:appId/personalization/preview": {},
855
1016
  "POST /v1/sdk/identify": {},
856
1017
  "POST /v1/sdk/responses": {},
857
1018
  // GDPR
@@ -956,6 +1117,9 @@ var endpoints = {
956
1117
  "GET /v1/apps/:appId/request-settings": {},
957
1118
  "PUT /v1/apps/:appId/request-settings": {},
958
1119
  "GET /v1/apps/:appId/request-settings/slug-available": {},
1120
+ /** Multipart `file` field; the processed logo URL is saved into branding.logoUrl. */
1121
+ "POST /v1/apps/:appId/request-settings/logo": {},
1122
+ "DELETE /v1/apps/:appId/request-settings/logo": {},
959
1123
  "POST /v1/apps/:appId/requests/seed-segments": {},
960
1124
  // ---------- feature requests — SDK (write-key) ----------
961
1125
  "GET /v1/sdk/requests": {},
@@ -983,8 +1147,15 @@ var endpoints = {
983
1147
  "GET /v1/workspaces/:wid/billing/periods": {},
984
1148
  // ---------- super admin ----------
985
1149
  "GET /v1/admin/session": {},
1150
+ "GET /v1/admin/feature-flags": {},
1151
+ "PATCH /v1/admin/feature-flags/:key": {},
986
1152
  "GET /v1/admin/customers": {},
987
1153
  "GET /v1/admin/customers/:workspaceId": {},
1154
+ "POST /v1/admin/customers/:workspaceId/permanent-deletion": {},
1155
+ "GET /v1/admin/dashboard-users": {},
1156
+ "POST /v1/admin/dashboard-users/:userId/permanent-deletion": {},
1157
+ "GET /v1/admin/deletion-jobs/:jobId": {},
1158
+ "POST /v1/admin/deletion-jobs/:jobId/retry": {},
988
1159
  "POST /v1/admin/customers/:workspaceId/billing-events/:eventId/replay": {},
989
1160
  "POST /v1/admin/customers/:workspaceId/grants": {},
990
1161
  "POST /v1/admin/customers/:workspaceId/grants/:grantId/extend": {},
@@ -997,7 +1168,43 @@ var endpoints = {
997
1168
  // ---------- feature requests — public web roadmap (no auth) ----------
998
1169
  "GET /v1/public/roadmap/:slug": {},
999
1170
  "GET /v1/public/roadmap/:slug/r/:requestId": {},
1000
- "GET /v1/public/roadmap/:slug/branding": {}
1171
+ "GET /v1/public/roadmap/:slug/branding": {},
1172
+ "GET /v1/apps/:appId/help/articles": {},
1173
+ "POST /v1/apps/:appId/help/articles": {},
1174
+ "GET /v1/apps/:appId/help/articles/:documentId": {},
1175
+ "PUT /v1/apps/:appId/help/articles/:documentId": {},
1176
+ "POST /v1/apps/:appId/help/articles/:documentId/lifecycle": {},
1177
+ "GET /v1/apps/:appId/changelog": {},
1178
+ "POST /v1/apps/:appId/changelog": {},
1179
+ "GET /v1/apps/:appId/changelog/:documentId": {},
1180
+ "PUT /v1/apps/:appId/changelog/:documentId": {},
1181
+ "POST /v1/apps/:appId/changelog/:documentId/lifecycle": {},
1182
+ "GET /v1/apps/:appId/help/collections": {},
1183
+ "POST /v1/apps/:appId/help/collections": {},
1184
+ "PATCH /v1/apps/:appId/help/collections/:collectionId": {},
1185
+ "POST /v1/apps/:appId/help/collections/:collectionId/position": {},
1186
+ "POST /v1/apps/:appId/help/articles/:documentId/position": {},
1187
+ "GET /v1/apps/:appId/roadmap": {},
1188
+ "POST /v1/apps/:appId/roadmap": {},
1189
+ "GET /v1/apps/:appId/roadmap/:itemId": {},
1190
+ "PUT /v1/apps/:appId/roadmap/:itemId": {},
1191
+ "POST /v1/apps/:appId/roadmap/:itemId/status": {},
1192
+ "POST /v1/apps/:appId/roadmap/:itemId/lifecycle": {},
1193
+ "GET /v1/portal/:portalSlug/apps/:appSlug/help/collections": {},
1194
+ "GET /v1/portal/:portalSlug/apps/:appSlug/help/collections/:collectionId": {},
1195
+ "GET /v1/portal/:portalSlug/apps/:appSlug/help/articles": {},
1196
+ "GET /v1/portal/:portalSlug/apps/:appSlug/help/articles/:documentId": {},
1197
+ "GET /v1/portal/:portalSlug/apps/:appSlug/changelog": {},
1198
+ "GET /v1/portal/:portalSlug/apps/:appSlug/changelog/:documentId": {},
1199
+ "GET /v1/portal/:portalSlug/apps/:appSlug/roadmap": {},
1200
+ "GET /v1/portal/:portalSlug/apps/:appSlug/roadmap/:itemId": {},
1201
+ "GET /v1/portal/:portalSlug/apps/:appSlug/requests/:requestId/changelog": {},
1202
+ "GET /v1/portal/:portalSlug/apps/:appSlug/roadmap/:itemId/changelog": {},
1203
+ "GET /v1/apps/:appId/portal-content/link-targets": {},
1204
+ // Binary routes use multipart/stream transports, not the JSON client helper.
1205
+ "POST /v1/apps/:appId/portal-content/assets/:kind/:documentId": {},
1206
+ "GET /v1/apps/:appId/portal-content/assets/:assetId": {},
1207
+ "GET /v1/portal/:portalSlug/apps/:appSlug/assets/:assetId": {}
1001
1208
  };
1002
1209
 
1003
1210
  // src/schemas/index.ts
@@ -1005,24 +1212,74 @@ var schemas_exports = {};
1005
1212
  __export(schemas_exports, {
1006
1213
  acceptWorkspaceInviteSchema: () => acceptWorkspaceInviteSchema,
1007
1214
  apiTokenScopeSchema: () => apiTokenScopeSchema,
1215
+ contentActionSchema: () => contentActionSchema,
1216
+ contentBodySchema: () => contentBodySchema,
1217
+ contentKindSchema: () => contentKindSchema,
1218
+ contentLinkQuerySchema: () => contentLinkQuerySchema,
1219
+ contentLinkSchema: () => contentLinkSchema,
1220
+ contentPageQuerySchema: () => contentPageQuerySchema,
1221
+ contentQuerySchema: () => contentQuerySchema,
1222
+ contentStateSchema: () => contentStateSchema,
1008
1223
  createApiTokenSchema: () => createApiTokenSchema,
1009
1224
  createAppSchema: () => createAppSchema,
1225
+ createCollectionSchema: () => createCollectionSchema,
1226
+ createDocumentSchema: () => createDocumentSchema,
1227
+ createRoadmapSchema: () => createRoadmapSchema,
1010
1228
  createWorkspaceSchema: () => createWorkspaceSchema,
1011
1229
  createWriteKeySchema: () => createWriteKeySchema,
1230
+ deferCurrentUserOnboardingSchema: () => deferCurrentUserOnboardingSchema,
1231
+ deliveryPlatformsSchema: () => deliveryPlatformsSchema,
1232
+ documentDraftSchema: () => documentDraftSchema,
1012
1233
  emailSchema: () => emailSchema,
1013
1234
  inviteMemberSchema: () => inviteMemberSchema,
1014
1235
  isoDateTimeSchema: () => isoDateTimeSchema,
1015
1236
  loginMagicLinkConsumeRequestSchema: () => loginMagicLinkConsumeRequestSchema,
1016
1237
  loginMagicLinkRequestSchema: () => loginMagicLinkRequestSchema,
1017
1238
  loginPasswordRequestSchema: () => loginPasswordRequestSchema,
1239
+ mcpCapabilitySchema: () => mcpCapabilitySchema,
1240
+ mcpConsentSchema: () => mcpConsentSchema,
1241
+ mcpGrantSchema: () => mcpGrantSchema,
1242
+ mcpPageSchema: () => mcpPageSchema,
1243
+ mcpSearchSchema: () => mcpSearchSchema,
1244
+ mcpUpdateConnectionSchema: () => mcpUpdateConnectionSchema,
1245
+ moveRoadmapSchema: () => moveRoadmapSchema,
1246
+ onboardingGoalSchema: () => onboardingGoalSchema,
1247
+ onboardingPushChoiceSchema: () => onboardingPushChoiceSchema,
1248
+ onboardingStatusSchema: () => onboardingStatusSchema,
1249
+ onboardingStepSchema: () => onboardingStepSchema,
1018
1250
  passwordSchema: () => passwordSchema,
1019
1251
  platformSchema: () => platformSchema,
1252
+ portalAssetUploadKeySchema: () => portalAssetUploadKeySchema,
1253
+ portalAuthStartSchema: () => portalAuthStartSchema,
1254
+ portalAuthVerifySchema: () => portalAuthVerifySchema,
1255
+ portalEmailSchema: () => portalEmailSchema,
1256
+ portalRequestQuerySchema: () => portalRequestQuerySchema,
1257
+ portalSlugSchema: () => portalSlugSchema,
1258
+ portalSubmissionSchema: () => portalSubmissionSchema,
1259
+ portalVisibilitySchema: () => portalVisibilitySchema,
1260
+ portalVoteSchema: () => portalVoteSchema,
1261
+ reorderContentSchema: () => reorderContentSchema,
1262
+ roadmapQuerySchema: () => roadmapQuerySchema,
1263
+ roadmapStatusSchema: () => roadmapStatusSchema,
1020
1264
  rotateWriteKeySchema: () => rotateWriteKeySchema,
1265
+ saveDocumentSchema: () => saveDocumentSchema,
1266
+ saveRoadmapSchema: () => saveRoadmapSchema,
1021
1267
  signupRequestSchema: () => signupRequestSchema,
1022
1268
  slugSchema: () => slugSchema,
1269
+ subjectRefSchema: () => subjectRefSchema,
1023
1270
  updateAppSchema: () => updateAppSchema,
1271
+ updateCollectionSchema: () => updateCollectionSchema,
1272
+ updateCurrentUserSchema: () => updateCurrentUserSchema,
1273
+ updateOnboardingSchema: () => updateOnboardingSchema,
1274
+ updatePortalAppSchema: () => updatePortalAppSchema,
1275
+ updatePortalSchema: () => updatePortalSchema,
1276
+ updateWorkspaceSchema: () => updateWorkspaceSchema,
1024
1277
  uuidSchema: () => uuidSchema,
1278
+ webAppConfigSchema: () => webAppConfigSchema,
1279
+ webOriginSchema: () => webOriginSchema,
1280
+ webPresentationSchema: () => webPresentationSchema,
1025
1281
  workspaceRoleSchema: () => workspaceRoleSchema,
1282
+ workspaceTimezoneSchema: () => workspaceTimezoneSchema,
1026
1283
  writeKeyEnvironmentSchema: () => writeKeyEnvironmentSchema
1027
1284
  });
1028
1285
  var slugSchema = zod.z.string().min(1).max(64).regex(/^[a-z0-9-]+$/, "Must be lowercase, digits, and dashes only");
@@ -1049,21 +1306,199 @@ var loginMagicLinkRequestSchema = zod.z.object({
1049
1306
  var loginMagicLinkConsumeRequestSchema = zod.z.object({
1050
1307
  token: zod.z.string().min(16).max(512)
1051
1308
  });
1052
- var platformSchema = zod.z.enum(["ios", "android", "react-native", "flutter"]);
1053
- var writeKeyEnvironmentSchema = zod.z.enum(["production", "staging", "development"]);
1054
- var apiTokenScopeSchema = zod.z.enum(["sdk:subjects", "push.transactional"]);
1309
+ var updateCurrentUserSchema = zod.z.object({
1310
+ name: zod.z.string().trim().min(1).max(120).optional()
1311
+ }).strict().refine((value) => Object.keys(value).length > 0, {
1312
+ message: "At least one field is required"
1313
+ });
1314
+ var deliveryPlatformsSchema = zod.z.array(zod.z.enum(["ios", "android", "web"])).min(1).max(3).transform((values) => [...new Set(values)]);
1315
+ var webPresentationSchema = zod.z.object({
1316
+ layout: zod.z.enum(["modal", "card", "panel"]).optional(),
1317
+ size: zod.z.enum(["compact", "standard", "wide"]).optional(),
1318
+ position: zod.z.enum(["left", "right"]).optional(),
1319
+ backdrop: zod.z.boolean().optional()
1320
+ }).strict();
1321
+ var webOriginSchema = zod.z.string().max(2048).refine((value) => {
1322
+ try {
1323
+ const url = new URL(value);
1324
+ return url.origin === value && !url.username && !url.password && (url.protocol === "https:" || url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname));
1325
+ } catch {
1326
+ return false;
1327
+ }
1328
+ }, "Use an exact HTTPS origin, or an HTTP localhost origin for development");
1329
+ var webAppConfigSchema = zod.z.object({
1330
+ allowedOrigins: zod.z.array(webOriginSchema).max(30).transform((values) => [...new Set(values)])
1331
+ }).strict();
1332
+
1333
+ // src/types/portal.ts
1334
+ var PORTAL_RESERVED_SLUGS = [
1335
+ "www",
1336
+ "app",
1337
+ "api",
1338
+ "admin",
1339
+ "auth",
1340
+ "portal",
1341
+ "docs",
1342
+ "status",
1343
+ "mail",
1344
+ "support",
1345
+ "login",
1346
+ "logout",
1347
+ "signup",
1348
+ "billing",
1349
+ "dashboard",
1350
+ "cdn",
1351
+ "assets",
1352
+ "static",
1353
+ "smtp",
1354
+ "ftp",
1355
+ "help",
1356
+ "account",
1357
+ "accounts",
1358
+ "developer"
1359
+ ];
1360
+ var PORTAL_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,46})[a-z0-9]$/;
1361
+ function validPortalSlug(slug) {
1362
+ return PORTAL_SLUG_PATTERN.test(slug) && !PORTAL_RESERVED_SLUGS.includes(slug);
1363
+ }
1364
+ function suggestPortalSlug(name) {
1365
+ const value = name.toLowerCase().normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 48).replace(/-$/, "");
1366
+ return validPortalSlug(value) ? value : value.length >= 3 ? `${value.slice(0, 40)}-team` : "";
1367
+ }
1368
+ function buildPortalUrl(slug, baseDomain = "usergist.com", appSlug) {
1369
+ if (!validPortalSlug(slug) || !/^[a-z0-9.-]+$/i.test(baseDomain)) throw new Error("Invalid portal address");
1370
+ const base = `https://${slug}.${baseDomain}`;
1371
+ return appSlug ? `${base}/${encodeURIComponent(appSlug)}/requests` : base;
1372
+ }
1373
+
1374
+ // src/schemas/portal.ts
1375
+ var portalSlugSchema = zod.z.string().refine(
1376
+ validPortalSlug,
1377
+ "Use 3\u201348 lowercase letters, numbers, or interior hyphens. This name must not be reserved."
1378
+ );
1379
+ var updatePortalSchema = zod.z.object({
1380
+ displayName: zod.z.string().trim().min(1).max(100).optional(),
1381
+ slug: portalSlugSchema.optional(),
1382
+ setupDismissed: zod.z.boolean().optional()
1383
+ }).strict();
1384
+ var updatePortalAppSchema = zod.z.object({ slug: portalSlugSchema, enabled: zod.z.boolean() }).strict();
1385
+ var portalVisibilitySchema = zod.z.object({ ids: zod.z.array(zod.z.string().uuid()).min(1).max(100), visible: zod.z.boolean() }).strict();
1386
+ var portalEmailSchema = zod.z.string().trim().email().max(254).transform((value) => value.toLowerCase());
1387
+ var portalAuthStartSchema = zod.z.object({ email: portalEmailSchema }).strict();
1388
+ var portalAuthVerifySchema = zod.z.object({ email: portalEmailSchema, code: zod.z.string().regex(/^\d{6}$/) }).strict();
1389
+ var portalSubmissionSchema = zod.z.object({
1390
+ title: zod.z.string().trim().min(1).max(120),
1391
+ description: zod.z.string().trim().min(1).max(1500),
1392
+ idempotencyKey: zod.z.string().uuid(),
1393
+ feedbackConsent: zod.z.literal(true)
1394
+ }).strict();
1395
+ var portalVoteSchema = zod.z.object({ vote: zod.z.boolean(), feedbackConsent: zod.z.literal(true) }).strict();
1396
+ var portalRequestQuerySchema = zod.z.object({
1397
+ q: zod.z.string().trim().max(200).optional(),
1398
+ status: zod.z.enum(["under_review", "planned", "in_progress", "shipped", "declined"]).optional(),
1399
+ sort: zod.z.enum(["top", "newest", "status_changed"]).default("top"),
1400
+ page: zod.z.coerce.number().int().min(1).max(1e5).default(1),
1401
+ limit: zod.z.coerce.number().int().min(1).max(100).default(20)
1402
+ }).strict();
1403
+
1404
+ // src/schemas/apps.ts
1405
+ var workspaceTimezoneSchema = zod.z.string().trim().min(1).max(64).refine(isValidIanaTimeZone, "Enter a valid IANA timezone");
1406
+ var platformSchema = zod.z.enum([
1407
+ "ios",
1408
+ "android",
1409
+ "react-native",
1410
+ "expo",
1411
+ "flutter",
1412
+ "web"
1413
+ ]);
1414
+ var writeKeyEnvironmentSchema = zod.z.enum([
1415
+ "production",
1416
+ "staging",
1417
+ "development"
1418
+ ]);
1419
+ var onboardingGoalSchema = zod.z.enum([
1420
+ "feedback",
1421
+ "survey",
1422
+ "inapp",
1423
+ "push",
1424
+ "requests"
1425
+ ]);
1426
+ var onboardingStatusSchema = zod.z.enum([
1427
+ "in_progress",
1428
+ "deferred",
1429
+ "completed"
1430
+ ]);
1431
+ var onboardingStepSchema = zod.z.enum([
1432
+ "connect",
1433
+ "verify",
1434
+ "experience",
1435
+ "push",
1436
+ "launch"
1437
+ ]);
1438
+ var onboardingPushChoiceSchema = zod.z.enum([
1439
+ "pending",
1440
+ "configured",
1441
+ "skipped"
1442
+ ]);
1443
+ var apiTokenScopeSchema = zod.z.enum([
1444
+ "sdk:subjects",
1445
+ "push.transactional",
1446
+ "users.properties.write"
1447
+ ]);
1055
1448
  var createAppSchema = zod.z.object({
1056
1449
  name: zod.z.string().min(1).max(120),
1057
1450
  slug: slugSchema.optional(),
1058
1451
  platforms: zod.z.array(platformSchema).min(1).max(8),
1059
- environment: writeKeyEnvironmentSchema.default("production")
1452
+ environment: writeKeyEnvironmentSchema.default("production"),
1453
+ onboardingGoal: onboardingGoalSchema.optional(),
1454
+ setupMode: zod.z.enum(["sdk", "portal"]).optional(),
1455
+ portal: zod.z.object({
1456
+ appSlug: portalSlugSchema,
1457
+ company: zod.z.object({
1458
+ displayName: zod.z.string().trim().min(1).max(100),
1459
+ slug: portalSlugSchema
1460
+ }).strict().optional()
1461
+ }).strict().optional(),
1462
+ webConfig: webAppConfigSchema.optional()
1463
+ });
1464
+ var updateOnboardingSchema = zod.z.object({
1465
+ action: zod.z.enum([
1466
+ "resume",
1467
+ "defer",
1468
+ "create_first_inapp",
1469
+ "first_inapp_completed",
1470
+ "create_first_feedback",
1471
+ "first_feedback_completed",
1472
+ "push_configured",
1473
+ "push_skipped",
1474
+ "complete"
1475
+ ]).optional(),
1476
+ step: onboardingStepSchema.optional(),
1477
+ question: zod.z.string().trim().min(1).max(500).optional(),
1478
+ message: zod.z.object({
1479
+ title: zod.z.string().trim().min(1).max(200),
1480
+ body: zod.z.string().trim().min(1).max(500),
1481
+ buttonLabel: zod.z.string().trim().min(1).max(40),
1482
+ format: zod.z.enum(["modal", "slideup"])
1483
+ }).strict().optional()
1484
+ }).refine((value) => Boolean(value.action || value.step), {
1485
+ message: "Provide an onboarding action or step"
1486
+ }).refine(
1487
+ (value) => value.action !== "create_first_feedback" || Boolean(value.question),
1488
+ { message: "Provide a question for the first feedback experience" }
1489
+ );
1490
+ var deferCurrentUserOnboardingSchema = zod.z.object({
1491
+ action: zod.z.literal("defer")
1060
1492
  });
1061
1493
  var updateAppSchema = zod.z.object({
1062
1494
  name: zod.z.string().min(1).max(120).optional(),
1063
1495
  platforms: zod.z.array(platformSchema).min(1).max(8).optional(),
1064
1496
  piiAllowList: zod.z.array(zod.z.string().min(1).max(120)).max(128).optional(),
1065
- lifecycleEventsEnabled: zod.z.boolean().optional()
1066
- }).refine((v) => Object.keys(v).length > 0, { message: "At least one field is required" });
1497
+ lifecycleEventsEnabled: zod.z.boolean().optional(),
1498
+ webConfig: webAppConfigSchema.optional()
1499
+ }).refine((v) => Object.keys(v).length > 0, {
1500
+ message: "At least one field is required"
1501
+ });
1067
1502
  var createWriteKeySchema = zod.z.object({
1068
1503
  label: zod.z.string().min(1).max(120).optional(),
1069
1504
  environment: writeKeyEnvironmentSchema.default("production")
@@ -1078,8 +1513,15 @@ var createApiTokenSchema = zod.z.object({
1078
1513
  expiresInDays: zod.z.number().int().min(1).max(365).default(90)
1079
1514
  });
1080
1515
  var createWorkspaceSchema = zod.z.object({
1081
- name: zod.z.string().min(1).max(120),
1082
- slug: slugSchema.optional()
1516
+ name: zod.z.string().trim().min(1).max(120),
1517
+ slug: slugSchema.optional(),
1518
+ timezone: workspaceTimezoneSchema.default("UTC")
1519
+ });
1520
+ var updateWorkspaceSchema = zod.z.object({
1521
+ name: zod.z.string().trim().min(1).max(120).optional(),
1522
+ timezone: workspaceTimezoneSchema.optional()
1523
+ }).strict().refine((value) => Object.keys(value).length > 0, {
1524
+ message: "At least one field is required"
1083
1525
  });
1084
1526
  var inviteMemberSchema = zod.z.object({
1085
1527
  email: emailSchema,
@@ -1089,6 +1531,714 @@ var acceptWorkspaceInviteSchema = zod.z.object({
1089
1531
  token: zod.z.string().regex(/^[a-f0-9]{64}$/i, "Invalid invitation token")
1090
1532
  });
1091
1533
 
1534
+ // src/types/portal-content.ts
1535
+ function emptyDocumentDraft() {
1536
+ return {
1537
+ title: "",
1538
+ summary: "",
1539
+ body: { type: "doc", content: [{ type: "paragraph" }] },
1540
+ collectionId: null,
1541
+ category: "improved",
1542
+ releaseDate: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
1543
+ version: "",
1544
+ links: []
1545
+ };
1546
+ }
1547
+ function contentText(node2) {
1548
+ return node2.text ?? (node2.content ?? []).map(contentText).join(node2.type === "paragraph" || node2.type === "heading" ? "" : "\n");
1549
+ }
1550
+ function contentAssetIds(node2) {
1551
+ return [
1552
+ .../* @__PURE__ */ new Set([
1553
+ ...node2.type === "image" && node2.attrs?.assetId ? [node2.attrs.assetId] : [],
1554
+ ...(node2.content ?? []).flatMap(contentAssetIds)
1555
+ ])
1556
+ ];
1557
+ }
1558
+ function contentSlug(title) {
1559
+ return title.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 96).replace(/-$/, "") || "article";
1560
+ }
1561
+ function safeContentHref(href) {
1562
+ return /^(https?:\/\/|mailto:|\/[^/]|#[a-zA-Z0-9_-])/.test(href) && !/[\u0000-\u0020\\]/.test(href);
1563
+ }
1564
+
1565
+ // src/schemas/portal-content.ts
1566
+ var uuid = zod.z.string().uuid();
1567
+ var contentKindSchema = zod.z.enum(["article", "changelog"]);
1568
+ var contentStateSchema = zod.z.enum(["draft", "published", "archived"]);
1569
+ var roadmapStatusSchema = zod.z.enum(["planned", "in_progress", "shipped"]);
1570
+ var contentLinkSchema = zod.z.object({ kind: zod.z.enum(["request", "roadmap"]), id: uuid }).strict();
1571
+ var mark = zod.z.object({
1572
+ type: zod.z.enum(["bold", "italic", "code", "link"]),
1573
+ attrs: zod.z.object({ href: zod.z.string().max(2048).refine(safeContentHref, "Use a safe link URL") }).strict().optional()
1574
+ }).strict().refine((m) => m.type === "link" ? Boolean(m.attrs) : !m.attrs);
1575
+ var node = zod.z.lazy(
1576
+ () => zod.z.object({
1577
+ type: zod.z.enum([
1578
+ "doc",
1579
+ "paragraph",
1580
+ "heading",
1581
+ "text",
1582
+ "bulletList",
1583
+ "orderedList",
1584
+ "listItem",
1585
+ "blockquote",
1586
+ "codeBlock",
1587
+ "hardBreak",
1588
+ "image"
1589
+ ]),
1590
+ text: zod.z.string().max(1e5).optional(),
1591
+ attrs: zod.z.object({
1592
+ level: zod.z.number().int().min(2).max(3).optional(),
1593
+ start: zod.z.number().int().min(1).max(1e4).optional(),
1594
+ language: zod.z.string().max(40).nullable().optional(),
1595
+ assetId: uuid.optional(),
1596
+ alt: zod.z.string().max(500).optional()
1597
+ }).strict().optional(),
1598
+ marks: zod.z.array(mark).max(4).optional(),
1599
+ content: zod.z.array(node).max(5e3).optional()
1600
+ }).strict()
1601
+ );
1602
+ var contentBodySchema = zod.z.unknown().superRefine((value, ctx) => {
1603
+ let count = 0, invalid = false;
1604
+ const walk = (v, depth) => {
1605
+ if (depth > 20 || ++count > 5e3) {
1606
+ invalid = true;
1607
+ return;
1608
+ }
1609
+ if (v && typeof v === "object" && "content" in v && Array.isArray(v.content))
1610
+ for (const child of v.content) {
1611
+ if (invalid) break;
1612
+ walk(child, depth + 1);
1613
+ }
1614
+ };
1615
+ walk(value, 0);
1616
+ if (invalid)
1617
+ ctx.addIssue({
1618
+ code: zod.z.ZodIssueCode.custom,
1619
+ message: "Document is too deeply nested or contains too many blocks"
1620
+ });
1621
+ }).pipe(node).superRefine((value, ctx) => {
1622
+ if (value.type !== "doc" || contentText(value).length > 1e5)
1623
+ ctx.addIssue({
1624
+ code: zod.z.ZodIssueCode.custom,
1625
+ message: "Invalid document or body exceeds 100,000 characters"
1626
+ });
1627
+ const walk = (v, root = false) => {
1628
+ const blocks = ["paragraph", "heading", "bulletList", "orderedList", "blockquote", "codeBlock", "image"];
1629
+ const children = v.content ?? [];
1630
+ const allowed = v.type === "doc" || v.type === "blockquote" ? blocks : v.type === "listItem" ? blocks.filter((t) => t !== "heading") : v.type === "bulletList" || v.type === "orderedList" ? ["listItem"] : v.type === "paragraph" || v.type === "heading" ? ["text", "hardBreak"] : v.type === "codeBlock" ? ["text"] : [];
1631
+ const attrs = Object.keys(v.attrs ?? {});
1632
+ const allowedAttrs = v.type === "heading" ? ["level"] : v.type === "orderedList" ? ["start"] : v.type === "codeBlock" ? ["language"] : v.type === "image" ? ["assetId", "alt"] : [];
1633
+ if (!root && v.type === "doc" || v.type === "text" && (!v.text || v.content) || v.type !== "text" && (v.text !== void 0 || Boolean(v.marks?.length)) || v.type === "image" && (!v.attrs?.assetId || v.content) || v.type === "heading" && !v.attrs?.level || attrs.some((a) => !allowedAttrs.includes(a)) || children.some((c) => !allowed.includes(c.type)) || v.type === "listItem" && children[0]?.type !== "paragraph" || ["bulletList", "orderedList", "blockquote", "doc"].includes(v.type) && !children.length || v.type === "codeBlock" && children.some((c) => c.marks?.length))
1634
+ ctx.addIssue({ code: zod.z.ZodIssueCode.custom, message: "Invalid content block" });
1635
+ v.content?.forEach((c) => walk(c));
1636
+ };
1637
+ walk(value, true);
1638
+ });
1639
+ var documentDraftSchema = zod.z.object({
1640
+ title: zod.z.string().trim().max(160),
1641
+ summary: zod.z.string().max(280),
1642
+ body: contentBodySchema,
1643
+ collectionId: uuid.nullable(),
1644
+ category: zod.z.enum(["new", "improved", "fixed"]),
1645
+ releaseDate: zod.z.string().regex(/^\d{4}-\d{2}-\d{2}$/).refine(
1646
+ (v) => !Number.isNaN(Date.parse(v)) && new Date(v).toISOString().slice(0, 10) === v,
1647
+ "Choose a valid date"
1648
+ ),
1649
+ version: zod.z.string().max(40),
1650
+ links: zod.z.array(contentLinkSchema).max(100)
1651
+ }).strict();
1652
+ var createDocumentSchema = zod.z.object({
1653
+ idempotencyKey: uuid,
1654
+ title: zod.z.string().trim().max(160).optional(),
1655
+ collectionId: uuid.nullable().optional(),
1656
+ links: zod.z.array(contentLinkSchema).max(100).optional()
1657
+ }).strict();
1658
+ var saveDocumentSchema = zod.z.object({ revision: zod.z.number().int().positive(), draft: documentDraftSchema }).strict();
1659
+ var contentActionSchema = zod.z.object({
1660
+ revision: zod.z.number().int().positive(),
1661
+ action: zod.z.enum(["publish", "unpublish", "archive", "restore"])
1662
+ }).strict();
1663
+ var contentQuerySchema = zod.z.object({
1664
+ q: zod.z.string().trim().max(200).optional(),
1665
+ state: contentStateSchema.optional(),
1666
+ collectionId: uuid.optional(),
1667
+ category: zod.z.enum(["new", "improved", "fixed"]).optional(),
1668
+ cursor: zod.z.string().max(2e3).optional(),
1669
+ limit: zod.z.coerce.number().int().min(1).max(50).default(20)
1670
+ }).strict();
1671
+ var createCollectionSchema = zod.z.object({
1672
+ title: zod.z.string().trim().min(1).max(160),
1673
+ description: zod.z.string().max(280),
1674
+ idempotencyKey: uuid
1675
+ }).strict();
1676
+ var contentPageQuerySchema = contentQuerySchema.pick({ cursor: true, limit: true });
1677
+ var portalAssetUploadKeySchema = uuid;
1678
+ var updateCollectionSchema = zod.z.object({
1679
+ revision: zod.z.number().int().positive(),
1680
+ title: zod.z.string().trim().min(1).max(160).optional(),
1681
+ description: zod.z.string().max(280).optional(),
1682
+ archived: zod.z.boolean().optional()
1683
+ }).strict();
1684
+ var reorderContentSchema = zod.z.object({ revision: zod.z.number().int().positive(), direction: zod.z.enum(["up", "down"]) }).strict();
1685
+ var roadmapQuerySchema = zod.z.object({
1686
+ status: roadmapStatusSchema,
1687
+ cursor: zod.z.string().max(2e3).optional(),
1688
+ limit: zod.z.coerce.number().int().min(1).max(50).default(20),
1689
+ archived: zod.z.enum(["true", "false"]).transform((v) => v === "true").optional()
1690
+ }).strict();
1691
+ var roadmapFields = {
1692
+ title: zod.z.string().trim().min(1).max(120),
1693
+ description: zod.z.string().max(1500),
1694
+ requestIds: zod.z.array(uuid).max(100).refine((v) => new Set(v).size === v.length)
1695
+ };
1696
+ var createRoadmapSchema = zod.z.object({ ...roadmapFields, idempotencyKey: uuid, status: roadmapStatusSchema }).strict();
1697
+ var saveRoadmapSchema = zod.z.object({ ...roadmapFields, revision: zod.z.number().int().positive() }).strict();
1698
+ var moveRoadmapSchema = zod.z.object({
1699
+ revision: zod.z.number().int().positive(),
1700
+ status: roadmapStatusSchema,
1701
+ requests: zod.z.array(zod.z.object({ id: uuid, updatedAt: zod.z.string().datetime() }).strict()).max(100).refine((v) => new Set(v.map((r) => r.id)).size === v.length)
1702
+ }).strict();
1703
+ var contentLinkQuerySchema = zod.z.object({
1704
+ kind: zod.z.enum(["request", "roadmap"]),
1705
+ q: zod.z.string().trim().max(200).optional(),
1706
+ cursor: zod.z.string().max(2e3).optional(),
1707
+ limit: zod.z.coerce.number().int().min(1).max(100).default(20),
1708
+ ids: zod.z.string().max(4e3).optional().refine((v) => !v || v.split(",").every((id2) => uuid.safeParse(id2).success), "Invalid linked IDs")
1709
+ }).strict();
1710
+
1711
+ // src/types/mcp.ts
1712
+ var MCP_DOMAINS = ["context", "users", "analytics", "requests", "roadmap", "content", "experiences", "segments", "brand", "portal", "push", "integrations", "sdk", "apps"];
1713
+ var MCP_ACCESS_MODES = ["read_only", "approve_changes", "automatic"];
1714
+ var MCP_CAPABILITIES = [
1715
+ "context:read",
1716
+ "users:read",
1717
+ "analytics:read",
1718
+ "requests:read",
1719
+ "requests:manage",
1720
+ "requests:publish",
1721
+ "roadmap:read",
1722
+ "roadmap:manage",
1723
+ "roadmap:publish",
1724
+ "content:read",
1725
+ "content:manage",
1726
+ "content:publish",
1727
+ "experiences:read",
1728
+ "experiences:manage",
1729
+ "experiences:publish",
1730
+ "segments:read",
1731
+ "segments:manage",
1732
+ "brand:read",
1733
+ "brand:manage",
1734
+ "portal:read",
1735
+ "portal:manage",
1736
+ "portal:publish",
1737
+ "push:read",
1738
+ "push:manage",
1739
+ "push:send",
1740
+ "integrations:read",
1741
+ "integrations:manage",
1742
+ "integrations:send",
1743
+ "sdk:read",
1744
+ "sdk:manage",
1745
+ "apps:read",
1746
+ "apps:manage"
1747
+ ];
1748
+ var MCP_DEFAULT_CAPABILITIES = [
1749
+ "context:read",
1750
+ "users:read",
1751
+ "analytics:read",
1752
+ "requests:read",
1753
+ "roadmap:read",
1754
+ "content:read",
1755
+ "experiences:read",
1756
+ "segments:read",
1757
+ "brand:read",
1758
+ "portal:read",
1759
+ "push:read",
1760
+ "sdk:read",
1761
+ "apps:read",
1762
+ "requests:manage",
1763
+ "roadmap:manage",
1764
+ "content:manage",
1765
+ "experiences:manage",
1766
+ "segments:manage"
1767
+ ];
1768
+
1769
+ // src/schemas/mcp.ts
1770
+ var mcpCapabilitySchema = zod.z.string().refine((value) => MCP_CAPABILITIES.includes(value), "Unknown MCP capability");
1771
+ var mcpGrantSchema = zod.z.object({
1772
+ name: zod.z.string().trim().min(1).max(100).default("AI connection"),
1773
+ appIds: zod.z.array(zod.z.string().uuid()).min(1).max(100).refine((v) => new Set(v).size === v.length, "Duplicate app IDs"),
1774
+ capabilities: zod.z.array(mcpCapabilitySchema).max(56).default([...MCP_DEFAULT_CAPABILITIES]),
1775
+ mode: zod.z.enum(MCP_ACCESS_MODES).default("approve_changes")
1776
+ }).strict();
1777
+ var mcpConsentSchema = mcpGrantSchema.extend({
1778
+ workspaceId: zod.z.string().uuid(),
1779
+ externalAuthId: zod.z.string().min(10).max(256).regex(/^[a-zA-Z0-9_-]+$/)
1780
+ });
1781
+ var mcpUpdateConnectionSchema = mcpGrantSchema.extend({ policyVersion: zod.z.number().int().positive() });
1782
+ var subjectRefSchema = zod.z.union([
1783
+ zod.z.object({ subjectId: zod.z.string().uuid() }).strict(),
1784
+ zod.z.object({ externalId: zod.z.string().min(1).max(256) }).strict(),
1785
+ zod.z.object({ anonymousId: zod.z.string().min(1).max(256) }).strict()
1786
+ ]);
1787
+ var mcpPageSchema = zod.z.object({ cursor: zod.z.string().max(4096).optional(), limit: zod.z.number().int().min(1).max(100).default(25) });
1788
+ var mcpSearchSchema = mcpPageSchema.extend({
1789
+ query: zod.z.string().trim().min(1).max(500),
1790
+ types: zod.z.array(zod.z.enum(["request", "feedback_answer", "survey_answer", "roadmap", "article", "changelog"])).max(6).optional(),
1791
+ variant: zod.z.enum(["draft", "published", "record"]).optional()
1792
+ });
1793
+
1794
+ // src/types/web.ts
1795
+ var DELIVERY_PROTOCOL_VERSION = 2;
1796
+ function deliveryPlatformsForApp(platforms) {
1797
+ const values = /* @__PURE__ */ new Set();
1798
+ for (const platform of platforms) {
1799
+ if (platform === "web" || platform === "ios" || platform === "android") values.add(platform);
1800
+ if (platform === "expo" || platform === "react-native" || platform === "flutter") {
1801
+ values.add("ios");
1802
+ values.add("android");
1803
+ }
1804
+ }
1805
+ return [...values];
1806
+ }
1807
+ function resolveWebPresentation(pillar, override) {
1808
+ return {
1809
+ layout: override?.layout ?? "modal",
1810
+ size: override?.size ?? (pillar === "requests" ? "wide" : "standard"),
1811
+ position: override?.position ?? "right",
1812
+ backdrop: override?.backdrop ?? override?.layout !== "card"
1813
+ };
1814
+ }
1815
+ var id = zod.z.string().regex(/^[A-Za-z][A-Za-z0-9_]{0,63}$/);
1816
+ var key = zod.z.string().min(1).max(120).refine(
1817
+ (v) => !["__proto__", "prototype", "constructor"].includes(v),
1818
+ "Reserved property key"
1819
+ );
1820
+ var scalar = zod.z.union([
1821
+ zod.z.string().max(8192),
1822
+ zod.z.number().finite(),
1823
+ zod.z.boolean(),
1824
+ zod.z.null()
1825
+ ]);
1826
+ var baseSource = { id, label: zod.z.string().min(1).max(120) };
1827
+ var filterSchema = zod.z.object({
1828
+ key,
1829
+ op: zod.z.enum([
1830
+ "eq",
1831
+ "neq",
1832
+ "gt",
1833
+ "gte",
1834
+ "lt",
1835
+ "lte",
1836
+ "in",
1837
+ "nin",
1838
+ "contains",
1839
+ "starts_with",
1840
+ "exists",
1841
+ "not_exists"
1842
+ ]),
1843
+ value: zod.z.union([
1844
+ zod.z.string(),
1845
+ zod.z.number().finite(),
1846
+ zod.z.boolean(),
1847
+ zod.z.array(zod.z.union([zod.z.string(), zod.z.number().finite()])).max(100)
1848
+ ]).optional()
1849
+ });
1850
+ var personalizationSpecSchema = zod.z.object({
1851
+ version: zod.z.literal(1),
1852
+ sources: zod.z.array(
1853
+ zod.z.discriminatedUnion("kind", [
1854
+ zod.z.object({ ...baseSource, kind: zod.z.literal("user_property") }),
1855
+ zod.z.object({ ...baseSource, kind: zod.z.literal("trigger_event") }),
1856
+ zod.z.object({ ...baseSource, kind: zod.z.literal("send_data") }),
1857
+ zod.z.object({ ...baseSource, kind: zod.z.literal("app") }),
1858
+ zod.z.object({ ...baseSource, kind: zod.z.literal("now") }),
1859
+ zod.z.object({
1860
+ ...baseSource,
1861
+ kind: zod.z.literal("latest_event"),
1862
+ eventName: zod.z.string().min(1).max(120),
1863
+ lookbackDays: zod.z.number().int().min(1).max(90),
1864
+ filters: zod.z.array(filterSchema).max(8).optional()
1865
+ })
1866
+ ])
1867
+ ).max(16),
1868
+ bindings: zod.z.array(
1869
+ zod.z.object({
1870
+ id,
1871
+ label: zod.z.string().min(1).max(120),
1872
+ sourceId: id,
1873
+ key,
1874
+ type: zod.z.enum(["string", "number", "boolean", "date"]),
1875
+ fallback: scalar.optional()
1876
+ })
1877
+ ).max(64),
1878
+ missingData: zod.z.literal("skip")
1879
+ }).superRefine((spec, ctx) => {
1880
+ const sources = new Set(spec.sources.map((source) => source.id));
1881
+ if (sources.size !== spec.sources.length)
1882
+ ctx.addIssue({
1883
+ code: "custom",
1884
+ path: ["sources"],
1885
+ message: "Source IDs must be unique"
1886
+ });
1887
+ if (spec.sources.filter((source) => source.kind === "latest_event").length > 4)
1888
+ ctx.addIssue({
1889
+ code: "custom",
1890
+ path: ["sources"],
1891
+ message: "Use at most four activity sources"
1892
+ });
1893
+ const bindings = /* @__PURE__ */ new Set();
1894
+ spec.bindings.forEach((binding, index) => {
1895
+ if (bindings.has(binding.id))
1896
+ ctx.addIssue({
1897
+ code: "custom",
1898
+ path: ["bindings", index, "id"],
1899
+ message: "Field IDs must be unique"
1900
+ });
1901
+ bindings.add(binding.id);
1902
+ if (!sources.has(binding.sourceId))
1903
+ ctx.addIssue({
1904
+ code: "custom",
1905
+ path: ["bindings", index, "sourceId"],
1906
+ message: "Choose an existing source"
1907
+ });
1908
+ if (binding.fallback !== void 0 && (isMissing(binding.fallback) || !matchesType(binding.fallback, binding.type)))
1909
+ ctx.addIssue({
1910
+ code: "custom",
1911
+ path: ["bindings", index, "fallback"],
1912
+ message: "Fallback must be a non-empty value of the selected type"
1913
+ });
1914
+ });
1915
+ });
1916
+ var userPropertiesUpdateSchema = zod.z.object({
1917
+ mutationId: zod.z.string().uuid(),
1918
+ set: zod.z.record(key, scalar).refine(
1919
+ (v) => Object.keys(v).length <= 64,
1920
+ "Update at most 64 properties"
1921
+ ).optional(),
1922
+ unset: zod.z.array(key).max(64).optional()
1923
+ }).superRefine((update, ctx) => {
1924
+ if (!Object.keys(update.set ?? {}).length && !update.unset?.length)
1925
+ ctx.addIssue({
1926
+ code: "custom",
1927
+ message: "Supply properties to set or remove"
1928
+ });
1929
+ if (update.unset?.some((name) => Object.hasOwn(update.set ?? {}, name)))
1930
+ ctx.addIssue({
1931
+ code: "custom",
1932
+ message: "A property cannot be set and removed in the same update"
1933
+ });
1934
+ });
1935
+ function isMissing(value) {
1936
+ return value == null || typeof value === "string" && !value.trim();
1937
+ }
1938
+ function matchesType(value, type) {
1939
+ if (type === "date")
1940
+ return typeof value === "string" && !Number.isNaN(Date.parse(value));
1941
+ return typeof value === type && (typeof value !== "number" || Number.isFinite(value));
1942
+ }
1943
+ function resolvePersonalizationBindings(spec, sources) {
1944
+ const values = /* @__PURE__ */ Object.create(null);
1945
+ const issues = [];
1946
+ const fallbackBindingIds = [];
1947
+ for (const binding of spec.bindings) {
1948
+ const source = sources[binding.sourceId]?.values;
1949
+ const value = source && Object.hasOwn(source, binding.key) ? source[binding.key] : void 0;
1950
+ const missing = isMissing(value);
1951
+ if (!missing && matchesType(value, binding.type))
1952
+ values[binding.id] = value;
1953
+ else if (missing && binding.fallback !== void 0) {
1954
+ values[binding.id] = binding.fallback;
1955
+ fallbackBindingIds.push(binding.id);
1956
+ } else
1957
+ issues.push({
1958
+ code: missing ? "missing" : "type_mismatch",
1959
+ bindingId: binding.id,
1960
+ message: missing ? `${binding.label} is missing` : `${binding.label} must be ${binding.type}`
1961
+ });
1962
+ }
1963
+ return {
1964
+ status: issues.length ? "skipped" : fallbackBindingIds.length ? "using_fallback" : "ready",
1965
+ values,
1966
+ fallbackBindingIds,
1967
+ issues,
1968
+ sources
1969
+ };
1970
+ }
1971
+ var TOKEN = /\{\{\s*p\.([A-Za-z][A-Za-z0-9_]*)\s*\}\}/g;
1972
+ var WHOLE_TOKEN = /^\{\{\s*p\.([A-Za-z][A-Za-z0-9_]*)\s*\}\}$/;
1973
+ function personalizationToken(bindingId) {
1974
+ return `{{p.${bindingId}}}`;
1975
+ }
1976
+ function renderPersonalizedValue(input, values, issues, path = "", mode = "text") {
1977
+ if (typeof input === "string") {
1978
+ const whole = WHOLE_TOKEN.exec(input);
1979
+ const lookup = (bindingId) => {
1980
+ if (Object.hasOwn(values, bindingId)) return values[bindingId];
1981
+ issues.push({
1982
+ code: "unknown_binding",
1983
+ bindingId,
1984
+ path,
1985
+ message: `No value is available for ${bindingId}`
1986
+ });
1987
+ return null;
1988
+ };
1989
+ if (mode === "json" && whole) return lookup(whole[1]);
1990
+ if (/\{\{|\}\}/.test(input.replace(TOKEN, "")))
1991
+ issues.push({
1992
+ code: "invalid_template",
1993
+ path,
1994
+ message: "Insert a valid dynamic field"
1995
+ });
1996
+ const result = input.replace(TOKEN, (_, bindingId) => {
1997
+ const value = lookup(bindingId);
1998
+ return mode === "url" && !whole ? encodeURIComponent(String(value ?? "")) : String(value ?? "");
1999
+ });
2000
+ if (mode === "url" && result) {
2001
+ try {
2002
+ const url = new URL(result);
2003
+ if (["javascript:", "data:", "file:", "vbscript:"].includes(url.protocol))
2004
+ throw new Error("unsafe");
2005
+ if (!whole && /\{\{/.test(input.split(/:\/\//)[0] ?? ""))
2006
+ throw new Error("dynamic scheme");
2007
+ if (!whole && /\{\{/.test(
2008
+ input.match(/^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i)?.[1] ?? ""
2009
+ ))
2010
+ throw new Error("dynamic authority");
2011
+ } catch {
2012
+ issues.push({
2013
+ code: "invalid_destination",
2014
+ path,
2015
+ message: "The resolved destination must be a valid app link or web URL"
2016
+ });
2017
+ }
2018
+ }
2019
+ return result;
2020
+ }
2021
+ if (Array.isArray(input))
2022
+ return input.map(
2023
+ (item, index) => renderPersonalizedValue(item, values, issues, `${path}/${index}`, mode)
2024
+ );
2025
+ if (input && typeof input === "object") {
2026
+ const result = /* @__PURE__ */ Object.create(null);
2027
+ for (const [name, value] of Object.entries(input)) {
2028
+ if (["__proto__", "constructor", "prototype"].includes(name)) {
2029
+ issues.push({
2030
+ code: "invalid_template",
2031
+ path,
2032
+ message: "Reserved object key"
2033
+ });
2034
+ continue;
2035
+ }
2036
+ result[name] = renderPersonalizedValue(
2037
+ value,
2038
+ values,
2039
+ issues,
2040
+ `${path}/${name}`,
2041
+ mode
2042
+ );
2043
+ }
2044
+ return result;
2045
+ }
2046
+ return input;
2047
+ }
2048
+ var TEXT_KEYS = /* @__PURE__ */ new Set([
2049
+ "title",
2050
+ "body",
2051
+ "subtitle",
2052
+ "headline",
2053
+ "label",
2054
+ "placeholder",
2055
+ "followUp",
2056
+ "lowLabel",
2057
+ "highLabel",
2058
+ "description",
2059
+ "buttonText",
2060
+ "submitLabel",
2061
+ "nextLabel",
2062
+ "backLabel",
2063
+ "text"
2064
+ ]);
2065
+ var URL_KEYS = /* @__PURE__ */ new Set(["imageUrl", "deepLink", "target"]);
2066
+ var CONTENT_KEYS = /* @__PURE__ */ new Set([
2067
+ "questions",
2068
+ "options",
2069
+ "ctas",
2070
+ "cta",
2071
+ "actionButtons",
2072
+ "flow",
2073
+ "welcome",
2074
+ "thankYou",
2075
+ "completion",
2076
+ "endScreen",
2077
+ "openAction"
2078
+ ]);
2079
+ function personalizationUsage(content) {
2080
+ const usage = /* @__PURE__ */ new Map();
2081
+ const scan = (value, field) => {
2082
+ if (typeof value === "string") {
2083
+ for (const match of value.matchAll(TOKEN)) {
2084
+ const fields = usage.get(match[1]) ?? /* @__PURE__ */ new Set();
2085
+ fields.add(field);
2086
+ usage.set(match[1], fields);
2087
+ }
2088
+ } else if (Array.isArray(value)) value.forEach((item) => scan(item, field));
2089
+ else if (value && typeof value === "object")
2090
+ Object.values(value).forEach((item) => scan(item, field));
2091
+ };
2092
+ const walk = (value) => {
2093
+ if (Array.isArray(value)) {
2094
+ value.forEach(walk);
2095
+ return;
2096
+ }
2097
+ if (!value || typeof value !== "object") return;
2098
+ for (const [key2, item] of Object.entries(value)) {
2099
+ if (TEXT_KEYS.has(key2) || URL_KEYS.has(key2) || key2 === "actionJson" || key2 === "payloadExtras")
2100
+ scan(item, key2);
2101
+ else if (CONTENT_KEYS.has(key2)) walk(item);
2102
+ }
2103
+ };
2104
+ walk(content);
2105
+ return usage;
2106
+ }
2107
+ function renderPersonalizedContent(content, resolution) {
2108
+ const usage = personalizationUsage(content);
2109
+ const onlyOptionalImage = (id2) => usage.get(id2)?.size === 1 && usage.get(id2)?.has("imageUrl");
2110
+ const issues = resolution.issues.filter(
2111
+ (issue) => !issue.bindingId || usage.has(issue.bindingId) && !(issue.code === "missing" && onlyOptionalImage(issue.bindingId))
2112
+ );
2113
+ const fallbacks = resolution.fallbackBindingIds.filter((id2) => usage.has(id2));
2114
+ const walk = (value, path = "") => {
2115
+ if (Array.isArray(value))
2116
+ return value.map((item, index) => walk(item, `${path}/${index}`));
2117
+ if (!value || typeof value !== "object") return value;
2118
+ return Object.fromEntries(
2119
+ Object.entries(value).map(([name, item]) => {
2120
+ const childPath = `${path}/${name}`;
2121
+ if (TEXT_KEYS.has(name) && typeof item === "string")
2122
+ return [
2123
+ name,
2124
+ renderPersonalizedValue(item, resolution.values, issues, childPath)
2125
+ ];
2126
+ if (URL_KEYS.has(name) && typeof item === "string") {
2127
+ if (name === "imageUrl" && [...item.matchAll(TOKEN)].some(
2128
+ (match) => resolution.issues.some(
2129
+ (issue) => issue.bindingId === match[1] && issue.code === "missing"
2130
+ )
2131
+ ))
2132
+ return [name, null];
2133
+ const isEvent = name === "target" && value.action === "custom_event";
2134
+ const rendered2 = renderPersonalizedValue(
2135
+ item,
2136
+ resolution.values,
2137
+ issues,
2138
+ childPath,
2139
+ isEvent ? "text" : "url"
2140
+ );
2141
+ if (name === "imageUrl" && rendered2 && !String(rendered2).startsWith("https://"))
2142
+ issues.push({
2143
+ code: "invalid_destination",
2144
+ path: childPath,
2145
+ message: "Image URLs must use HTTPS"
2146
+ });
2147
+ return [name, rendered2];
2148
+ }
2149
+ if (name === "actionJson" || name === "payloadExtras")
2150
+ return [
2151
+ name,
2152
+ renderPersonalizedValue(
2153
+ item,
2154
+ resolution.values,
2155
+ issues,
2156
+ childPath,
2157
+ "json"
2158
+ )
2159
+ ];
2160
+ if (CONTENT_KEYS.has(name)) return [name, walk(item, childPath)];
2161
+ return [name, item];
2162
+ })
2163
+ );
2164
+ };
2165
+ const rendered = walk(content);
2166
+ return {
2167
+ content: rendered,
2168
+ resolution: {
2169
+ ...resolution,
2170
+ fallbackBindingIds: fallbacks,
2171
+ status: issues.length ? "skipped" : fallbacks.length ? "using_fallback" : "ready",
2172
+ issues
2173
+ }
2174
+ };
2175
+ }
2176
+
2177
+ // src/presentation.ts
2178
+ var PresentationGate = class {
2179
+ paused;
2180
+ identity = 0;
2181
+ revisions = { feedback: 0, survey: 0 };
2182
+ listeners = /* @__PURE__ */ new Set();
2183
+ constructor(paused = false) {
2184
+ this.paused = paused;
2185
+ }
2186
+ get isPaused() {
2187
+ return this.paused;
2188
+ }
2189
+ setPaused(paused) {
2190
+ this.paused = paused;
2191
+ this.notify();
2192
+ }
2193
+ invalidate(purpose) {
2194
+ if (purpose) this.revisions[purpose]++;
2195
+ else this.identity++;
2196
+ this.notify();
2197
+ }
2198
+ validator(purpose) {
2199
+ const identity = this.identity;
2200
+ const revision = this.revisions[purpose];
2201
+ return () => identity === this.identity && revision === this.revisions[purpose];
2202
+ }
2203
+ subscribe(listener) {
2204
+ this.listeners.add(listener);
2205
+ return () => {
2206
+ this.listeners.delete(listener);
2207
+ };
2208
+ }
2209
+ runWhenReady(run, valid, cancel = () => {
2210
+ }) {
2211
+ if (!valid()) {
2212
+ cancel();
2213
+ return;
2214
+ }
2215
+ if (!this.paused) {
2216
+ run();
2217
+ return;
2218
+ }
2219
+ const stop = this.subscribe(() => {
2220
+ if (valid() && this.paused) return;
2221
+ stop();
2222
+ if (valid()) run();
2223
+ else cancel();
2224
+ });
2225
+ }
2226
+ waitUntilReady(valid) {
2227
+ if (!valid()) return Promise.resolve(false);
2228
+ if (!this.paused) return Promise.resolve(true);
2229
+ return new Promise((resolve) => {
2230
+ const stop = this.subscribe(() => {
2231
+ if (valid() && this.paused) return;
2232
+ stop();
2233
+ resolve(valid());
2234
+ });
2235
+ });
2236
+ }
2237
+ notify() {
2238
+ for (const listener of [...this.listeners]) listener();
2239
+ }
2240
+ };
2241
+
1092
2242
  exports.APP_OPEN_EVENT_NAME = APP_OPEN_EVENT_NAME;
1093
2243
  exports.APP_VERSION_CHANGED_EVENT_NAME = APP_VERSION_CHANGED_EVENT_NAME;
1094
2244
  exports.AUDIENCE_JOIN_EVENT_NAME = AUDIENCE_JOIN_EVENT_NAME;
@@ -1096,13 +2246,21 @@ exports.AUDIENCE_JOIN_TRIGGER_KIND = AUDIENCE_JOIN_TRIGGER_KIND;
1096
2246
  exports.BILLING_GRACE_DAYS = BILLING_GRACE_DAYS;
1097
2247
  exports.COMMERCIAL_BILLING_PLANS = COMMERCIAL_BILLING_PLANS;
1098
2248
  exports.CORE_INTEGRATION_EVENTS = CORE_INTEGRATION_EVENTS;
2249
+ exports.DELIVERY_PROTOCOL_VERSION = DELIVERY_PROTOCOL_VERSION;
1099
2250
  exports.INAPP_AUTO_DISMISSED_EVENT_NAME = INAPP_AUTO_DISMISSED_EVENT_NAME;
1100
2251
  exports.INAPP_CTA_CLICKED_EVENT_NAME = INAPP_CTA_CLICKED_EVENT_NAME;
1101
2252
  exports.INAPP_DISMISSED_EVENT_NAME = INAPP_DISMISSED_EVENT_NAME;
1102
2253
  exports.INAPP_SHOWN_EVENT_NAME = INAPP_SHOWN_EVENT_NAME;
1103
2254
  exports.INTEGRATION_CATEGORIES = INTEGRATION_CATEGORIES;
1104
2255
  exports.INTEGRATION_PROVIDERS = INTEGRATION_PROVIDERS;
2256
+ exports.MCP_ACCESS_MODES = MCP_ACCESS_MODES;
2257
+ exports.MCP_CAPABILITIES = MCP_CAPABILITIES;
2258
+ exports.MCP_DEFAULT_CAPABILITIES = MCP_DEFAULT_CAPABILITIES;
2259
+ exports.MCP_DOMAINS = MCP_DOMAINS;
2260
+ exports.PORTAL_RESERVED_SLUGS = PORTAL_RESERVED_SLUGS;
2261
+ exports.PORTAL_SLUG_PATTERN = PORTAL_SLUG_PATTERN;
1105
2262
  exports.PUSH_EVENTS = PUSH_EVENTS;
2263
+ exports.PresentationGate = PresentationGate;
1106
2264
  exports.RADIUS_PRESETS = RADIUS_PRESETS;
1107
2265
  exports.RECIPIENTS_LIMIT = RECIPIENTS_LIMIT;
1108
2266
  exports.REQUEST_COMMENTED_EVENT_NAME = REQUEST_COMMENTED_EVENT_NAME;
@@ -1123,10 +2281,17 @@ exports.TRIAL_APP_LIMIT = TRIAL_APP_LIMIT;
1123
2281
  exports.TRIAL_DAYS = TRIAL_DAYS;
1124
2282
  exports.USER_IDENTIFIED_EVENT_NAME = USER_IDENTIFIED_EVENT_NAME;
1125
2283
  exports.brandTokensFromPreset = brandTokensFromPreset;
2284
+ exports.buildPortalUrl = buildPortalUrl;
2285
+ exports.contentAssetIds = contentAssetIds;
2286
+ exports.contentSlug = contentSlug;
2287
+ exports.contentText = contentText;
1126
2288
  exports.defaultEventTrigger = defaultEventTrigger;
2289
+ exports.defaultOnboardingMessage = defaultOnboardingMessage;
1127
2290
  exports.defaultThemePreset = defaultThemePreset;
1128
2291
  exports.defaultTriggerSpec = defaultTriggerSpec;
2292
+ exports.deliveryPlatformsForApp = deliveryPlatformsForApp;
1129
2293
  exports.emptyAudienceSpec = emptyAudienceSpec;
2294
+ exports.emptyDocumentDraft = emptyDocumentDraft;
1130
2295
  exports.emptySegmentDsl = emptySegmentDsl;
1131
2296
  exports.endpoints = endpoints;
1132
2297
  exports.err = err;
@@ -1140,15 +2305,30 @@ exports.getCoreIntegrationEvent = getCoreIntegrationEvent;
1140
2305
  exports.getThemePresetById = getThemePresetById;
1141
2306
  exports.inAppColorsFromBrandTokens = inAppColorsFromBrandTokens;
1142
2307
  exports.isSilentPushPayload = isSilentPushPayload;
2308
+ exports.isValidIanaTimeZone = isValidIanaTimeZone;
1143
2309
  exports.nextPeriodicFire = nextPeriodicFire;
1144
2310
  exports.nextQuestionId = nextQuestionId;
1145
2311
  exports.ok = ok;
2312
+ exports.personalizationSpecSchema = personalizationSpecSchema;
2313
+ exports.personalizationToken = personalizationToken;
2314
+ exports.personalizationUsage = personalizationUsage;
1146
2315
  exports.promptThemeFromBrandTokens = promptThemeFromBrandTokens;
1147
2316
  exports.reachableQuestions = reachableQuestions;
2317
+ exports.renderPersonalizedContent = renderPersonalizedContent;
2318
+ exports.renderPersonalizedValue = renderPersonalizedValue;
1148
2319
  exports.requestAccentFromBrandTokens = requestAccentFromBrandTokens;
2320
+ exports.resolvePersonalizationBindings = resolvePersonalizationBindings;
2321
+ exports.resolveWebPresentation = resolveWebPresentation;
2322
+ exports.safeContentHref = safeContentHref;
1149
2323
  exports.sanitizeCoreIntegrationProperties = sanitizeCoreIntegrationProperties;
1150
2324
  exports.schemas = schemas_exports;
1151
2325
  exports.serializedRulesToDsl = serializedRulesToDsl;
2326
+ exports.suggestPortalSlug = suggestPortalSlug;
1152
2327
  exports.tzOffsetMinutes = tzOffsetMinutes;
2328
+ exports.userPropertiesUpdateSchema = userPropertiesUpdateSchema;
2329
+ exports.validPortalSlug = validPortalSlug;
2330
+ exports.zonedDateEndToUtc = zonedDateEndToUtc;
2331
+ exports.zonedDateTimeParts = zonedDateTimeParts;
2332
+ exports.zonedDateTimeToUtc = zonedDateTimeToUtc;
1153
2333
  //# sourceMappingURL=index.cjs.map
1154
2334
  //# sourceMappingURL=index.cjs.map