@funnelsgrove/runtime 0.11.2 → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +51 -0
  2. package/dist/components/ManageSubscriptionScreen.js +7 -2
  3. package/dist/services/api.service.d.ts +28 -104
  4. package/dist/services/api.service.js +24 -519
  5. package/dist/services/funnel-sdk/checkout/chargeOneClickPayment.d.ts +2 -0
  6. package/dist/services/funnel-sdk/checkout/chargeOneClickPayment.js +17 -0
  7. package/dist/services/funnel-sdk/checkout/createHostedCheckoutSession.d.ts +2 -0
  8. package/dist/services/funnel-sdk/checkout/createHostedCheckoutSession.js +9 -0
  9. package/dist/services/funnel-sdk/checkout/createOneTimeCheckout.d.ts +2 -0
  10. package/dist/services/funnel-sdk/checkout/createOneTimeCheckout.js +18 -0
  11. package/dist/services/funnel-sdk/checkout/createOneTimePaymentIntent.d.ts +3 -0
  12. package/dist/services/funnel-sdk/checkout/createOneTimePaymentIntent.js +10 -0
  13. package/dist/services/funnel-sdk/checkout/createSubscriptionCheckout.d.ts +2 -0
  14. package/dist/services/funnel-sdk/checkout/createSubscriptionCheckout.js +19 -0
  15. package/dist/services/funnel-sdk/checkout/requests.d.ts +126 -0
  16. package/dist/services/funnel-sdk/checkout/requests.js +111 -0
  17. package/dist/services/funnel-sdk/checkout/types.d.ts +183 -0
  18. package/dist/services/funnel-sdk/checkout/types.js +1 -0
  19. package/dist/services/funnel-sdk/checkout/updateSubscriptionCheckoutPlan.d.ts +2 -0
  20. package/dist/services/funnel-sdk/checkout/updateSubscriptionCheckoutPlan.js +18 -0
  21. package/dist/services/funnel-sdk/checkout/verifySubscriptionCheckout.d.ts +2 -0
  22. package/dist/services/funnel-sdk/checkout/verifySubscriptionCheckout.js +18 -0
  23. package/dist/services/funnel-sdk/shared/http.d.ts +20 -0
  24. package/dist/services/funnel-sdk/shared/http.js +65 -0
  25. package/dist/services/funnel-sdk/shared/runtimeConfig.d.ts +17 -0
  26. package/dist/services/funnel-sdk/shared/runtimeConfig.js +42 -0
  27. package/dist/services/funnel-sdk/shared/types.d.ts +9 -0
  28. package/dist/services/funnel-sdk/shared/types.js +1 -0
  29. package/dist/services/funnel-sdk/subscriptions/listSubscriptions.d.ts +3 -0
  30. package/dist/services/funnel-sdk/subscriptions/listSubscriptions.js +17 -0
  31. package/dist/services/funnel-sdk/subscriptions/types.d.ts +24 -0
  32. package/dist/services/funnel-sdk/subscriptions/types.js +1 -0
  33. package/dist/services/funnel-sdk/subscriptions/updateSubscription.d.ts +2 -0
  34. package/dist/services/funnel-sdk/subscriptions/updateSubscription.js +33 -0
  35. package/dist/services/funnel-sdk/subscriptions/validator.d.ts +2 -0
  36. package/dist/services/funnel-sdk/subscriptions/validator.js +15 -0
  37. package/dist/services/funnel-sdk/uploads/preparePhotoUpload.d.ts +4 -0
  38. package/dist/services/funnel-sdk/uploads/preparePhotoUpload.js +19 -0
  39. package/dist/services/funnel-sdk/uploads/types.d.ts +32 -0
  40. package/dist/services/funnel-sdk/uploads/types.js +1 -0
  41. package/dist/services/funnel-sdk/uploads/uploadPhoto.d.ts +7 -0
  42. package/dist/services/funnel-sdk/uploads/uploadPhoto.js +18 -0
  43. package/dist/services/funnel-sdk/uploads/uploadPhotoFile.d.ts +2 -0
  44. package/dist/services/funnel-sdk/uploads/uploadPhotoFile.js +26 -0
  45. package/dist/services/funnel-sdk/users/bootstrapUser.d.ts +3 -0
  46. package/dist/services/funnel-sdk/users/bootstrapUser.js +15 -0
  47. package/dist/services/funnel-sdk/users/captureEmail.d.ts +2 -0
  48. package/dist/services/funnel-sdk/users/captureEmail.js +15 -0
  49. package/dist/services/funnel-sdk/users/claimUserSubscription.d.ts +3 -0
  50. package/dist/services/funnel-sdk/users/claimUserSubscription.js +7 -0
  51. package/dist/services/funnel-sdk/users/getCurrentUser.d.ts +3 -0
  52. package/dist/services/funnel-sdk/users/getCurrentUser.js +13 -0
  53. package/dist/services/funnel-sdk/users/getUserSubscriptionStatus.d.ts +3 -0
  54. package/dist/services/funnel-sdk/users/getUserSubscriptionStatus.js +14 -0
  55. package/dist/services/funnel-sdk/users/types.d.ts +57 -0
  56. package/dist/services/funnel-sdk/users/types.js +1 -0
  57. package/dist/services/funnel-sdk/users/updateFunnelUser.d.ts +3 -0
  58. package/dist/services/funnel-sdk/users/updateFunnelUser.js +18 -0
  59. package/dist/services/funnel-sdk.service.d.ts +26 -319
  60. package/dist/services/funnel-sdk.service.js +38 -456
  61. package/dist/services/session/bootstrap/bootstrapSession.d.ts +8 -0
  62. package/dist/services/session/bootstrap/bootstrapSession.js +23 -0
  63. package/dist/services/session/bootstrap/currentUser.d.ts +1 -0
  64. package/dist/services/session/bootstrap/currentUser.js +37 -0
  65. package/dist/services/session/bootstrap/idempotency.d.ts +9 -0
  66. package/dist/services/session/bootstrap/idempotency.js +97 -0
  67. package/dist/services/session/bootstrap/requests.d.ts +23 -0
  68. package/dist/services/session/bootstrap/requests.js +25 -0
  69. package/dist/services/session/bootstrap/responses.d.ts +3 -0
  70. package/dist/services/session/bootstrap/responses.js +10 -0
  71. package/dist/services/session/bootstrap/types.d.ts +11 -0
  72. package/dist/services/session/bootstrap/types.js +1 -0
  73. package/dist/services/session/emailCapture/captureEmail.d.ts +8 -0
  74. package/dist/services/session/emailCapture/captureEmail.js +13 -0
  75. package/dist/services/session/emailCapture/requests.d.ts +12 -0
  76. package/dist/services/session/emailCapture/requests.js +6 -0
  77. package/dist/services/session/emailCapture/responses.d.ts +3 -0
  78. package/dist/services/session/emailCapture/responses.js +14 -0
  79. package/dist/services/session/emailCapture/types.d.ts +8 -0
  80. package/dist/services/session/emailCapture/types.js +1 -0
  81. package/dist/services/session/emailCapture/validator.d.ts +16 -0
  82. package/dist/services/session/emailCapture/validator.js +37 -0
  83. package/dist/services/session/identity.d.ts +6 -0
  84. package/dist/services/session/identity.js +48 -0
  85. package/dist/services/session/ping/pingUserContext.d.ts +2 -0
  86. package/dist/services/session/ping/pingUserContext.js +10 -0
  87. package/dist/services/session/ping/transport.d.ts +2 -0
  88. package/dist/services/session/ping/transport.js +41 -0
  89. package/dist/services/session/shared/values.d.ts +6 -0
  90. package/dist/services/session/shared/values.js +25 -0
  91. package/dist/services/session/subscriptions/getManageSubscriptions.d.ts +3 -0
  92. package/dist/services/session/subscriptions/getManageSubscriptions.js +8 -0
  93. package/dist/services/session/subscriptions/identity.d.ts +3 -0
  94. package/dist/services/session/subscriptions/identity.js +8 -0
  95. package/dist/services/session/subscriptions/types.d.ts +35 -0
  96. package/dist/services/session/subscriptions/types.js +1 -0
  97. package/dist/services/session/subscriptions/updateSubscription.d.ts +10 -0
  98. package/dist/services/session/subscriptions/updateSubscription.js +7 -0
  99. package/dist/services/session/subscriptions/validator.d.ts +6 -0
  100. package/dist/services/session/subscriptions/validator.js +13 -0
  101. package/dist/services/session/uploads/localPhoto.d.ts +2 -0
  102. package/dist/services/session/uploads/localPhoto.js +10 -0
  103. package/dist/services/session/uploads/requests.d.ts +10 -0
  104. package/dist/services/session/uploads/requests.js +7 -0
  105. package/dist/services/session/uploads/types.d.ts +7 -0
  106. package/dist/services/session/uploads/types.js +1 -0
  107. package/dist/services/session/uploads/uploadTempPhoto.d.ts +6 -0
  108. package/dist/services/session/uploads/uploadTempPhoto.js +13 -0
  109. package/dist/services/session/uploads/validator.d.ts +3 -0
  110. package/dist/services/session/uploads/validator.js +12 -0
  111. package/dist/services/session/users/mappers.d.ts +13 -0
  112. package/dist/services/session/users/mappers.js +33 -0
  113. package/dist/services/session/users/requests.d.ts +15 -0
  114. package/dist/services/session/users/requests.js +8 -0
  115. package/dist/services/session/users/syncUrlUserAttributes.d.ts +10 -0
  116. package/dist/services/session/users/syncUrlUserAttributes.js +21 -0
  117. package/dist/services/session/users/types.d.ts +20 -0
  118. package/dist/services/session/users/types.js +1 -0
  119. package/dist/services/session/users/updateUser.d.ts +6 -0
  120. package/dist/services/session/users/updateUser.js +18 -0
  121. package/package.json +1 -1
  122. /package/dist/services/{funnel-sdk-payments.functions.d.ts → funnel-sdk/checkout/selection.d.ts} +0 -0
  123. /package/dist/services/{funnel-sdk-payments.functions.js → funnel-sdk/checkout/selection.js} +0 -0
