@funnelsgrove/runtime 0.11.3 → 0.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -32,6 +32,7 @@ export * from './runtime/step-asset-preloader.js';
32
32
  export * from './runtime/url-user-attributes.js';
33
33
  export * from './runtime/use-url-user-attributes-sync.js';
34
34
  export * from './services/api.service.js';
35
+ export * from './services/checkout-identity.service.js';
35
36
  export * from './services/funnel-sdk.service.js';
36
37
  export * from './services/funnel-state.service.js';
37
38
  export * from './services/logger.js';
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ export * from './runtime/url-user-attributes.js';
34
34
  export * from './runtime/use-url-user-attributes-sync.js';
35
35
  // Browser-safe services.
36
36
  export * from './services/api.service.js';
37
+ export * from './services/checkout-identity.service.js';
37
38
  export * from './services/funnel-sdk.service.js';
38
39
  export * from './services/funnel-state.service.js';
39
40
  export * from './services/logger.js';
@@ -0,0 +1,2 @@
1
+ export declare const retainCheckoutAccessToken: (checkoutSessionId: unknown, token: unknown) => void;
2
+ export declare const getCheckoutAccessToken: (checkoutSessionId: unknown) => string | null;
@@ -0,0 +1,19 @@
1
+ const checkoutAccessTokens = new Map();
2
+ const normalized = (value) => (typeof value === 'string' ? value.trim() : '');
3
+ export const retainCheckoutAccessToken = (checkoutSessionId, token) => {
4
+ const sessionId = normalized(checkoutSessionId);
5
+ const accessToken = normalized(token);
6
+ if (!sessionId) {
7
+ return;
8
+ }
9
+ if (!accessToken || accessToken.length > 4096) {
10
+ checkoutAccessTokens.delete(sessionId);
11
+ return;
12
+ }
13
+ checkoutAccessTokens.set(sessionId, accessToken);
14
+ };
15
+ export const getCheckoutAccessToken = (checkoutSessionId) => {
16
+ var _a;
17
+ const sessionId = normalized(checkoutSessionId);
18
+ return sessionId ? (_a = checkoutAccessTokens.get(sessionId)) !== null && _a !== void 0 ? _a : null : null;
19
+ };
@@ -0,0 +1,4 @@
1
+ export declare const retainCheckoutIdentityToken: (userId: string, token: unknown) => void;
2
+ export declare const getCheckoutIdentityToken: (userId: string | null | undefined) => string | null;
3
+ export type CheckoutIdentityStatus = 'pending' | 'legacy-ready' | 'proof-ready';
4
+ export declare const getCheckoutIdentityStatus: (userId: string | null | undefined) => CheckoutIdentityStatus;
@@ -0,0 +1,28 @@
1
+ const checkoutIdentityTokens = new Map();
2
+ const checkoutIdentityReadyUsers = new Set();
3
+ const normalizeIdentityValue = (value) => (typeof value === 'string' ? value.trim() : '');
4
+ export const retainCheckoutIdentityToken = (userId, token) => {
5
+ const normalizedUserId = normalizeIdentityValue(userId);
6
+ const normalizedToken = normalizeIdentityValue(token);
7
+ if (!normalizedUserId) {
8
+ return;
9
+ }
10
+ checkoutIdentityReadyUsers.add(normalizedUserId);
11
+ if (!normalizedToken || normalizedToken.length > 4096) {
12
+ checkoutIdentityTokens.delete(normalizedUserId);
13
+ return;
14
+ }
15
+ checkoutIdentityTokens.set(normalizedUserId, normalizedToken);
16
+ };
17
+ export const getCheckoutIdentityToken = (userId) => {
18
+ var _a;
19
+ const normalizedUserId = normalizeIdentityValue(userId);
20
+ return normalizedUserId ? (_a = checkoutIdentityTokens.get(normalizedUserId)) !== null && _a !== void 0 ? _a : null : null;
21
+ };
22
+ export const getCheckoutIdentityStatus = (userId) => {
23
+ const normalizedUserId = normalizeIdentityValue(userId);
24
+ if (!normalizedUserId || !checkoutIdentityReadyUsers.has(normalizedUserId)) {
25
+ return 'pending';
26
+ }
27
+ return checkoutIdentityTokens.has(normalizedUserId) ? 'proof-ready' : 'legacy-ready';
28
+ };
@@ -2,13 +2,16 @@ import { toV1OneTimeCheckoutRequest } from './requests.js';
2
2
  import { postJson } from '../shared/http.js';
