@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/mobile.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { z } from 'zod';
2
+
1
3
  // src/types/segment-dsl.ts
2
4
  function emptySegmentDsl() {
3
5
  return { version: 1, root: { combinator: "AND", predicates: [] } };
@@ -14,6 +16,16 @@ function err(code, message, details) {
14
16
  };
15
17
  }
16
18
 
19
+ // src/types/workspace.ts
20
+ function defaultOnboardingMessage(appName) {
21
+ return {
22
+ title: `Welcome to ${appName.trim() || "our app"}`,
23
+ body: "Glad you\u2019re here. Take a look around and make yourself at home.",
24
+ buttonLabel: "Got it",
25
+ format: "modal"
26
+ };
27
+ }
28
+
17
29
  // src/types/survey.ts
18
30
  var SURVEY_END_SENTINEL = "__end__";
19
31
 
@@ -257,8 +269,8 @@ var THEME_PRESETS = [
257
269
  swatches: ["#8B5CF6", "#EC4899", "#E9D5FF"]
258
270
  }
259
271
  ];
260
- function getThemePresetById(id) {
261
- return THEME_PRESETS.find((preset) => preset.id === id);
272
+ function getThemePresetById(id2) {
273
+ return THEME_PRESETS.find((preset) => preset.id === id2);
262
274
  }
263
275
  function defaultThemePreset() {
264
276
  return THEME_PRESETS[0];
@@ -309,7 +321,7 @@ var USER_IDENTIFIED_EVENT_NAME = "$user_identified";
309
321
  function camelize(value) {
310
322
  return value.replace(/_([a-z])/g, (_match, letter) => letter.toUpperCase());
311
323
  }
312
- var ids = (...keys) => Object.fromEntries(keys.map((key) => [key, [key, camelize(key)]]));
324
+ var ids = (...keys) => Object.fromEntries(keys.map((key2) => [key2, [key2, camelize(key2)]]));
313
325
  var pushEvents = [
314
326
  ["$push_sent", "UserGist Push Sent"],
315
327
  ["$push_delivered", "UserGist Push Delivered"],
@@ -366,8 +378,8 @@ var CORE_INTEGRATION_EVENTS = [
366
378
  { key: "$inapp_dismissed", name: "UserGist In-App Message Dismissed", category: "inapp", subjectRole: "actor", properties: { ...ids("message_id", "dismiss_reason") } },
367
379
  { key: "$inapp_auto_dismissed", name: "UserGist In-App Message Auto-Dismissed", category: "inapp", subjectRole: "actor", properties: { ...ids("message_id", "dismiss_reason") } },
368
380
  { 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"] } },
369
- ...pushEvents.map(([key, name]) => ({
370
- key,
381
+ ...pushEvents.map(([key2, name]) => ({
382
+ key: key2,
371
383
  name,
372
384
  category: "push",
373
385
  subjectRole: "actor",
@@ -376,11 +388,11 @@ var CORE_INTEGRATION_EVENTS = [
376
388
  action_id: ["action_id", "actionId", "action_button", "actionButton"]
377
389
  }
378
390
  })),
379
- ...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"] } }))
391
+ ...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"] } }))
380
392
  ];
381
393
  var CORE_EVENT_BY_KEY = new Map(CORE_INTEGRATION_EVENTS.map((event) => [event.key, event]));
382
- function getCoreIntegrationEvent(key) {
383
- return CORE_EVENT_BY_KEY.get(key) ?? null;
394
+ function getCoreIntegrationEvent(key2) {
395
+ return CORE_EVENT_BY_KEY.get(key2) ?? null;
384
396
  }
385
397
  function sanitizeCoreIntegrationProperties(definition, input) {
386
398
  if (!input) return {};
@@ -589,15 +601,15 @@ function reachableQuestions(flow, startId) {
589
601
  const visited = /* @__PURE__ */ new Set();
590
602
  const stack = [start];
591
603
  while (stack.length > 0) {
592
- const id = stack.pop();
593
- if (id === void 0) continue;
594
- if (visited.has(id)) continue;
595
- visited.add(id);
596
- const outgoing = flow.branches.filter((b) => b.fromQuestionId === id);
604
+ const id2 = stack.pop();
605
+ if (id2 === void 0) continue;
606
+ if (visited.has(id2)) continue;
607
+ visited.add(id2);
608
+ const outgoing = flow.branches.filter((b) => b.fromQuestionId === id2);
597
609
  for (const b of outgoing) {
598
610
  if (b.toQuestionId !== SURVEY_END_SENTINEL) stack.push(b.toQuestionId);
599
611
  }
600
- const idx = flow.questions.findIndex((q) => q.id === id);
612
+ const idx = flow.questions.findIndex((q) => q.id === id2);
601
613
  if (idx >= 0 && idx < flow.questions.length - 1) {
602
614
  const next = flow.questions[idx + 1];
603
615
  if (next) stack.push(next.id);
@@ -636,7 +648,7 @@ function tzOffsetMinutes(at, tz) {
636
648
  function startCandidate(schedule, now, tz) {
637
649
  const localNow = wallClock(now, tz);
638
650
  const target = new Date(localNow);
639
- target.setHours(schedule.hourLocal, schedule.minuteLocal, 0, 0);
651
+ target.setUTCHours(schedule.hourLocal, schedule.minuteLocal, 0, 0);
640
652
  return localToUtc(target, tz);
641
653
  }
642
654
  function walkForward(candidate, schedule, now, tz) {
@@ -654,30 +666,30 @@ function walkForward(candidate, schedule, now, tz) {
654
666
  function matchesFrequency(local, schedule) {
655
667
  if (schedule.frequency === "daily") return true;
656
668
  if (schedule.frequency === "weekly") {
657
- return schedule.weekday === void 0 || local.getDay() === schedule.weekday;
669
+ return schedule.weekday === void 0 || local.getUTCDay() === schedule.weekday;
658
670
  }
659
- return schedule.dayOfMonth === void 0 || local.getDate() === schedule.dayOfMonth;
671
+ return schedule.dayOfMonth === void 0 || local.getUTCDate() === schedule.dayOfMonth;
660
672
  }
661
673
  function step(cursor, cursorLocal, schedule, tz) {
662
674
  if (schedule.frequency === "daily" || schedule.frequency === "weekly") {
663
675
  return addDays(cursor, 1);
664
676
  }
665
677
  const next = new Date(cursorLocal);
666
- next.setMonth(next.getMonth() + 1);
678
+ next.setUTCMonth(next.getUTCMonth() + 1);
667
679
  if (schedule.dayOfMonth !== void 0) {
668
- const lastDay = lastDayOfMonth(next.getFullYear(), next.getMonth());
669
- next.setDate(Math.min(schedule.dayOfMonth, lastDay));
680
+ const lastDay = lastDayOfMonth(next.getUTCFullYear(), next.getUTCMonth());
681
+ next.setUTCDate(Math.min(schedule.dayOfMonth, lastDay));
670
682
  }
671
- next.setHours(schedule.hourLocal, schedule.minuteLocal, 0, 0);
683
+ next.setUTCHours(schedule.hourLocal, schedule.minuteLocal, 0, 0);
672
684
  return localToUtc(next, tz);
673
685
  }
674
686
  function addDays(d, days) {
675
687
  const next = new Date(d.getTime());
676
- next.setDate(next.getDate() + days);
688
+ next.setUTCDate(next.getUTCDate() + days);
677
689
  return next;
678
690
  }
679
691
  function lastDayOfMonth(year, monthIndex) {
680
- return new Date(year, monthIndex + 1, 0).getDate();
692
+ return new Date(Date.UTC(year, monthIndex + 1, 0)).getUTCDate();
681
693
  }
682
694
  function wallClock(d, tz) {
683
695
  const offsetMin = tzOffsetMinutes(d, tz);
@@ -705,6 +717,454 @@ function getFormatter(tz) {
705
717
  return fmt;
706
718
  }
707
719
 
708
- export { APP_OPEN_EVENT_NAME, APP_VERSION_CHANGED_EVENT_NAME, AUDIENCE_JOIN_EVENT_NAME, AUDIENCE_JOIN_TRIGGER_KIND, CORE_INTEGRATION_EVENTS, INAPP_AUTO_DISMISSED_EVENT_NAME, INAPP_CTA_CLICKED_EVENT_NAME, INAPP_DISMISSED_EVENT_NAME, INAPP_SHOWN_EVENT_NAME, INTEGRATION_CATEGORIES, INTEGRATION_PROVIDERS, PUSH_EVENTS, RADIUS_PRESETS, REQUEST_COMMENTED_EVENT_NAME, REQUEST_COMMENT_DELETED_EVENT_NAME, REQUEST_COMMENT_EDITED_EVENT_NAME, REQUEST_FOLLOWED_EVENT_NAME, REQUEST_RESPONDED_EVENT_NAME, REQUEST_STATUS_CHANGED_EVENT_NAME, REQUEST_SUBMITTED_EVENT_NAME, REQUEST_UNFOLLOWED_EVENT_NAME, REQUEST_UNUPVOTED_EVENT_NAME, REQUEST_UPVOTED_EVENT_NAME, SURVEY_END_SENTINEL, THEME_PRESETS, USER_IDENTIFIED_EVENT_NAME, brandTokensFromPreset, defaultEventTrigger, defaultThemePreset, defaultTriggerSpec, emptyAudienceSpec, emptySegmentDsl, err, estimateProgress, evaluateBranchCondition, evaluateSegment, evaluateSerializedSegmentRules, findQuestion, findQuestionIndex, getCoreIntegrationEvent, getThemePresetById, inAppColorsFromBrandTokens, isSilentPushPayload, nextPeriodicFire, nextQuestionId, ok, promptThemeFromBrandTokens, reachableQuestions, requestAccentFromBrandTokens, sanitizeCoreIntegrationProperties, serializedRulesToDsl, tzOffsetMinutes };
720
+ // src/types/web.ts
721
+ var DELIVERY_PROTOCOL_VERSION = 2;
722
+ function deliveryPlatformsForApp(platforms) {
723
+ const values = /* @__PURE__ */ new Set();
724
+ for (const platform of platforms) {
725
+ if (platform === "web" || platform === "ios" || platform === "android") values.add(platform);
726
+ if (platform === "expo" || platform === "react-native" || platform === "flutter") {
727
+ values.add("ios");
728
+ values.add("android");
729
+ }
730
+ }
731
+ return [...values];
732
+ }
733
+ function resolveWebPresentation(pillar, override) {
734
+ return {
735
+ layout: override?.layout ?? "modal",
736
+ size: override?.size ?? (pillar === "requests" ? "wide" : "standard"),
737
+ position: override?.position ?? "right",
738
+ backdrop: override?.backdrop ?? override?.layout !== "card"
739
+ };
740
+ }
741
+ var id = z.string().regex(/^[A-Za-z][A-Za-z0-9_]{0,63}$/);
742
+ var key = z.string().min(1).max(120).refine(
743
+ (v) => !["__proto__", "prototype", "constructor"].includes(v),
744
+ "Reserved property key"
745
+ );
746
+ var scalar = z.union([
747
+ z.string().max(8192),
748
+ z.number().finite(),
749
+ z.boolean(),
750
+ z.null()
751
+ ]);
752
+ var baseSource = { id, label: z.string().min(1).max(120) };
753
+ var filterSchema = z.object({
754
+ key,
755
+ op: z.enum([
756
+ "eq",
757
+ "neq",
758
+ "gt",
759
+ "gte",
760
+ "lt",
761
+ "lte",
762
+ "in",
763
+ "nin",
764
+ "contains",
765
+ "starts_with",
766
+ "exists",
767
+ "not_exists"
768
+ ]),
769
+ value: z.union([
770
+ z.string(),
771
+ z.number().finite(),
772
+ z.boolean(),
773
+ z.array(z.union([z.string(), z.number().finite()])).max(100)
774
+ ]).optional()
775
+ });
776
+ var personalizationSpecSchema = z.object({
777
+ version: z.literal(1),
778
+ sources: z.array(
779
+ z.discriminatedUnion("kind", [
780
+ z.object({ ...baseSource, kind: z.literal("user_property") }),
781
+ z.object({ ...baseSource, kind: z.literal("trigger_event") }),
782
+ z.object({ ...baseSource, kind: z.literal("send_data") }),
783
+ z.object({ ...baseSource, kind: z.literal("app") }),
784
+ z.object({ ...baseSource, kind: z.literal("now") }),
785
+ z.object({
786
+ ...baseSource,
787
+ kind: z.literal("latest_event"),
788
+ eventName: z.string().min(1).max(120),
789
+ lookbackDays: z.number().int().min(1).max(90),
790
+ filters: z.array(filterSchema).max(8).optional()
791
+ })
792
+ ])
793
+ ).max(16),
794
+ bindings: z.array(
795
+ z.object({
796
+ id,
797
+ label: z.string().min(1).max(120),
798
+ sourceId: id,
799
+ key,
800
+ type: z.enum(["string", "number", "boolean", "date"]),
801
+ fallback: scalar.optional()
802
+ })
803
+ ).max(64),
804
+ missingData: z.literal("skip")
805
+ }).superRefine((spec, ctx) => {
806
+ const sources = new Set(spec.sources.map((source) => source.id));
807
+ if (sources.size !== spec.sources.length)
808
+ ctx.addIssue({
809
+ code: "custom",
810
+ path: ["sources"],
811
+ message: "Source IDs must be unique"
812
+ });
813
+ if (spec.sources.filter((source) => source.kind === "latest_event").length > 4)
814
+ ctx.addIssue({
815
+ code: "custom",
816
+ path: ["sources"],
817
+ message: "Use at most four activity sources"
818
+ });
819
+ const bindings = /* @__PURE__ */ new Set();
820
+ spec.bindings.forEach((binding, index) => {
821
+ if (bindings.has(binding.id))
822
+ ctx.addIssue({
823
+ code: "custom",
824
+ path: ["bindings", index, "id"],
825
+ message: "Field IDs must be unique"
826
+ });
827
+ bindings.add(binding.id);
828
+ if (!sources.has(binding.sourceId))
829
+ ctx.addIssue({
830
+ code: "custom",
831
+ path: ["bindings", index, "sourceId"],
832
+ message: "Choose an existing source"
833
+ });
834
+ if (binding.fallback !== void 0 && (isMissing(binding.fallback) || !matchesType(binding.fallback, binding.type)))
835
+ ctx.addIssue({
836
+ code: "custom",
837
+ path: ["bindings", index, "fallback"],
838
+ message: "Fallback must be a non-empty value of the selected type"
839
+ });
840
+ });
841
+ });
842
+ var userPropertiesUpdateSchema = z.object({
843
+ mutationId: z.string().uuid(),
844
+ set: z.record(key, scalar).refine(
845
+ (v) => Object.keys(v).length <= 64,
846
+ "Update at most 64 properties"
847
+ ).optional(),
848
+ unset: z.array(key).max(64).optional()
849
+ }).superRefine((update, ctx) => {
850
+ if (!Object.keys(update.set ?? {}).length && !update.unset?.length)
851
+ ctx.addIssue({
852
+ code: "custom",
853
+ message: "Supply properties to set or remove"
854
+ });
855
+ if (update.unset?.some((name) => Object.hasOwn(update.set ?? {}, name)))
856
+ ctx.addIssue({
857
+ code: "custom",
858
+ message: "A property cannot be set and removed in the same update"
859
+ });
860
+ });
861
+ function isMissing(value) {
862
+ return value == null || typeof value === "string" && !value.trim();
863
+ }
864
+ function matchesType(value, type) {
865
+ if (type === "date")
866
+ return typeof value === "string" && !Number.isNaN(Date.parse(value));
867
+ return typeof value === type && (typeof value !== "number" || Number.isFinite(value));
868
+ }
869
+ function resolvePersonalizationBindings(spec, sources) {
870
+ const values = /* @__PURE__ */ Object.create(null);
871
+ const issues = [];
872
+ const fallbackBindingIds = [];
873
+ for (const binding of spec.bindings) {
874
+ const source = sources[binding.sourceId]?.values;
875
+ const value = source && Object.hasOwn(source, binding.key) ? source[binding.key] : void 0;
876
+ const missing = isMissing(value);
877
+ if (!missing && matchesType(value, binding.type))
878
+ values[binding.id] = value;
879
+ else if (missing && binding.fallback !== void 0) {
880
+ values[binding.id] = binding.fallback;
881
+ fallbackBindingIds.push(binding.id);
882
+ } else
883
+ issues.push({
884
+ code: missing ? "missing" : "type_mismatch",
885
+ bindingId: binding.id,
886
+ message: missing ? `${binding.label} is missing` : `${binding.label} must be ${binding.type}`
887
+ });
888
+ }
889
+ return {
890
+ status: issues.length ? "skipped" : fallbackBindingIds.length ? "using_fallback" : "ready",
891
+ values,
892
+ fallbackBindingIds,
893
+ issues,
894
+ sources
895
+ };
896
+ }
897
+ var TOKEN = /\{\{\s*p\.([A-Za-z][A-Za-z0-9_]*)\s*\}\}/g;
898
+ var WHOLE_TOKEN = /^\{\{\s*p\.([A-Za-z][A-Za-z0-9_]*)\s*\}\}$/;
899
+ function personalizationToken(bindingId) {
900
+ return `{{p.${bindingId}}}`;
901
+ }
902
+ function renderPersonalizedValue(input, values, issues, path = "", mode = "text") {
903
+ if (typeof input === "string") {
904
+ const whole = WHOLE_TOKEN.exec(input);
905
+ const lookup = (bindingId) => {
906
+ if (Object.hasOwn(values, bindingId)) return values[bindingId];
907
+ issues.push({
908
+ code: "unknown_binding",
909
+ bindingId,
910
+ path,
911
+ message: `No value is available for ${bindingId}`
912
+ });
913
+ return null;
914
+ };
915
+ if (mode === "json" && whole) return lookup(whole[1]);
916
+ if (/\{\{|\}\}/.test(input.replace(TOKEN, "")))
917
+ issues.push({
918
+ code: "invalid_template",
919
+ path,
920
+ message: "Insert a valid dynamic field"
921
+ });
922
+ const result = input.replace(TOKEN, (_, bindingId) => {
923
+ const value = lookup(bindingId);
924
+ return mode === "url" && !whole ? encodeURIComponent(String(value ?? "")) : String(value ?? "");
925
+ });
926
+ if (mode === "url" && result) {
927
+ try {
928
+ const url = new URL(result);
929
+ if (["javascript:", "data:", "file:", "vbscript:"].includes(url.protocol))
930
+ throw new Error("unsafe");
931
+ if (!whole && /\{\{/.test(input.split(/:\/\//)[0] ?? ""))
932
+ throw new Error("dynamic scheme");
933
+ if (!whole && /\{\{/.test(
934
+ input.match(/^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i)?.[1] ?? ""
935
+ ))
936
+ throw new Error("dynamic authority");
937
+ } catch {
938
+ issues.push({
939
+ code: "invalid_destination",
940
+ path,
941
+ message: "The resolved destination must be a valid app link or web URL"
942
+ });
943
+ }
944
+ }
945
+ return result;
946
+ }
947
+ if (Array.isArray(input))
948
+ return input.map(
949
+ (item, index) => renderPersonalizedValue(item, values, issues, `${path}/${index}`, mode)
950
+ );
951
+ if (input && typeof input === "object") {
952
+ const result = /* @__PURE__ */ Object.create(null);
953
+ for (const [name, value] of Object.entries(input)) {
954
+ if (["__proto__", "constructor", "prototype"].includes(name)) {
955
+ issues.push({
956
+ code: "invalid_template",
957
+ path,
958
+ message: "Reserved object key"
959
+ });
960
+ continue;
961
+ }
962
+ result[name] = renderPersonalizedValue(
963
+ value,
964
+ values,
965
+ issues,
966
+ `${path}/${name}`,
967
+ mode
968
+ );
969
+ }
970
+ return result;
971
+ }
972
+ return input;
973
+ }
974
+ var TEXT_KEYS = /* @__PURE__ */ new Set([
975
+ "title",
976
+ "body",
977
+ "subtitle",
978
+ "headline",
979
+ "label",
980
+ "placeholder",
981
+ "followUp",
982
+ "lowLabel",
983
+ "highLabel",
984
+ "description",
985
+ "buttonText",
986
+ "submitLabel",
987
+ "nextLabel",
988
+ "backLabel",
989
+ "text"
990
+ ]);
991
+ var URL_KEYS = /* @__PURE__ */ new Set(["imageUrl", "deepLink", "target"]);
992
+ var CONTENT_KEYS = /* @__PURE__ */ new Set([
993
+ "questions",
994
+ "options",
995
+ "ctas",
996
+ "cta",
997
+ "actionButtons",
998
+ "flow",
999
+ "welcome",
1000
+ "thankYou",
1001
+ "completion",
1002
+ "endScreen",
1003
+ "openAction"
1004
+ ]);
1005
+ function personalizationUsage(content) {
1006
+ const usage = /* @__PURE__ */ new Map();
1007
+ const scan = (value, field) => {
1008
+ if (typeof value === "string") {
1009
+ for (const match of value.matchAll(TOKEN)) {
1010
+ const fields = usage.get(match[1]) ?? /* @__PURE__ */ new Set();
1011
+ fields.add(field);
1012
+ usage.set(match[1], fields);
1013
+ }
1014
+ } else if (Array.isArray(value)) value.forEach((item) => scan(item, field));
1015
+ else if (value && typeof value === "object")
1016
+ Object.values(value).forEach((item) => scan(item, field));
1017
+ };
1018
+ const walk = (value) => {
1019
+ if (Array.isArray(value)) {
1020
+ value.forEach(walk);
1021
+ return;
1022
+ }
1023
+ if (!value || typeof value !== "object") return;
1024
+ for (const [key2, item] of Object.entries(value)) {
1025
+ if (TEXT_KEYS.has(key2) || URL_KEYS.has(key2) || key2 === "actionJson" || key2 === "payloadExtras")
1026
+ scan(item, key2);
1027
+ else if (CONTENT_KEYS.has(key2)) walk(item);
1028
+ }
1029
+ };
1030
+ walk(content);
1031
+ return usage;
1032
+ }
1033
+ function renderPersonalizedContent(content, resolution) {
1034
+ const usage = personalizationUsage(content);
1035
+ const onlyOptionalImage = (id2) => usage.get(id2)?.size === 1 && usage.get(id2)?.has("imageUrl");
1036
+ const issues = resolution.issues.filter(
1037
+ (issue) => !issue.bindingId || usage.has(issue.bindingId) && !(issue.code === "missing" && onlyOptionalImage(issue.bindingId))
1038
+ );
1039
+ const fallbacks = resolution.fallbackBindingIds.filter((id2) => usage.has(id2));
1040
+ const walk = (value, path = "") => {
1041
+ if (Array.isArray(value))
1042
+ return value.map((item, index) => walk(item, `${path}/${index}`));
1043
+ if (!value || typeof value !== "object") return value;
1044
+ return Object.fromEntries(
1045
+ Object.entries(value).map(([name, item]) => {
1046
+ const childPath = `${path}/${name}`;
1047
+ if (TEXT_KEYS.has(name) && typeof item === "string")
1048
+ return [
1049
+ name,
1050
+ renderPersonalizedValue(item, resolution.values, issues, childPath)
1051
+ ];
1052
+ if (URL_KEYS.has(name) && typeof item === "string") {
1053
+ if (name === "imageUrl" && [...item.matchAll(TOKEN)].some(
1054
+ (match) => resolution.issues.some(
1055
+ (issue) => issue.bindingId === match[1] && issue.code === "missing"
1056
+ )
1057
+ ))
1058
+ return [name, null];
1059
+ const isEvent = name === "target" && value.action === "custom_event";
1060
+ const rendered2 = renderPersonalizedValue(
1061
+ item,
1062
+ resolution.values,
1063
+ issues,
1064
+ childPath,
1065
+ isEvent ? "text" : "url"
1066
+ );
1067
+ if (name === "imageUrl" && rendered2 && !String(rendered2).startsWith("https://"))
1068
+ issues.push({
1069
+ code: "invalid_destination",
1070
+ path: childPath,
1071
+ message: "Image URLs must use HTTPS"
1072
+ });
1073
+ return [name, rendered2];
1074
+ }
1075
+ if (name === "actionJson" || name === "payloadExtras")
1076
+ return [
1077
+ name,
1078
+ renderPersonalizedValue(
1079
+ item,
1080
+ resolution.values,
1081
+ issues,
1082
+ childPath,
1083
+ "json"
1084
+ )
1085
+ ];
1086
+ if (CONTENT_KEYS.has(name)) return [name, walk(item, childPath)];
1087
+ return [name, item];
1088
+ })
1089
+ );
1090
+ };
1091
+ const rendered = walk(content);
1092
+ return {
1093
+ content: rendered,
1094
+ resolution: {
1095
+ ...resolution,
1096
+ fallbackBindingIds: fallbacks,
1097
+ status: issues.length ? "skipped" : fallbacks.length ? "using_fallback" : "ready",
1098
+ issues
1099
+ }
1100
+ };
1101
+ }
1102
+
1103
+ // src/presentation.ts
1104
+ var PresentationGate = class {
1105
+ paused;
1106
+ identity = 0;
1107
+ revisions = { feedback: 0, survey: 0 };
1108
+ listeners = /* @__PURE__ */ new Set();
1109
+ constructor(paused = false) {
1110
+ this.paused = paused;
1111
+ }
1112
+ get isPaused() {
1113
+ return this.paused;
1114
+ }
1115
+ setPaused(paused) {
1116
+ this.paused = paused;
1117
+ this.notify();
1118
+ }
1119
+ invalidate(purpose) {
1120
+ if (purpose) this.revisions[purpose]++;
1121
+ else this.identity++;
1122
+ this.notify();
1123
+ }
1124
+ validator(purpose) {
1125
+ const identity = this.identity;
1126
+ const revision = this.revisions[purpose];
1127
+ return () => identity === this.identity && revision === this.revisions[purpose];
1128
+ }
1129
+ subscribe(listener) {
1130
+ this.listeners.add(listener);
1131
+ return () => {
1132
+ this.listeners.delete(listener);
1133
+ };
1134
+ }
1135
+ runWhenReady(run, valid, cancel = () => {
1136
+ }) {
1137
+ if (!valid()) {
1138
+ cancel();
1139
+ return;
1140
+ }
1141
+ if (!this.paused) {
1142
+ run();
1143
+ return;
1144
+ }
1145
+ const stop = this.subscribe(() => {
1146
+ if (valid() && this.paused) return;
1147
+ stop();
1148
+ if (valid()) run();
1149
+ else cancel();
1150
+ });
1151
+ }
1152
+ waitUntilReady(valid) {
1153
+ if (!valid()) return Promise.resolve(false);
1154
+ if (!this.paused) return Promise.resolve(true);
1155
+ return new Promise((resolve) => {
1156
+ const stop = this.subscribe(() => {
1157
+ if (valid() && this.paused) return;
1158
+ stop();
1159
+ resolve(valid());
1160
+ });
1161
+ });
1162
+ }
1163
+ notify() {
1164
+ for (const listener of [...this.listeners]) listener();
1165
+ }
1166
+ };
1167
+
1168
+ export { APP_OPEN_EVENT_NAME, APP_VERSION_CHANGED_EVENT_NAME, AUDIENCE_JOIN_EVENT_NAME, AUDIENCE_JOIN_TRIGGER_KIND, CORE_INTEGRATION_EVENTS, DELIVERY_PROTOCOL_VERSION, INAPP_AUTO_DISMISSED_EVENT_NAME, INAPP_CTA_CLICKED_EVENT_NAME, INAPP_DISMISSED_EVENT_NAME, INAPP_SHOWN_EVENT_NAME, INTEGRATION_CATEGORIES, INTEGRATION_PROVIDERS, PUSH_EVENTS, PresentationGate, RADIUS_PRESETS, REQUEST_COMMENTED_EVENT_NAME, REQUEST_COMMENT_DELETED_EVENT_NAME, REQUEST_COMMENT_EDITED_EVENT_NAME, REQUEST_FOLLOWED_EVENT_NAME, REQUEST_RESPONDED_EVENT_NAME, REQUEST_STATUS_CHANGED_EVENT_NAME, REQUEST_SUBMITTED_EVENT_NAME, REQUEST_UNFOLLOWED_EVENT_NAME, REQUEST_UNUPVOTED_EVENT_NAME, REQUEST_UPVOTED_EVENT_NAME, SURVEY_END_SENTINEL, THEME_PRESETS, USER_IDENTIFIED_EVENT_NAME, brandTokensFromPreset, defaultEventTrigger, defaultOnboardingMessage, defaultThemePreset, defaultTriggerSpec, deliveryPlatformsForApp, emptyAudienceSpec, emptySegmentDsl, err, estimateProgress, evaluateBranchCondition, evaluateSegment, evaluateSerializedSegmentRules, findQuestion, findQuestionIndex, getCoreIntegrationEvent, getThemePresetById, inAppColorsFromBrandTokens, isSilentPushPayload, nextPeriodicFire, nextQuestionId, ok, personalizationSpecSchema, personalizationToken, personalizationUsage, promptThemeFromBrandTokens, reachableQuestions, renderPersonalizedContent, renderPersonalizedValue, requestAccentFromBrandTokens, resolvePersonalizationBindings, resolveWebPresentation, sanitizeCoreIntegrationProperties, serializedRulesToDsl, tzOffsetMinutes, userPropertiesUpdateSchema };
709
1169
  //# sourceMappingURL=mobile.js.map
710
1170
  //# sourceMappingURL=mobile.js.map