@funnelsgrove/runtime 0.7.26 → 0.7.28
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.
|
@@ -13,6 +13,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
13
13
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
14
|
import { createContext, useContext, useEffect, useMemo, useState, } from 'react';
|
|
15
15
|
import { loadFunnelRuntimeConfig, resolvePublishedFunnelRuntimeConfig, } from '../services/funnel-runtime-config.js';
|
|
16
|
+
import { isPreviewFrameRuntime } from '../services/preview-frame.service.js';
|
|
16
17
|
const FunnelRuntimeConfigContext = createContext({
|
|
17
18
|
status: 'fallback',
|
|
18
19
|
config: null,
|
|
@@ -32,6 +33,12 @@ function ActiveFunnelRuntimeConfigBoundary({ funnelId, funnelVersionId, children
|
|
|
32
33
|
error: null,
|
|
33
34
|
});
|
|
34
35
|
useEffect(() => {
|
|
36
|
+
// The server snapshot cannot see the browser query string, so a preview
|
|
37
|
+
// frame can briefly mount this active boundary during hydration. Avoid a
|
|
38
|
+
// same-origin config request before the parent switches to disabled mode.
|
|
39
|
+
if (isPreviewFrameRuntime()) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
35
42
|
let active = true;
|
|
36
43
|
let refreshTimer = null;
|
|
37
44
|
const refresh = () => loadFunnelRuntimeConfig(funnelId, { versionId: funnelVersionId })
|
|
@@ -59,7 +59,6 @@ export type EmailCaptureResult = {
|
|
|
59
59
|
activeSubscription: boolean;
|
|
60
60
|
};
|
|
61
61
|
declare class ApiService {
|
|
62
|
-
private readFileAsDataUrl;
|
|
63
62
|
getOrCreateClientUserId(): string;
|
|
64
63
|
persistCanonicalUserId(userId: string): string;
|
|
65
64
|
getSubscriptionManagementUserId(): string | null;
|
|
@@ -194,20 +194,6 @@ const toAppUser = (input) => {
|
|
|
194
194
|
};
|
|
195
195
|
};
|
|
196
196
|
class ApiService {
|
|
197
|
-
readFileAsDataUrl(file) {
|
|
198
|
-
return new Promise((resolve, reject) => {
|
|
199
|
-
const reader = new FileReader();
|
|
200
|
-
reader.onload = () => {
|
|
201
|
-
if (typeof reader.result !== 'string' || !reader.result.trim()) {
|
|
202
|
-
reject(new Error('Failed to read image'));
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
resolve(reader.result);
|
|
206
|
-
};
|
|
207
|
-
reader.onerror = () => reject(new Error('Failed to read image'));
|
|
208
|
-
reader.readAsDataURL(file);
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
197
|
getOrCreateClientUserId() {
|
|
212
198
|
const existing = readStoredUserId(FUNNEL_ID);
|
|
213
199
|
if (existing) {
|
|
@@ -465,8 +451,8 @@ class ApiService {
|
|
|
465
451
|
async uploadTempPhoto(input) {
|
|
466
452
|
const userId = persistUserId(input.userId || this.getOrCreateClientUserId(), FUNNEL_ID);
|
|
467
453
|
const publishableKey = getFunnelSdkPublishableKey();
|
|
468
|
-
const imageDataUrl = await this.readFileAsDataUrl(input.file);
|
|
469
454
|
if (!publishableKey) {
|
|
455
|
+
const imageDataUrl = URL.createObjectURL(input.file);
|
|
470
456
|
return {
|
|
471
457
|
key: `local_${userId}_${Date.now()}`,
|
|
472
458
|
publicUrl: imageDataUrl,
|
|
@@ -475,11 +461,11 @@ class ApiService {
|
|
|
475
461
|
uploadedAt: new Date().toISOString(),
|
|
476
462
|
};
|
|
477
463
|
}
|
|
478
|
-
const payload = await funnelSdkService.
|
|
464
|
+
const payload = await funnelSdkService.uploadPhotoFile({
|
|
479
465
|
userId,
|
|
480
466
|
fileName: input.file.name || 'capture.jpg',
|
|
481
|
-
|
|
482
|
-
|
|
467
|
+
contentType: input.file.type || undefined,
|
|
468
|
+
file: input.file,
|
|
483
469
|
source: input.source || 'upload',
|
|
484
470
|
});
|
|
485
471
|
const publicUrl = asString(payload.publicUrl);
|
|
@@ -77,6 +77,25 @@ export type FunnelSdkUploadPhotoInput = {
|
|
|
77
77
|
userId?: string | null;
|
|
78
78
|
runtimeConfig?: FunnelSdkRuntimeConfigOverrides;
|
|
79
79
|
};
|
|
80
|
+
export type FunnelSdkUploadPhotoFileInput = {
|
|
81
|
+
file: Blob;
|
|
82
|
+
fileName: string;
|
|
83
|
+
contentType?: string | null;
|
|
84
|
+
source?: 'camera' | 'upload' | string | null;
|
|
85
|
+
userId?: string | null;
|
|
86
|
+
runtimeConfig?: FunnelSdkRuntimeConfigOverrides;
|
|
87
|
+
};
|
|
88
|
+
export type FunnelSdkPreparedPhotoUpload = {
|
|
89
|
+
key: string;
|
|
90
|
+
publicUrl: string;
|
|
91
|
+
uploadUrl: string;
|
|
92
|
+
uploadHeaders: Record<string, string>;
|
|
93
|
+
contentType: string;
|
|
94
|
+
sizeBytes: number;
|
|
95
|
+
};
|
|
96
|
+
export type FunnelSdkUploadedPhoto = Omit<FunnelSdkPreparedPhotoUpload, 'uploadUrl' | 'uploadHeaders'> & {
|
|
97
|
+
uploadedAt: string;
|
|
98
|
+
};
|
|
80
99
|
export type FunnelSdkCreateHostedCheckoutSessionInput = {
|
|
81
100
|
planId: string;
|
|
82
101
|
offerSetId?: string | null;
|
|
@@ -263,6 +282,10 @@ declare class FunnelSdkService {
|
|
|
263
282
|
claimUserSubscription<ResponsePayload = FunnelSdkJsonObject>(input: FunnelSdkClaimUserSubscriptionInput): Promise<ResponsePayload>;
|
|
264
283
|
updateFunnelUser<ResponsePayload = FunnelSdkJsonObject>(input: FunnelSdkUpdateFunnelUserInput): Promise<ResponsePayload>;
|
|
265
284
|
uploadPhoto<ResponsePayload = FunnelSdkJsonObject>(input: FunnelSdkUploadPhotoInput): Promise<ResponsePayload>;
|
|
285
|
+
preparePhotoUpload(input: Omit<FunnelSdkUploadPhotoFileInput, 'file'> & {
|
|
286
|
+
sizeBytes: number;
|
|
287
|
+
}): Promise<FunnelSdkPreparedPhotoUpload>;
|
|
288
|
+
uploadPhotoFile(input: FunnelSdkUploadPhotoFileInput): Promise<FunnelSdkUploadedPhoto>;
|
|
266
289
|
listPaymentPlans(input?: {
|
|
267
290
|
environment?: FunnelSdkRuntimeMode;
|
|
268
291
|
offerSetId?: string | null;
|
|
@@ -186,6 +186,48 @@ class FunnelSdkService {
|
|
|
186
186
|
errorMessage: 'Failed to upload photo',
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
|
+
async preparePhotoUpload(input) {
|
|
190
|
+
const { funnelId } = resolveRuntimeConfig(input.runtimeConfig);
|
|
191
|
+
return this.postJson('/sdk/public/uploads/photos/prepare', {
|
|
192
|
+
runtimeConfig: input.runtimeConfig,
|
|
193
|
+
body: {
|
|
194
|
+
funnelId,
|
|
195
|
+
userId: input.userId,
|
|
196
|
+
fileName: input.fileName,
|
|
197
|
+
contentType: input.contentType,
|
|
198
|
+
sizeBytes: input.sizeBytes,
|
|
199
|
+
source: input.source,
|
|
200
|
+
},
|
|
201
|
+
includeRuntimeFields: false,
|
|
202
|
+
includePublishableKey: false,
|
|
203
|
+
errorMessage: 'Failed to prepare photo upload',
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
async uploadPhotoFile(input) {
|
|
207
|
+
const prepared = await this.preparePhotoUpload({
|
|
208
|
+
fileName: input.fileName,
|
|
209
|
+
contentType: input.contentType,
|
|
210
|
+
sizeBytes: input.file.size,
|
|
211
|
+
source: input.source,
|
|
212
|
+
userId: input.userId,
|
|
213
|
+
runtimeConfig: input.runtimeConfig,
|
|
214
|
+
});
|
|
215
|
+
const response = await fetch(prepared.uploadUrl, {
|
|
216
|
+
method: 'PUT',
|
|
217
|
+
headers: prepared.uploadHeaders,
|
|
218
|
+
body: input.file,
|
|
219
|
+
});
|
|
220
|
+
if (!response.ok) {
|
|
221
|
+
throw new Error(`Failed to upload photo (${response.status})`);
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
key: prepared.key,
|
|
225
|
+
publicUrl: prepared.publicUrl,
|
|
226
|
+
contentType: prepared.contentType,
|
|
227
|
+
sizeBytes: prepared.sizeBytes,
|
|
228
|
+
uploadedAt: new Date().toISOString(),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
189
231
|
async listPaymentPlans(input = {}) {
|
|
190
232
|
const { funnelId } = resolveRuntimeConfig(input.runtimeConfig);
|
|
191
233
|
return this.getJson('/sdk/public/payments/plans', {
|