3
3
  import { resolveRuntimeConfig } from '../shared/runtimeConfig.js';
4
4
  import { toV2CheckoutSessionRequest } from './selection.js';
5
+ import { retainCheckoutAccessToken } from '../../checkout-access.service.js';
5
6
  export const createOneTimeCheckout = async (input) => {
6
7
  if (resolveRuntimeConfig(input.runtimeConfig).paymentsApiVersion === 'v2') {
7
- return postJson('/sdk/public/v2/payments/checkout-sessions', {
8
+ const result = await postJson('/sdk/public/v2/payments/checkout-sessions', {
8
9
  runtimeConfig: input.runtimeConfig,
9
10
  body: toV2CheckoutSessionRequest(input, 'one_time'),
10
11
  errorMessage: 'Unable to create one-time checkout',
11
12
  });
13
+ retainCheckoutAccessToken(result.checkoutSessionId, result.checkoutAccessToken);
14
+ return result;
12
15
  }
13
16
  return postJson('/sdk/public/payments/one-time-checkout', {
14
17
  runtimeConfig: input.runtimeConfig,
@@ -2,14 +2,17 @@ import { toV1SubscriptionCheckoutRequest } from './requests.js';
2
2
  import { postJson } from '../shared/http.js';
3
3
  import { resolveRuntimeConfig } from '../shared/runtimeConfig.js';
4
4
  import { toV2CheckoutSessionRequest } from './selection.js';
5
+ import { retainCheckoutAccessToken } from '../../checkout-access.service.js';
5
6
  export const createSubscriptionCheckout = async (input) => {
6
7
  const { paymentsApiVersion } = resolveRuntimeConfig(input.runtimeConfig);
7
8
  if (paymentsApiVersion === 'v2') {
8
- return postJson('/sdk/public/v2/payments/checkout-sessions', {
9
+ const result = await postJson('/sdk/public/v2/payments/checkout-sessions', {
9
10
  runtimeConfig: input.runtimeConfig,
10
11
  body: toV2CheckoutSessionRequest(input, 'subscription'),
11
12
  errorMessage: 'Unable to create subscription checkout',
12
13
  });
14
+ retainCheckoutAccessToken(result.checkoutSessionId, result.checkoutAccessToken);
15
+ return result;
13
16
  }
14
17
  return postJson('/sdk/public/payments/subscriptions', {
15
18
  runtimeConfig: input.runtimeConfig,
@@ -57,6 +57,7 @@ export declare const toV1OneTimeCheckoutRequest: (input: FunnelSdkCreateOneTimeC
57
57
  environment: import("../shared/types.js").FunnelSdkRuntimeMode | undefined;
58
58
  };
59
59
  export declare const toV2SubscriptionPlanUpdateRequest: (input: FunnelSdkUpdateSubscriptionCheckoutPlanInput) => {
60
+ checkoutAccessToken: string | null;
60
61
  couponId: string | null | undefined;
61
62
  analyticsMetadata: Record<string, unknown> | null | undefined;
62
63
  environment: import("../shared/types.js").FunnelSdkRuntimeMode | undefined;
@@ -1,4 +1,5 @@
1
1
  import { toV2CheckoutSelection } from './selection.js';
2
+ import { getCheckoutAccessToken } from '../../checkout-access.service.js';
2
3
  export const toV1HostedCheckoutRequest = (input) => ({
3
4
  offerSetId: input.offerSetId,
4
5
  offerSetKey: input.offerSetKey,
@@ -56,7 +57,7 @@ export const toV1OneTimeCheckoutRequest = (input) => ({
56
57
  user_id: input.userId,
57
58
  environment: input.environment,
58
59
  });
59
- export const toV2SubscriptionPlanUpdateRequest = (input) => (Object.assign(Object.assign({}, toV2CheckoutSelection(input)), { couponId: input.couponId, analyticsMetadata: input.analyticsMetadata, environment: input.environment }));
60
+ export const toV2SubscriptionPlanUpdateRequest = (input) => (Object.assign(Object.assign({}, toV2CheckoutSelection(input)), { checkoutAccessToken: getCheckoutAccessToken(input.checkoutSessionId), couponId: input.couponId, analyticsMetadata: input.analyticsMetadata, environment: input.environment }));
60
61
  export const toV1SubscriptionPlanUpdateRequest = (input) => ({
61
62
  checkoutSessionId: input.checkoutSessionId,
62
63
  offerSetId: input.offerSetId,
@@ -22,6 +22,7 @@ export declare const toV2CheckoutSessionRequest: (input: PublishedStripeSelectio
22
22
  returnUrl: string;
23
23
  userId?: string | null;
24
24
  anonymousUserId?: string | null;
25
+ checkoutIdentityToken?: string | null;
25
26
  idempotencyKey?: string | null;
26
27
  environment?: "test" | "live";
27
28
  }, checkoutType: "subscription" | "one_time") => {
@@ -33,6 +34,7 @@ export declare const toV2CheckoutSessionRequest: (input: PublishedStripeSelectio
33
34
  returnUrl: string;
34
35
  userId: string | null | undefined;
35
36
  anonymousUserId: string | null | undefined;
37
+ checkoutIdentityToken: string | null | undefined;
36
38
  idempotencyKey: string | null | undefined;
37
39
  environment: "test" | "live" | undefined;
38
40
  offerSetId: string | undefined;
@@ -14,4 +14,4 @@ export const toV2CheckoutSelection = (input) => {
14
14
  // Retained for older API versions, but not required to identify an offer.
15
15
  runtimeConfigRevisionId: ((_f = input.runtimeConfigRevisionId) === null || _f === void 0 ? void 0 : _f.trim()) || undefined }, selection);
16
16
  };
17
- export const toV2CheckoutSessionRequest = (input, checkoutType) => (Object.assign(Object.assign({}, toV2CheckoutSelection(input)), { checkoutType, uiMode: 'custom', couponId: input.couponId, analyticsMetadata: input.analyticsMetadata, customerEmail: input.customerEmail, returnUrl: input.returnUrl, userId: input.userId, anonymousUserId: input.anonymousUserId, idempotencyKey: input.idempotencyKey, environment: input.environment }));
17
+ export const toV2CheckoutSessionRequest = (input, checkoutType) => (Object.assign(Object.assign({}, toV2CheckoutSelection(input)), { checkoutType, uiMode: 'custom', couponId: input.couponId, analyticsMetadata: input.analyticsMetadata, customerEmail: input.customerEmail, returnUrl: input.returnUrl, userId: input.userId, anonymousUserId: input.anonymousUserId, checkoutIdentityToken: input.checkoutIdentityToken, idempotencyKey: input.idempotencyKey, environment: input.environment }));
@@ -47,6 +47,7 @@ export type FunnelSdkCreateSubscriptionCheckoutInput = {
47
47
  paymentProfileId?: string | null;
48
48
  runtimeConfigRevisionId?: string | null;
49
49
  anonymousUserId?: string | null;
50
+ checkoutIdentityToken?: string | null;
50
51
  idempotencyKey?: string | null;
51
52
  runtimeConfig?: FunnelSdkRuntimeConfigOverrides;
52
53
  title?: string | null;
@@ -55,6 +56,7 @@ export type FunnelSdkCreateSubscriptionCheckoutInput = {
55
56
  export type FunnelSdkCreateSubscriptionCheckoutResponse = {
56
57
  clientSecret: string;
57
58
  checkoutSessionId?: string;
59
+ checkoutAccessToken?: string;
58
60
  subscriptionId?: string;
59
61
  stripePublishableKey?: string;
60
62
  environment?: FunnelSdkRuntimeMode;
@@ -66,6 +68,7 @@ export type FunnelSdkCreateOneTimeCheckoutInput = {
66
68
  provider?: 'stripe' | null;
67
69
  runtimeConfigRevisionId?: string | null;
68
70
  anonymousUserId?: string | null;
71
+ checkoutIdentityToken?: string | null;
69
72
  idempotencyKey?: string | null;
70
73
  offerSetId?: string | null;
71
74
  offerSetKey?: string | null;
@@ -84,6 +87,7 @@ export type FunnelSdkCreateOneTimeCheckoutInput = {
84
87
  export type FunnelSdkCreateOneTimeCheckoutResponse = {
85
88
  clientSecret: string;
86
89
  checkoutSessionId?: string;
90
+ checkoutAccessToken?: string;
87
91
  stripePublishableKey?: string;
88
92
  environment?: FunnelSdkRuntimeMode;
89
93
  };
@@ -1,12 +1,19 @@
1
1
  import { toV1SubscriptionCheckoutStatusRequest } from './requests.js';
2
2
  import { postJson, getJson } from '../shared/http.js';
3
3
  import { resolveRuntimeConfig } from '../shared/runtimeConfig.js';
4
+ import { getCheckoutAccessToken } from '../../checkout-access.service.js';
4
5
  export const verifySubscriptionCheckout = async (input) => {
5
6
  const { funnelId, paymentsApiVersion } = resolveRuntimeConfig(input.runtimeConfig);
6
7
  if (paymentsApiVersion === 'v2') {
8
+ const checkoutAccessToken = getCheckoutAccessToken(input.checkoutSessionId);
7
9
  return getJson(`/sdk/public/v2/payments/checkout-sessions/${encodeURIComponent(input.checkoutSessionId)}`, {
8
10
  runtimeConfig: input.runtimeConfig,
9
11
  searchParams: { funnelId },
12
+ headers: Object.assign({}, (checkoutAccessToken
13
+ ? {
14
+ 'x-funnelsgrove-checkout-access-token': checkoutAccessToken,
15
+ }
16
+ : {})),
10
17
  errorMessage: 'Unable to verify subscription checkout',
11
18
  });
12
19
  }
@@ -9,6 +9,7 @@ type JsonWriteInput = {
9
9
  export declare const getJson: <ResponsePayload>(path: string, input: {
10
10
  runtimeConfig?: FunnelSdkRuntimeConfigOverrides;
11
11
  searchParams?: Record<string, string | null | undefined>;
12
+ headers?: Record<string, string>;
12
13
  errorMessage: string;
13
14
  }) => Promise<ResponsePayload>;
14
15
  export declare const postJson: <ResponsePayload>(path: string, input: JsonWriteInput) => Promise<ResponsePayload>;
@@ -38,7 +38,7 @@ export const getJson = async (path, input) => {
38
38
  }
39
39
  const response = await fetch(url.toString(), {
40
40
  method: 'GET',
41
- headers: buildHeaders(input.runtimeConfig),
41
+ headers: buildHeaders(input.runtimeConfig, input.headers),
42
42
  });
43
43
  return readJsonResponse(response, input.errorMessage);
44
44
  };
@@ -7,6 +7,7 @@ import { resolveBootstrapUserId } from './currentUser.js';
7
7
  import { digestBootstrapRequest, getOrCreateBootstrapIdempotencyRecord, clearBootstrapIdempotencyRecord } from './idempotency.js';
8
8
  import { toBootstrapProfile, toBootstrapRequest, toBootstrapFingerprint } from './requests.js';
9
9
  import { resolveBootstrapResponseUserId, toBootstrapUser } from './responses.js';
10
+ import { retainCheckoutIdentityToken } from '../../checkout-identity.service.js';
10
11
  export async function bootstrapSession(input) {
11
12
  const urlUserAttributes = resolveUrlUserAttributes();
12
13
  const profile = toBootstrapProfile(input);
@@ -19,5 +20,6 @@ export async function bootstrapSession(input) {
19
20
  const payload = await funnelSdkService.bootstrapUser(Object.assign(Object.assign({}, request), { idempotencyKey: record.key }));
20
21
  clearBootstrapIdempotencyRecord(record);
21
22
  const persistedUserId = persistUserId(resolveBootstrapResponseUserId(payload, userId), FUNNEL_ID) || userId;
23
+ retainCheckoutIdentityToken(persistedUserId, payload.checkoutIdentityToken);
22
24
  return toBootstrapUser(persistedUserId, profile, payload);
23
25
  }
@@ -6,6 +6,7 @@ export type BootstrapProfile = {
6
6
  attribution?: FunnelUserAttribution;
7
7
  };
8
8
  export type SessionBootstrapResponse = {
9
+ checkoutIdentityToken?: unknown;
9
10
  user?: SdkApiUser;
10
11
  user_id?: unknown;
11
12
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/runtime",
3
- "version": "0.11.3",
3
+ "version": "0.11.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/The-Solid-Grove/funnelsgrove.git",