@@ -1,520 +1,25 @@
1
- import { buildSdkHeaders, FUNNEL_ID, FUNNEL_VERSION_ID, getFunnelSdkPublishableKey, } from './runtime-api.config.js';
2
- import { funnelSdkService } from './funnel-sdk.service.js';
3
- import { mergeFunnelUserAttribution, } from '../runtime/funnel-attribution.js';
4
- import { applyUrlUserAttributesToUser, hasUrlUserProfileAttributes, resolveUrlUserAttributes, } from '../runtime/url-user-attributes.js';
5
- import { getRuntimeMode } from './runtime-mode.service.js';
6
- const DEFAULT_USER_ID_STORAGE_KEY = 'funnel:user-id';
7
- const DEFAULT_BOOTSTRAP_IDEMPOTENCY_KEY_STORAGE_KEY = 'funnel:bootstrap-idempotency-key';
8
- const SUBSCRIPTION_MANAGEMENT_LINK_ERROR = 'This subscription management link is invalid or has expired. Please request a new link or contact support.';
9
- const canUseDom = () => {
10
- return typeof window !== 'undefined';
1
+ import { getOrCreateClientUserId, persistCanonicalUserId, getBootstrapCandidateUserId } from './session/identity.js';
2
+ import { getSubscriptionManagementUserId, getSubscriptionManagementStripeCustomerId } from './session/subscriptions/identity.js';
3
+ import { bootstrapSession } from './session/bootstrap/bootstrapSession.js';
4
+ import { updateUser } from './session/users/updateUser.js';
5
+ import { syncUrlUserAttributes } from './session/users/syncUrlUserAttributes.js';
6
+ import { captureEmail } from './session/emailCapture/captureEmail.js';
7
+ import { uploadTempPhoto } from './session/uploads/uploadTempPhoto.js';
8
+ import { pingUserContext } from './session/ping/pingUserContext.js';
9
+ import { getManageSubscriptions } from './session/subscriptions/getManageSubscriptions.js';
10
+ import { updateSubscription } from './session/subscriptions/updateSubscription.js';
11
+ export const apiService = {
12
+ getOrCreateClientUserId,
13
+ persistCanonicalUserId,
14
+ getSubscriptionManagementUserId,
15
+ getSubscriptionManagementStripeCustomerId,
16
+ getBootstrapCandidateUserId,
17
+ bootstrapSession,
18
+ updateUser,
19
+ captureEmail,
20
+ syncUrlUserAttributes,
21
+ pingUserContext,
22
+ uploadTempPhoto,
23
+ getManageSubscriptions,
24
+ updateSubscription,
11
25
  };
12
- const isRecord = (value) => {
13
- return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
14
- };
15
- const asRecord = (value) => {
16
- return isRecord(value) ? value : {};
17
- };
18
- const asString = (value) => {
19
- if (typeof value !== 'string') {
20
- return null;
21
- }
22
- const trimmed = value.trim();
23
- return trimmed || null;
24
- };
25
- const asNumber = (value) => {
26
- if (typeof value !== 'number' || !Number.isFinite(value)) {
27
- return null;
28
- }
29
- return value;
30
- };
31
- const resolveBrowserTimezone = () => {
32
- if (!canUseDom()) {
33
- return null;
34
- }
35
- try {
36
- return asString(Intl.DateTimeFormat().resolvedOptions().timeZone);
37
- }
38
- catch (_a) {
39
- return null;
40
- }
41
- };
42
- const normalizeUserId = (value) => {
43
- if (!value || typeof value !== 'string') {
44
- return null;
45
- }
46
- const trimmed = value.trim();
47
- return trimmed || null;
48
- };
49
- const normalizeFunnelId = (value) => {
50
- return asString(value);
51
- };
52
- const buildUserIdStorageKey = (funnelId = FUNNEL_ID) => {
53
- const normalizedFunnelId = normalizeFunnelId(funnelId);
54
- if (!normalizedFunnelId) {
55
- return DEFAULT_USER_ID_STORAGE_KEY;
56
- }
57
- return `funnel:${normalizedFunnelId}:user-id`;
58
- };
59
- const buildBootstrapIdempotencyKeyStorageKey = (funnelId = FUNNEL_ID) => {
60
- const normalizedFunnelId = normalizeFunnelId(funnelId);
61
- return normalizedFunnelId
62
- ? `funnel:${normalizedFunnelId}:bootstrap-idempotency-key`
63
- : DEFAULT_BOOTSTRAP_IDEMPOTENCY_KEY_STORAGE_KEY;
64
- };
65
- const generateBootstrapIdempotencyKey = () => {
66
- var _a;
67
- if (canUseDom() && typeof ((_a = window.crypto) === null || _a === void 0 ? void 0 : _a.randomUUID) === 'function') {
68
- return window.crypto.randomUUID();
69
- }
70
- return `${Date.now()}_${Math.random().toString(16).slice(2, 10)}`;
71
- };
72
- const parseBootstrapIdempotencyRecord = (value) => {
73
- if (!value) {
74
- return null;
75
- }
76
- try {
77
- const parsed = JSON.parse(value);
78
- const key = asString(parsed.key);
79
- const fingerprint = asString(parsed.fingerprint);
80
- return parsed.version === 1 && key && fingerprint
81
- ? { version: 1, key, fingerprint }
82
- : null;
83
- }
84
- catch (_a) {
85
- return null;
86
- }
87
- };
88
- const toStableJsonValue = (value) => {
89
- if (Array.isArray(value)) {
90
- return value.map(toStableJsonValue);
91
- }
92
- if (!isRecord(value)) {
93
- return value;
94
- }
95
- return Object.keys(value).sort().reduce((result, key) => {
96
- if (value[key] !== undefined) {
97
- result[key] = toStableJsonValue(value[key]);
98
- }
99
- return result;
100
- }, {});
101
- };
102
- const buildFallbackDigest = (value) => {
103
- var _a;
104
- const bytes = new TextEncoder().encode(value);
105
- const hashes = Array.from({ length: 8 }, (_, index) => ((0x811c9dc5 ^ Math.imul(index + 1, 0x9e3779b1)) >>> 0));
106
- for (const byte of bytes) {
107
- for (let index = 0; index < hashes.length; index += 1) {
108
- hashes[index] = Math.imul(((_a = hashes[index]) !== null && _a !== void 0 ? _a : 0) ^ byte, 0x01000193 + index * 2) >>> 0;
109
- }
110
- }
111
- return hashes.map((hash) => hash.toString(16).padStart(8, '0')).join('');
112
- };
113
- const digestBootstrapRequest = async (value) => {
114
- var _a;
115
- const serialized = JSON.stringify(toStableJsonValue(value));
116
- const bytes = new TextEncoder().encode(serialized);
117
- const subtle = (_a = globalThis.crypto) === null || _a === void 0 ? void 0 : _a.subtle;
118
- if (!subtle) {
119
- return `fallback:${buildFallbackDigest(serialized)}`;
120
- }
121
- const digest = await subtle.digest('SHA-256', bytes);
122
- const hex = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, '0')).join('');
123
- return `sha256:${hex}`;
124
- };
125
- const getOrCreateBootstrapIdempotencyRecord = (fingerprint) => {
126
- const created = () => ({
127
- version: 1,
128
- key: generateBootstrapIdempotencyKey(),
129
- fingerprint,
130
- });
131
- if (!canUseDom()) {
132
- return created();
133
- }
134
- const storageKey = buildBootstrapIdempotencyKeyStorageKey();
135
- const existing = parseBootstrapIdempotencyRecord(window.localStorage.getItem(storageKey));
136
- if ((existing === null || existing === void 0 ? void 0 : existing.fingerprint) === fingerprint) {
137
- return existing;
138
- }
139
- const next = created();
140
- window.localStorage.setItem(storageKey, JSON.stringify(next));
141
- return next;
142
- };
143
- const clearBootstrapIdempotencyRecord = (completed) => {
144
- if (!canUseDom()) {
145
- return;
146
- }
147
- const storageKey = buildBootstrapIdempotencyKeyStorageKey();
148
- const current = parseBootstrapIdempotencyRecord(window.localStorage.getItem(storageKey));
149
- if ((current === null || current === void 0 ? void 0 : current.key) === completed.key && current.fingerprint === completed.fingerprint) {
150
- window.localStorage.removeItem(storageKey);
151
- }
152
- };
153
- const generateUserId = () => {
154
- var _a;
155
- if (canUseDom() && typeof ((_a = window.crypto) === null || _a === void 0 ? void 0 : _a.randomUUID) === 'function') {
156
- return `u_${window.crypto.randomUUID().replace(/-/g, '')}`;
157
- }
158
- return `u_${Date.now()}_${Math.random().toString(16).slice(2, 10)}`;
159
- };
160
- const readStoredUserId = (funnelId = FUNNEL_ID) => {
161
- if (!canUseDom()) {
162
- return null;
163
- }
164
- return normalizeUserId(window.localStorage.getItem(buildUserIdStorageKey(funnelId)));
165
- };
166
- const persistUserId = (value, funnelId = FUNNEL_ID) => {
167
- const normalized = normalizeUserId(value) || generateUserId();
168
- if (canUseDom()) {
169
- window.localStorage.setItem(buildUserIdStorageKey(funnelId), normalized);
170
- }
171
- return normalized;
172
- };
173
- const withMergedAttributionDocument = (document, attribution) => {
174
- const normalizedDocument = asRecord(document);
175
- if (!attribution) {
176
- return normalizedDocument;
177
- }
178
- return Object.assign(Object.assign({}, normalizedDocument), { attribution: mergeFunnelUserAttribution(normalizedDocument.attribution, attribution) });
179
- };
180
- const toAppUser = (input) => {
181
- var _a, _b;
182
- const apiUser = input.apiUser;
183
- const apiDocument = asRecord(apiUser === null || apiUser === void 0 ? void 0 : apiUser.document);
184
- const apiProgress = asRecord(apiDocument.progress);
185
- const apiAttributes = asRecord(apiProgress.attributes);
186
- return {
187
- id: input.userId,
188
- name: asString(apiUser === null || apiUser === void 0 ? void 0 : apiUser.fullName) || input.fallbackName || '',
189
- email: asString(apiUser === null || apiUser === void 0 ? void 0 : apiUser.email) || input.fallbackEmail || '',
190
- attributes: Object.keys(apiAttributes).length > 0
191
- ? apiAttributes
192
- : ((_a = input.fallbackAttributes) !== null && _a !== void 0 ? _a : {}),
193
- document: Object.keys(apiDocument).length > 0 ? apiDocument : ((_b = input.fallbackDocument) !== null && _b !== void 0 ? _b : {}),
194
- };
195
- };
196
- class ApiService {
197
- getOrCreateClientUserId() {
198
- const existing = readStoredUserId(FUNNEL_ID);
199
- if (existing) {
200
- return existing;
201
- }
202
- return persistUserId(generateUserId(), FUNNEL_ID);
203
- }
204
- persistCanonicalUserId(userId) {
205
- const normalizedUserId = normalizeUserId(userId);
206
- if (!normalizedUserId) {
207
- throw new Error('Invalid canonical user id');
208
- }
209
- return persistUserId(normalizedUserId, FUNNEL_ID);
210
- }
211
- getSubscriptionManagementUserId() {
212
- return resolveUrlUserAttributes().userId;
213
- }
214
- getSubscriptionManagementStripeCustomerId() {
215
- return resolveUrlUserAttributes().stripeCustomerId;
216
- }
217
- getBootstrapCandidateUserId(fallbackUserId) {
218
- return resolveUrlUserAttributes().userId || normalizeUserId(fallbackUserId);
219
- }
220
- async fetchCurrentUserState(userId) {
221
- const publishableKey = getFunnelSdkPublishableKey();
222
- if (!publishableKey || !FUNNEL_ID) {
223
- return null;
224
- }
225
- try {
226
- return await funnelSdkService.getCurrentUser({
227
- userId,
228
- });
229
- }
230
- catch (_a) {
231
- return null;
232
- }
233
- }
234
- async resolveBootstrapUserId(candidateUserId) {
235
- var _a;
236
- const storedUserId = readStoredUserId(FUNNEL_ID);
237
- const fallbackUserId = storedUserId || generateUserId();
238
- const normalizedCandidateUserId = normalizeUserId(candidateUserId);
239
- const publishableKey = getFunnelSdkPublishableKey();
240
- if (!normalizedCandidateUserId) {
241
- return persistUserId(fallbackUserId, FUNNEL_ID);
242
- }
243
- if (normalizedCandidateUserId === storedUserId) {
244
- return persistUserId(normalizedCandidateUserId, FUNNEL_ID);
245
- }
246
- if (!publishableKey || !FUNNEL_ID) {
247
- return persistUserId(fallbackUserId, FUNNEL_ID);
248
- }
249
- const existingUser = await this.fetchCurrentUserState(normalizedCandidateUserId);
250
- const resolvedCandidateUserId = normalizeUserId(asString((_a = existingUser === null || existingUser === void 0 ? void 0 : existingUser.user) === null || _a === void 0 ? void 0 : _a.user_id) || asString(existingUser === null || existingUser === void 0 ? void 0 : existingUser.user_id));
251
- return persistUserId(resolvedCandidateUserId || fallbackUserId, FUNNEL_ID);
252
- }
253
- async bootstrapSession(input) {
254
- var _a, _b, _c;
255
- const urlUserAttributes = resolveUrlUserAttributes();
256
- const inputEmail = (input === null || input === void 0 ? void 0 : input.email) || undefined;
257
- const inputName = (input === null || input === void 0 ? void 0 : input.name) || undefined;
258
- const candidateUserId = (input === null || input === void 0 ? void 0 : input.userId) || urlUserAttributes.userId;
259
- const userId = await this.resolveBootstrapUserId(candidateUserId);
260
- const publishableKey = getFunnelSdkPublishableKey();
261
- if (!publishableKey) {
262
- return toAppUser({
263
- userId,
264
- fallbackName: inputName,
265
- fallbackEmail: inputEmail,
266
- fallbackDocument: withMergedAttributionDocument({}, input === null || input === void 0 ? void 0 : input.attribution),
267
- });
268
- }
269
- const metadata = {
270
- source: 'funnel-session',
271
- environment: getRuntimeMode(),
272
- };
273
- const fingerprint = await digestBootstrapRequest({
274
- funnelVersionId: asString(FUNNEL_VERSION_ID),
275
- userId,
276
- email: (_b = (_a = asString(inputEmail)) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : null,
277
- fullName: asString(inputName),
278
- metadata,
279
- attribution: mergeFunnelUserAttribution({}, input === null || input === void 0 ? void 0 : input.attribution),
280
- });
281
- const idempotencyRecord = getOrCreateBootstrapIdempotencyRecord(fingerprint);
282
- const payload = await funnelSdkService.bootstrapUser({
283
- userId,
284
- idempotencyKey: idempotencyRecord.key,
285
- email: inputEmail,
286
- fullName: inputName,
287
- metadata,
288
- attribution: input === null || input === void 0 ? void 0 : input.attribution,
289
- });
290
- clearBootstrapIdempotencyRecord(idempotencyRecord);
291
- const persistedUserId = persistUserId(asString((_c = payload.user) === null || _c === void 0 ? void 0 : _c.user_id) ||
292
- asString(payload.user_id) ||
293
- userId, FUNNEL_ID) || userId;
294
- return toAppUser({
295
- apiUser: payload.user,
296
- userId: persistedUserId,
297
- fallbackName: inputName,
298
- fallbackEmail: inputEmail,
299
- fallbackDocument: withMergedAttributionDocument({}, input === null || input === void 0 ? void 0 : input.attribution),
300
- });
301
- }
302
- async updateUser(user, options) {
303
- const userId = normalizeUserId(user.id) || this.getOrCreateClientUserId();
304
- const persistedUserId = (options === null || options === void 0 ? void 0 : options.persistClientIdentity) === false
305
- ? userId
306
- : persistUserId(userId, FUNNEL_ID);
307
- const publishableKey = getFunnelSdkPublishableKey();
308
- if (!publishableKey) {
309
- return toAppUser({
310
- userId: persistedUserId,
311
- fallbackName: user.name,
312
- fallbackEmail: user.email,
313
- fallbackAttributes: user.attributes,
314
- fallbackDocument: withMergedAttributionDocument(user.document, options === null || options === void 0 ? void 0 : options.attribution),
315
- });
316
- }
317
- const payload = await funnelSdkService.updateFunnelUser({
318
- userId: persistedUserId,
319
- email: user.email || undefined,
320
- fullName: user.name || undefined,
321
- progress: {
322
- attributes: user.attributes || {},
323
- },
324
- metadata: {
325
- source: 'funnel',
326
- environment: getRuntimeMode(),
327
- },
328
- attribution: options === null || options === void 0 ? void 0 : options.attribution,
329
- });
330
- return toAppUser({
331
- apiUser: payload.user,
332
- userId: persistedUserId,
333
- fallbackName: user.name,
334
- fallbackEmail: user.email,
335
- fallbackAttributes: user.attributes,
336
- fallbackDocument: withMergedAttributionDocument(user.document, options === null || options === void 0 ? void 0 : options.attribution),
337
- });
338
- }
339
- async captureEmail(input) {
340
- var _a, _b, _c, _d;
341
- const userId = input.userId.trim();
342
- const email = input.email.trim().toLowerCase();
343
- const payload = await funnelSdkService.captureEmail({
344
- userId,
345
- email,
346
- environment: input.environment,
347
- answers: input.answers,
348
- });
349
- const eventId = asString(payload.eventId);
350
- const responseUser = isRecord(payload.user) ? payload.user : null;
351
- const responseUserId = responseUser === null || responseUser === void 0 ? void 0 : responseUser.user_id;
352
- const responseEmail = (_b = (_a = asString(responseUser === null || responseUser === void 0 ? void 0 : responseUser.email)) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : null;
353
- const canonicalUserValue = payload.canonicalUser;
354
- const canonicalUserRecord = isRecord(canonicalUserValue)
355
- ? canonicalUserValue
356
- : null;
357
- const canonicalUserId = asString(canonicalUserRecord === null || canonicalUserRecord === void 0 ? void 0 : canonicalUserRecord.user_id);
358
- const canonicalUserEmail = (_d = (_c = asString(canonicalUserRecord === null || canonicalUserRecord === void 0 ? void 0 : canonicalUserRecord.email)) === null || _c === void 0 ? void 0 : _c.toLowerCase()) !== null && _d !== void 0 ? _d : null;
359
- const hasCanonicalUser = canonicalUserValue !== undefined
360
- && canonicalUserValue !== null;
361
- const canonicalUserKeys = canonicalUserRecord
362
- ? Object.keys(canonicalUserRecord)
363
- : [];
364
- if (!eventId
365
- || typeof payload.eventCreated !== 'boolean'
366
- || typeof payload.activeSubscription !== 'boolean'
367
- || !responseUser
368
- || typeof responseUserId !== 'string'
369
- || responseUserId !== userId
370
- || responseEmail !== email
371
- || (hasCanonicalUser
372
- && (!canonicalUserRecord
373
- || !canonicalUserId
374
- || canonicalUserEmail !== email
375
- || canonicalUserKeys.length !== 2
376
- || canonicalUserKeys.some((key) => key !== 'user_id' && key !== 'email')))) {
377
- throw new Error('Invalid email capture response');
378
- }
379
- const persistedUserId = persistUserId(userId, FUNNEL_ID);
380
- const canonicalUser = canonicalUserRecord && canonicalUserId
381
- ? {
382
- id: canonicalUserId,
383
- name: '',
384
- email,
385
- attributes: {},
386
- document: {},
387
- }
388
- : null;
389
- return {
390
- user: toAppUser({
391
- apiUser: Object.assign(Object.assign({}, responseUser), { user_id: userId, email }),
392
- userId: persistedUserId,
393
- fallbackEmail: email,
394
- }),
395
- eventId,
396
- eventCreated: payload.eventCreated,
397
- canonicalUser,
398
- activeSubscription: payload.activeSubscription,
399
- };
400
- }
401
- async syncUrlUserAttributes(input) {
402
- var _a;
403
- if (!hasUrlUserProfileAttributes(input.urlAttributes)) {
404
- return null;
405
- }
406
- const nextUser = applyUrlUserAttributesToUser({
407
- user: input.user,
408
- attributes: input.attributes,
409
- urlAttributes: input.urlAttributes,
410
- });
411
- const updatedUser = await this.updateUser(Object.assign(Object.assign({}, nextUser), { document: (_a = nextUser.document) !== null && _a !== void 0 ? _a : {} }), {
412
- attribution: input.attribution,
413
- });
414
- return applyUrlUserAttributesToUser({
415
- user: updatedUser,
416
- attributes: nextUser.attributes,
417
- urlAttributes: input.urlAttributes,
418
- });
419
- }
420
- async pingUserContext(userId) {
421
- var _a;
422
- const normalizedUserId = normalizeUserId(userId);
423
- const publishableKey = getFunnelSdkPublishableKey();
424
- if (!normalizedUserId || !publishableKey || !FUNNEL_ID || !canUseDom()) {
425
- return null;
426
- }
427
- try {
428
- const response = await fetch('/api/ping', {
429
- method: 'POST',
430
- headers: buildSdkHeaders({
431
- 'Content-Type': 'application/json',
432
- }),
433
- body: JSON.stringify({
434
- funnelId: FUNNEL_ID,
435
- user_id: normalizedUserId,
436
- timezone: resolveBrowserTimezone() || undefined,
437
- }),
438
- });
439
- if (!response.ok) {
440
- return null;
441
- }
442
- const payload = (await response.json());
443
- return toAppUser({
444
- apiUser: payload.user,
445
- userId: asString((_a = payload.user) === null || _a === void 0 ? void 0 : _a.user_id) || normalizedUserId,
446
- });
447
- }
448
- catch (_b) {
449
- return null;
450
- }
451
- }
452
- async uploadTempPhoto(input) {
453
- const userId = persistUserId(input.userId || this.getOrCreateClientUserId(), FUNNEL_ID);
454
- const publishableKey = getFunnelSdkPublishableKey();
455
- if (!publishableKey) {
456
- const imageDataUrl = URL.createObjectURL(input.file);
457
- return {
458
- key: `local_${userId}_${Date.now()}`,
459
- publicUrl: imageDataUrl,
460
- contentType: input.file.type || 'image/jpeg',
461
- sizeBytes: input.file.size || 0,
462
- uploadedAt: new Date().toISOString(),
463
- };
464
- }
465
- const payload = await funnelSdkService.uploadPhotoFile({
466
- userId,
467
- fileName: input.file.name || 'capture.jpg',
468
- contentType: input.file.type || undefined,
469
- file: input.file,
470
- source: input.source || 'upload',
471
- });
472
- const publicUrl = asString(payload.publicUrl);
473
- const key = asString(payload.key);
474
- const contentType = asString(payload.contentType) || input.file.type || 'image/jpeg';
475
- const sizeBytes = asNumber(payload.sizeBytes) || input.file.size || 0;
476
- const uploadedAt = asString(payload.uploadedAt) || new Date().toISOString();
477
- if (!publicUrl || !key) {
478
- throw new Error('Invalid photo upload response');
479
- }
480
- return {
481
- key,
482
- publicUrl,
483
- contentType,
484
- sizeBytes,
485
- uploadedAt,
486
- };
487
- }
488
- async getManageSubscriptions() {
489
- const userId = this.getSubscriptionManagementUserId();
490
- const stripeCustomerId = this.getSubscriptionManagementStripeCustomerId();
491
- if (!userId && !stripeCustomerId) {
492
- throw new Error(SUBSCRIPTION_MANAGEMENT_LINK_ERROR);
493
- }
494
- const payload = await funnelSdkService.listSubscriptions({
495
- userId,
496
- stripeCustomerId,
497
- funnelId: FUNNEL_ID || undefined,
498
- });
499
- if (!payload.user) {
500
- throw new Error(SUBSCRIPTION_MANAGEMENT_LINK_ERROR);
501
- }
502
- return payload;
503
- }
504
- async updateSubscription(input) {
505
- const userId = this.getSubscriptionManagementUserId();
506
- const stripeCustomerId = this.getSubscriptionManagementStripeCustomerId();
507
- if (!userId && !stripeCustomerId) {
508
- throw new Error(SUBSCRIPTION_MANAGEMENT_LINK_ERROR);
509
- }
510
- return funnelSdkService.updateSubscription({
511
- subscriptionId: input.subscriptionId,
512
- action: input.action,
513
- couponId: input.couponId,
514
- userId,
515
- stripeCustomerId,
516
- funnelId: FUNNEL_ID || undefined,
517
- });
518
- }
519
- }
520
- export const apiService = new ApiService();
@@ -0,0 +1,2 @@
1
+ import type { FunnelSdkChargeOneClickPaymentInput, FunnelSdkChargeOneClickPaymentResponse } from './types.js';
2
+ export declare const chargeOneClickPayment: (input: FunnelSdkChargeOneClickPaymentInput) => Promise<FunnelSdkChargeOneClickPaymentResponse>;
@@ -0,0 +1,17 @@
1
+ import { toV1OneClickPaymentRequest, toV2OneClickPaymentRequest } from './requests.js';
2
+ import { postJson } from '../shared/http.js';
3
+ import { resolveRuntimeConfig } from '../shared/runtimeConfig.js';
4
+ export const chargeOneClickPayment = async (input) => {
5
+ if (resolveRuntimeConfig(input.runtimeConfig).paymentsApiVersion === 'v2') {
6
+ return postJson('/sdk/public/v2/payments/one-click', {
7
+ runtimeConfig: input.runtimeConfig,
8
+ body: toV2OneClickPaymentRequest(input),
9
+ errorMessage: 'Unable to charge one-click payment',
10
+ });
11
+ }
12
+ return postJson('/sdk/public/payments/one-click', {
13
+ runtimeConfig: input.runtimeConfig,
14
+ body: toV1OneClickPaymentRequest(input),
15
+ errorMessage: 'Unable to charge one-click payment',
16
+ });
17
+ };
@@ -0,0 +1,2 @@
1
+ import type { FunnelSdkCreateHostedCheckoutSessionInput, FunnelSdkCreateHostedCheckoutSessionResponse } from './types.js';
2
+ export declare const createHostedCheckoutSession: (input: FunnelSdkCreateHostedCheckoutSessionInput) => Promise<FunnelSdkCreateHostedCheckoutSessionResponse>;
@@ -0,0 +1,9 @@
1
+ import { toV1HostedCheckoutRequest } from './requests.js';
2
+ import { postJson } from '../shared/http.js';
3
+ export const createHostedCheckoutSession = async (input) => {
4
+ return postJson('/sdk/public/payments/checkout-session', {
5
+ runtimeConfig: input.runtimeConfig,
6
+ body: toV1HostedCheckoutRequest(input),
7
+ errorMessage: 'Unable to create checkout session',
8
+ });
9
+ };
@@ -0,0 +1,2 @@
1
+ import type { FunnelSdkCreateOneTimeCheckoutInput, FunnelSdkCreateOneTimeCheckoutResponse } from './types.js';
2
+ export declare const createOneTimeCheckout: (input: FunnelSdkCreateOneTimeCheckoutInput) => Promise<FunnelSdkCreateOneTimeCheckoutResponse>;
@@ -0,0 +1,18 @@
1
+ import { toV1OneTimeCheckoutRequest } from './requests.js';
2
+ import { postJson } from '../shared/http.js';
3
+ import { resolveRuntimeConfig } from '../shared/runtimeConfig.js';
4
+ import { toV2CheckoutSessionRequest } from './selection.js';
5
+ export const createOneTimeCheckout = async (input) => {
6
+ if (resolveRuntimeConfig(input.runtimeConfig).paymentsApiVersion === 'v2') {
7
+ return postJson('/sdk/public/v2/payments/checkout-sessions', {
8
+ runtimeConfig: input.runtimeConfig,
9
+ body: toV2CheckoutSessionRequest(input, 'one_time'),
10
+ errorMessage: 'Unable to create one-time checkout',
11
+ });
12
+ }
13
+ return postJson('/sdk/public/payments/one-time-checkout', {
14
+ runtimeConfig: input.runtimeConfig,
15
+ body: toV1OneTimeCheckoutRequest(input),
16
+ errorMessage: 'Unable to create one-time checkout',
17
+ });
18
+ };
@@ -0,0 +1,3 @@
1
+ import type { FunnelSdkCreateOneTimePaymentIntentInput, FunnelSdkCreateOneTimePaymentIntentResponse } from './types.js';
2
+ /** @deprecated Use createOneTimeCheckout for one-time paywall checkout. */
3
+ export declare const createOneTimePaymentIntent: (input: FunnelSdkCreateOneTimePaymentIntentInput) => Promise<FunnelSdkCreateOneTimePaymentIntentResponse>;
@@ -0,0 +1,10 @@
1
+ import { toV1PaymentIntentRequest } from './requests.js';
2
+ import { postJson } from '../shared/http.js';
3
+ /** @deprecated Use createOneTimeCheckout for one-time paywall checkout. */
4
+ export const createOneTimePaymentIntent = async (input) => {
5
+ return postJson('/sdk/public/payments/intents', {
6
+ runtimeConfig: input.runtimeConfig,
7
+ body: toV1PaymentIntentRequest(input),
8
+ errorMessage: 'Unable to create payment intent',
9
+ });
10
+ };
@@ -0,0 +1,2 @@
1
+ import type { FunnelSdkCreateSubscriptionCheckoutInput, FunnelSdkCreateSubscriptionCheckoutResponse } from './types.js';
2
+ export declare const createSubscriptionCheckout: (input: FunnelSdkCreateSubscriptionCheckoutInput) => Promise<FunnelSdkCreateSubscriptionCheckoutResponse>;
@@ -0,0 +1,19 @@
1
+ import { toV1SubscriptionCheckoutRequest } from './requests.js';
2
+ import { postJson } from '../shared/http.js';
3
+ import { resolveRuntimeConfig } from '../shared/runtimeConfig.js';
4
+ import { toV2CheckoutSessionRequest } from './selection.js';
5
+ export const createSubscriptionCheckout = async (input) => {
6
+ const { paymentsApiVersion } = resolveRuntimeConfig(input.runtimeConfig);
7
+ if (paymentsApiVersion === 'v2') {
8
+ return postJson('/sdk/public/v2/payments/checkout-sessions', {
9
+ runtimeConfig: input.runtimeConfig,
10
+ body: toV2CheckoutSessionRequest(input, 'subscription'),
11
+ errorMessage: 'Unable to create subscription checkout',
12
+ });
13
+ }
14
+ return postJson('/sdk/public/payments/subscriptions', {
15
+ runtimeConfig: input.runtimeConfig,
16
+ body: toV1SubscriptionCheckoutRequest(input),
17
+ errorMessage: 'Unable to create subscription checkout',
18
+ });
19
+ };