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