@proxy-checkout/server-js 0.0.7 → 0.0.8-prx-109.81.1

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/README.md CHANGED
@@ -35,7 +35,11 @@ const proxy = createProxyCheckoutServerClient({
35
35
 
36
36
  const handoff = await proxy.sessions.createHandoff({
37
37
  amountMinor: 5000,
38
+ // Stable, non-PII entitlement owner reference. For pre-account flows,
39
+ // use a pending entitlement id instead of an email address.
38
40
  buyerReference: "buyer_123",
41
+ // Optional beneficiary contact for the person receiving access.
42
+ beneficiaryContact: { email: "recipient@example.com" },
39
43
  currency: "usd",
40
44
  cartSnapshot: {
41
45
  items: [{ product_id: "prod_123", quantity: 1 }],
@@ -70,6 +74,29 @@ For delegated checkout, prefer the high-level flow:
70
74
 
71
75
  Use `payerHandoff`, `payerOpened`, raw event construction, or manual provisioning acknowledgements only for custom integrations that cannot use the default helpers.
72
76
 
77
+ `proxy.webhooks.handle(...)` automatically marks successful initial provisioning as provisioned after `onResolved` completes. Return a fulfillment reference and/or metadata from `onResolved` when you want that acknowledgement to record the merchant-side access row:
78
+
79
+ ```ts
80
+ await proxy.webhooks.handle(request, {
81
+ secret: process.env.PROXY_WEBHOOK_SIGNING_SECRET!,
82
+ async onResolved(resolved) {
83
+ if (resolved.kind !== "initial_provision") {
84
+ return;
85
+ }
86
+
87
+ const entitlement = await grantOrMarkPending(resolved.session);
88
+ return {
89
+ fulfillmentReference: entitlement.id,
90
+ metadata: { claim_status: entitlement.profileId ? "claimed" : "pending_account_claim" },
91
+ };
92
+ },
93
+ });
94
+ ```
95
+
96
+ `fulfillmentReference` is copied to Proxy's `proxy_session.provisioned` session/audit event. Use it for support and reconciliation, for example "Proxy session `psess_...` was fulfilled by Fiveable pending entitlement `pent_...`." It does not grant access and is not used for future claim validation.
97
+
98
+ For pre-account purchases, create a durable pending entitlement before `sessions.createHandoff(...)`, use that pending entitlement id as `buyerReference`, pass the future recipient's contact as `beneficiaryContact`, and claim the entitlement after signup/login with your own high-entropy claim token. Store only the token hash on the pending entitlement; use `sessionStorage` or an emailed merchant-owned claim link to carry the plaintext token to the authenticated claim endpoint. Treat `proxy_session_id` as public correlation, not as a claim secret.
99
+
73
100
  Verify and parse outbound webhooks with the exact raw request body:
74
101
 
75
102
  ```ts
@@ -9,5 +9,5 @@ export { type MerchantProxySubscription, ProxySubscriptionsResource, type ProxyS
9
9
  export type { JsonObject, JsonPrimitive, JsonValue, ProxyCheckoutFetch, ProxyCheckoutServerClientOptions, ProxyCheckoutServerRequestOptions, } from "./types.js";
10
10
  export { proxyCheckoutServerSdkName, proxyCheckoutServerSdkUserAgent, proxyCheckoutServerSdkVersion, } from "./version.js";
11
11
  export { isProxyPaymentAttemptEvent, isProxySessionEvent, isProxySubscriptionEvent, PROXY_WEBHOOK_EVENT_TYPES, type ProxyWebhookEventType, } from "./webhook-events.js";
12
- export { PROXY_WEBHOOK_RETRY_AFTER_SECONDS, type ProxyWebhookClaimResult, type ProxyWebhookHandlerOptions, type ProxyWebhookOutcome, type ProxyWebhookPayloadInput, type ProxyWebhookProcessRecord, type ProxyWebhookProcessResult, type ProxyWebhookProvisioningFailure, type ProxyWebhookRequestInput, type ProxyWebhookStore, ProxyWebhooksResource, } from "./webhook-handler.js";
12
+ export { PROXY_WEBHOOK_RETRY_AFTER_SECONDS, type ProxyWebhookClaimResult, type ProxyWebhookHandlerOptions, type ProxyWebhookOutcome, type ProxyWebhookPayloadInput, type ProxyWebhookProcessRecord, type ProxyWebhookProcessResult, type ProxyWebhookProvisioningFailure, type ProxyWebhookProvisioningSuccess, type ProxyWebhookProvisioningSuccessResult, type ProxyWebhookRequestInput, type ProxyWebhookStore, ProxyWebhooksResource, } from "./webhook-handler.js";
13
13
  export { type ConstructProxyWebhookEventInput, type CreateWebhookEndpointInput, constructProxyWebhookEvent, PROXY_SIGNATURE_HEADER, ProxyWebhookEndpointsResource, type ProxyWebhookEvent, ProxyWebhookSignatureVerificationError, proxyCheckoutWebhookEndpointEndpoints, type RotateWebhookEndpointSecretInput, type UpdateWebhookEndpointInput, type VerifyProxyWebhookSignatureInput, verifyProxyWebhookSignature, type WebhookEndpoint, type WebhookEndpointSecretResult, } from "./webhooks.js";
@@ -9,5 +9,5 @@ export { type MerchantProxySubscription, ProxySubscriptionsResource, type ProxyS
9
9
  export type { JsonObject, JsonPrimitive, JsonValue, ProxyCheckoutFetch, ProxyCheckoutServerClientOptions, ProxyCheckoutServerRequestOptions, } from "./types.js";
10
10
  export { proxyCheckoutServerSdkName, proxyCheckoutServerSdkUserAgent, proxyCheckoutServerSdkVersion, } from "./version.js";
11
11
  export { isProxyPaymentAttemptEvent, isProxySessionEvent, isProxySubscriptionEvent, PROXY_WEBHOOK_EVENT_TYPES, type ProxyWebhookEventType, } from "./webhook-events.js";
12
- export { PROXY_WEBHOOK_RETRY_AFTER_SECONDS, type ProxyWebhookClaimResult, type ProxyWebhookHandlerOptions, type ProxyWebhookOutcome, type ProxyWebhookPayloadInput, type ProxyWebhookProcessRecord, type ProxyWebhookProcessResult, type ProxyWebhookProvisioningFailure, type ProxyWebhookRequestInput, type ProxyWebhookStore, ProxyWebhooksResource, } from "./webhook-handler.js";
12
+ export { PROXY_WEBHOOK_RETRY_AFTER_SECONDS, type ProxyWebhookClaimResult, type ProxyWebhookHandlerOptions, type ProxyWebhookOutcome, type ProxyWebhookPayloadInput, type ProxyWebhookProcessRecord, type ProxyWebhookProcessResult, type ProxyWebhookProvisioningFailure, type ProxyWebhookProvisioningSuccess, type ProxyWebhookProvisioningSuccessResult, type ProxyWebhookRequestInput, type ProxyWebhookStore, ProxyWebhooksResource, } from "./webhook-handler.js";
13
13
  export { type ConstructProxyWebhookEventInput, type CreateWebhookEndpointInput, constructProxyWebhookEvent, PROXY_SIGNATURE_HEADER, ProxyWebhookEndpointsResource, type ProxyWebhookEvent, ProxyWebhookSignatureVerificationError, proxyCheckoutWebhookEndpointEndpoints, type RotateWebhookEndpointSecretInput, type UpdateWebhookEndpointInput, type VerifyProxyWebhookSignatureInput, verifyProxyWebhookSignature, type WebhookEndpoint, type WebhookEndpointSecretResult, } from "./webhooks.js";
@@ -6,6 +6,10 @@ export interface CreateProxySessionOptions extends ProxyCheckoutServerRequestOpt
6
6
  }
7
7
  export interface CreateProxySessionInput extends CreateProxySessionOptions {
8
8
  readonly amountMinor: number;
9
+ readonly beneficiaryContact?: {
10
+ readonly email?: string;
11
+ readonly phone?: string;
12
+ };
9
13
  readonly buyerReference: string;
10
14
  readonly cartSnapshot: JsonObject;
11
15
  readonly currency: string;
@@ -34,6 +38,10 @@ export interface ProxySessionHandoff extends ProxySession {
34
38
  }
35
39
  export interface MerchantProxySession {
36
40
  readonly amountMinor: number;
41
+ readonly beneficiaryContact: {
42
+ readonly email: string | null;
43
+ readonly phone: string | null;
44
+ } | null;
37
45
  readonly buyerReference: string;
38
46
  readonly cartSnapshot: JsonObject;
39
47
  readonly cartVersion: number;
@@ -87,7 +95,14 @@ export interface ProxySessionProviderBinding {
87
95
  readonly updatedAt: string;
88
96
  }
89
97
  export interface MarkProxySessionProvisionedInput extends ProxyCheckoutServerRequestOptions {
98
+ /**
99
+ * Optional merchant-side fulfillment row id to store on Proxy's provisioned
100
+ * session/audit event, for example a pending entitlement id or durable role
101
+ * id. This is for support and reconciliation only; do not put claim tokens or
102
+ * secrets here.
103
+ */
90
104
  readonly fulfillmentReference?: string;
105
+ /** Optional non-secret metadata to store with the provisioned acknowledgement. */
91
106
  readonly metadata?: JsonObject;
92
107
  }
93
108
  export interface MarkProxySessionProvisioningFailedInput extends ProxyCheckoutServerRequestOptions {
@@ -6,6 +6,10 @@ export interface CreateProxySessionOptions extends ProxyCheckoutServerRequestOpt
6
6
  }
7
7
  export interface CreateProxySessionInput extends CreateProxySessionOptions {
8
8
  readonly amountMinor: number;
9
+ readonly beneficiaryContact?: {
10
+ readonly email?: string;
11
+ readonly phone?: string;
12
+ };
9
13
  readonly buyerReference: string;
10
14
  readonly cartSnapshot: JsonObject;
11
15
  readonly currency: string;
@@ -34,6 +38,10 @@ export interface ProxySessionHandoff extends ProxySession {
34
38
  }
35
39
  export interface MerchantProxySession {
36
40
  readonly amountMinor: number;
41
+ readonly beneficiaryContact: {
42
+ readonly email: string | null;
43
+ readonly phone: string | null;
44
+ } | null;
37
45
  readonly buyerReference: string;
38
46
  readonly cartSnapshot: JsonObject;
39
47
  readonly cartVersion: number;
@@ -87,7 +95,14 @@ export interface ProxySessionProviderBinding {
87
95
  readonly updatedAt: string;
88
96
  }
89
97
  export interface MarkProxySessionProvisionedInput extends ProxyCheckoutServerRequestOptions {
98
+ /**
99
+ * Optional merchant-side fulfillment row id to store on Proxy's provisioned
100
+ * session/audit event, for example a pending entitlement id or durable role
101
+ * id. This is for support and reconciliation only; do not put claim tokens or
102
+ * secrets here.
103
+ */
90
104
  readonly fulfillmentReference?: string;
105
+ /** Optional non-secret metadata to store with the provisioned acknowledgement. */
91
106
  readonly metadata?: JsonObject;
92
107
  }
93
108
  export interface MarkProxySessionProvisioningFailedInput extends ProxyCheckoutServerRequestOptions {
@@ -196,6 +196,12 @@ function toCreateProxySessionBody(input) {
196
196
  cart_snapshot: input.cartSnapshot,
197
197
  currency: input.currency,
198
198
  };
199
+ if (input.beneficiaryContact !== undefined) {
200
+ body.beneficiary_contact = removeUndefinedValues({
201
+ email: input.beneficiaryContact.email,
202
+ phone: input.beneficiaryContact.phone,
203
+ });
204
+ }
199
205
  if (input.expiresAt !== undefined) {
200
206
  body.expires_at =
201
207
  input.expiresAt instanceof Date ? input.expiresAt.toISOString() : input.expiresAt;
@@ -256,6 +262,7 @@ function toMerchantProxySession(response) {
256
262
  const body = (0, response_validators_js_1.requireJsonObject)(response, "sessions.retrieve");
257
263
  return {
258
264
  amountMinor: (0, response_validators_js_1.requireInteger)(body.amount_minor, "sessions.retrieve.amountMinor"),
265
+ beneficiaryContact: requireNullableContact(body.beneficiary_contact, "sessions.retrieve.beneficiaryContact"),
259
266
  buyerReference: (0, response_validators_js_1.requireString)(body.buyer_reference, "sessions.retrieve.buyerReference"),
260
267
  cartSnapshot: (0, response_validators_js_1.requireJsonObject)(body.cart_snapshot, "sessions.retrieve.cartSnapshot"),
261
268
  cartVersion: (0, response_validators_js_1.requireInteger)(body.cart_version, "sessions.retrieve.cartVersion"),
@@ -266,7 +273,7 @@ function toMerchantProxySession(response) {
266
273
  idempotencyKey: (0, response_validators_js_1.requireNullableString)(body.idempotency_key, "sessions.retrieve.idempotencyKey"),
267
274
  integrationMode: (0, response_validators_js_1.requireString)(body.integration_mode, "sessions.retrieve.integrationMode"),
268
275
  metadata: (0, response_validators_js_1.requireJsonObject)(body.metadata, "sessions.retrieve.metadata"),
269
- payerContact: requireNullablePayerContact(body.payer_contact),
276
+ payerContact: requireNullableContact(body.payer_contact, "sessions.retrieve.payerContact"),
270
277
  payerDestinationUrl: (0, response_validators_js_1.requireNullableString)(body.payer_destination_url, "sessions.retrieve.payerDestinationUrl"),
271
278
  providerCheckoutSessionId: (0, response_validators_js_1.requireNullableString)(body.provider_checkout_session_id, "sessions.retrieve.providerCheckoutSessionId"),
272
279
  providerCheckoutSessionPsp: (0, response_validators_js_1.requireNullableString)(body.provider_checkout_session_psp, "sessions.retrieve.providerCheckoutSessionPsp"),
@@ -282,6 +289,7 @@ function toPayerOpenedResult(response) {
282
289
  }
283
290
  return {
284
291
  amountMinor: (0, response_validators_js_1.requireInteger)(body.amount_minor, "sessions.payerOpened.amountMinor"),
292
+ beneficiaryContact: requireNullableContact(body.beneficiary_contact, "sessions.payerOpened.beneficiaryContact"),
285
293
  buyerReference: (0, response_validators_js_1.requireString)(body.buyer_reference, "sessions.payerOpened.buyerReference"),
286
294
  cartSnapshot: (0, response_validators_js_1.requireJsonObject)(body.cart_snapshot, "sessions.payerOpened.cartSnapshot"),
287
295
  cartVersion: (0, response_validators_js_1.requireInteger)(body.cart_version, "sessions.payerOpened.cartVersion"),
@@ -292,7 +300,7 @@ function toPayerOpenedResult(response) {
292
300
  idempotencyKey: (0, response_validators_js_1.requireNullableString)(body.idempotency_key, "sessions.payerOpened.idempotencyKey"),
293
301
  integrationMode: (0, response_validators_js_1.requireString)(body.integration_mode, "sessions.payerOpened.integrationMode"),
294
302
  metadata: (0, response_validators_js_1.requireJsonObject)(body.metadata, "sessions.payerOpened.metadata"),
295
- payerContact: requireNullablePayerContact(body.payer_contact, "sessions.payerOpened"),
303
+ payerContact: requireNullableContact(body.payer_contact, "sessions.payerOpened.payerContact"),
296
304
  payerDestinationUrl: (0, response_validators_js_1.requireNullableString)(body.payer_destination_url, "sessions.payerOpened.payerDestinationUrl"),
297
305
  providerCheckoutSessionId: (0, response_validators_js_1.requireNullableString)(body.provider_checkout_session_id, "sessions.payerOpened.providerCheckoutSessionId"),
298
306
  providerCheckoutSessionPsp: (0, response_validators_js_1.requireNullableString)(body.provider_checkout_session_psp, "sessions.payerOpened.providerCheckoutSessionPsp"),
@@ -300,14 +308,14 @@ function toPayerOpenedResult(response) {
300
308
  updatedAt: (0, response_validators_js_1.requireString)(body.updated_at, "sessions.payerOpened.updatedAt"),
301
309
  };
302
310
  }
303
- function requireNullablePayerContact(value, operation = "sessions.retrieve") {
304
- if (value === null) {
311
+ function requireNullableContact(value, field) {
312
+ if (value === null || value === undefined) {
305
313
  return null;
306
314
  }
307
- const contact = (0, response_validators_js_1.requireJsonObject)(value, `${operation}.payerContact`);
315
+ const contact = (0, response_validators_js_1.requireJsonObject)(value, field);
308
316
  return {
309
- email: (0, response_validators_js_1.requireNullableString)(contact.email, `${operation}.payerContact.email`),
310
- phone: (0, response_validators_js_1.requireNullableString)(contact.phone, `${operation}.payerContact.phone`),
317
+ email: (0, response_validators_js_1.requireNullableString)(contact.email, `${field}.email`),
318
+ phone: (0, response_validators_js_1.requireNullableString)(contact.phone, `${field}.phone`),
311
319
  };
312
320
  }
313
321
  function requirePayerHandoffStatus(value) {
@@ -1,3 +1,3 @@
1
1
  export declare const proxyCheckoutServerSdkName = "@proxy-checkout/server-js";
2
- export declare const proxyCheckoutServerSdkVersion = "0.0.7";
3
- export declare const proxyCheckoutServerSdkUserAgent = "@proxy-checkout/server-js/0.0.7";
2
+ export declare const proxyCheckoutServerSdkVersion = "0.0.8-prx-109.81.1";
3
+ export declare const proxyCheckoutServerSdkUserAgent = "@proxy-checkout/server-js/0.0.8-prx-109.81.1";
@@ -1,3 +1,3 @@
1
1
  export declare const proxyCheckoutServerSdkName = "@proxy-checkout/server-js";
2
- export declare const proxyCheckoutServerSdkVersion = "0.0.7";
3
- export declare const proxyCheckoutServerSdkUserAgent = "@proxy-checkout/server-js/0.0.7";
2
+ export declare const proxyCheckoutServerSdkVersion = "0.0.8-prx-109.81.1";
3
+ export declare const proxyCheckoutServerSdkUserAgent = "@proxy-checkout/server-js/0.0.8-prx-109.81.1";
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.proxyCheckoutServerSdkUserAgent = exports.proxyCheckoutServerSdkVersion = exports.proxyCheckoutServerSdkName = void 0;
4
4
  exports.proxyCheckoutServerSdkName = "@proxy-checkout/server-js";
5
- exports.proxyCheckoutServerSdkVersion = "0.0.7";
5
+ exports.proxyCheckoutServerSdkVersion = "0.0.8-prx-109.81.1";
6
6
  exports.proxyCheckoutServerSdkUserAgent = `${exports.proxyCheckoutServerSdkName}/${exports.proxyCheckoutServerSdkVersion}`;
@@ -40,6 +40,20 @@ export interface ProxyWebhookProvisioningFailure {
40
40
  readonly errorMessage: string;
41
41
  readonly metadata?: JsonObject;
42
42
  }
43
+ /**
44
+ * Optional data recorded when the handler acknowledges successful initial
45
+ * provisioning back to Proxy. This is audit/reconciliation data only. It does
46
+ * not grant access, does not participate in future claim-token validation, and
47
+ * should not contain secrets.
48
+ */
49
+ export interface ProxyWebhookProvisioningSuccess {
50
+ /** Stable merchant-side row id that fulfilled the session, such as a pending entitlement or role id. */
51
+ readonly fulfillmentReference?: string;
52
+ /** Small non-secret facts to store on Proxy's provisioned session/audit event. */
53
+ readonly metadata?: JsonObject;
54
+ }
55
+ type ProxyWebhookNoProvisioningMetadataResult = void;
56
+ export type ProxyWebhookProvisioningSuccessResult = ProxyWebhookProvisioningSuccess | null | undefined | ProxyWebhookNoProvisioningMetadataResult;
43
57
  export interface ProxyWebhookPayloadInput {
44
58
  readonly body: Buffer | string;
45
59
  readonly signature?: string | null;
@@ -56,8 +70,14 @@ export interface ProxyWebhookHandlerOptions {
56
70
  * failure payload only after the merchant knows retrying cannot grant access.
57
71
  */
58
72
  readonly classifyProvisioningFailure?: (error: unknown, resolved: ResolvedProxyEvent) => Promise<ProxyWebhookProvisioningFailure | null | undefined> | ProxyWebhookProvisioningFailure | null | undefined;
59
- /** Merchant entitlement callback, invoked once per claimed event after current-state resolution. */
60
- readonly onResolved: (resolved: ResolvedProxyEvent) => Promise<void> | void;
73
+ /**
74
+ * Merchant entitlement callback, invoked once per claimed event after
75
+ * current-state resolution. For initial provisioning, mutate the merchant's
76
+ * entitlement store first, then optionally return the merchant-side row id
77
+ * and non-secret metadata to record on Proxy's provisioned acknowledgement.
78
+ * Do not return claim tokens or other secrets here.
79
+ */
80
+ readonly onResolved: (resolved: ResolvedProxyEvent) => Promise<ProxyWebhookProvisioningSuccessResult> | ProxyWebhookProvisioningSuccessResult;
61
81
  /** Optional request id forwarded to the current-state retrieval calls. */
62
82
  readonly requestId?: string;
63
83
  /** Endpoint signing secret. */
@@ -102,3 +122,4 @@ export declare class ProxyWebhooksResource {
102
122
  private runResolvedHandler;
103
123
  private requireSessionsResource;
104
124
  }
125
+ export {};
@@ -40,6 +40,20 @@ export interface ProxyWebhookProvisioningFailure {
40
40
  readonly errorMessage: string;
41
41
  readonly metadata?: JsonObject;
42
42
  }
43
+ /**
44
+ * Optional data recorded when the handler acknowledges successful initial
45
+ * provisioning back to Proxy. This is audit/reconciliation data only. It does
46
+ * not grant access, does not participate in future claim-token validation, and
47
+ * should not contain secrets.
48
+ */
49
+ export interface ProxyWebhookProvisioningSuccess {
50
+ /** Stable merchant-side row id that fulfilled the session, such as a pending entitlement or role id. */
51
+ readonly fulfillmentReference?: string;
52
+ /** Small non-secret facts to store on Proxy's provisioned session/audit event. */
53
+ readonly metadata?: JsonObject;
54
+ }
55
+ type ProxyWebhookNoProvisioningMetadataResult = void;
56
+ export type ProxyWebhookProvisioningSuccessResult = ProxyWebhookProvisioningSuccess | null | undefined | ProxyWebhookNoProvisioningMetadataResult;
43
57
  export interface ProxyWebhookPayloadInput {
44
58
  readonly body: Buffer | string;
45
59
  readonly signature?: string | null;
@@ -56,8 +70,14 @@ export interface ProxyWebhookHandlerOptions {
56
70
  * failure payload only after the merchant knows retrying cannot grant access.
57
71
  */
58
72
  readonly classifyProvisioningFailure?: (error: unknown, resolved: ResolvedProxyEvent) => Promise<ProxyWebhookProvisioningFailure | null | undefined> | ProxyWebhookProvisioningFailure | null | undefined;
59
- /** Merchant entitlement callback, invoked once per claimed event after current-state resolution. */
60
- readonly onResolved: (resolved: ResolvedProxyEvent) => Promise<void> | void;
73
+ /**
74
+ * Merchant entitlement callback, invoked once per claimed event after
75
+ * current-state resolution. For initial provisioning, mutate the merchant's
76
+ * entitlement store first, then optionally return the merchant-side row id
77
+ * and non-secret metadata to record on Proxy's provisioned acknowledgement.
78
+ * Do not return claim tokens or other secrets here.
79
+ */
80
+ readonly onResolved: (resolved: ResolvedProxyEvent) => Promise<ProxyWebhookProvisioningSuccessResult> | ProxyWebhookProvisioningSuccessResult;
61
81
  /** Optional request id forwarded to the current-state retrieval calls. */
62
82
  readonly requestId?: string;
63
83
  /** Endpoint signing secret. */
@@ -102,3 +122,4 @@ export declare class ProxyWebhooksResource {
102
122
  private runResolvedHandler;
103
123
  private requireSessionsResource;
104
124
  }
125
+ export {};
@@ -64,9 +64,11 @@ class ProxyWebhooksResource {
64
64
  let resolved;
65
65
  try {
66
66
  resolved = await this.events.resolveCurrentState(event, { requestId: options.requestId });
67
- const provisioningFailed = await this.runResolvedHandler(resolved, options);
68
- if (!provisioningFailed && resolved.kind === "initial_provision") {
67
+ const provisioning = await this.runResolvedHandler(resolved, options);
68
+ if (!provisioning.failed && resolved.kind === "initial_provision") {
69
69
  await this.requireSessionsResource("mark provisioned").markProvisioned(resolved.session.id, {
70
+ fulfillmentReference: provisioning.success?.fulfillmentReference,
71
+ metadata: provisioning.success?.metadata,
70
72
  requestId: options.requestId,
71
73
  });
72
74
  }
@@ -130,8 +132,11 @@ class ProxyWebhooksResource {
130
132
  }
131
133
  async runResolvedHandler(resolved, options) {
132
134
  try {
133
- await options.onResolved(resolved);
134
- return false;
135
+ const success = await options.onResolved(resolved);
136
+ return {
137
+ failed: false,
138
+ success: normalizeProvisioningSuccess(success),
139
+ };
135
140
  }
136
141
  catch (error) {
137
142
  if (resolved.kind !== "initial_provision" || !options.classifyProvisioningFailure) {
@@ -147,7 +152,7 @@ class ProxyWebhooksResource {
147
152
  metadata: failure.metadata,
148
153
  requestId: options.requestId,
149
154
  });
150
- return true;
155
+ return { failed: true };
151
156
  }
152
157
  }
153
158
  requireSessionsResource(operation) {
@@ -160,6 +165,21 @@ class ProxyWebhooksResource {
160
165
  }
161
166
  }
162
167
  exports.ProxyWebhooksResource = ProxyWebhooksResource;
168
+ function normalizeProvisioningSuccess(value) {
169
+ if (value == null) {
170
+ return undefined;
171
+ }
172
+ const success = {};
173
+ if (value.fulfillmentReference !== undefined) {
174
+ success.fulfillmentReference = value.fulfillmentReference;
175
+ }
176
+ if (value.metadata !== undefined) {
177
+ success.metadata = value.metadata;
178
+ }
179
+ return success.fulfillmentReference === undefined && success.metadata === undefined
180
+ ? undefined
181
+ : success;
182
+ }
163
183
  function toWebhookResponse(result) {
164
184
  const headers = { "content-type": "application/json" };
165
185
  if (result.retryable) {
@@ -9,5 +9,5 @@ export { type MerchantProxySubscription, ProxySubscriptionsResource, type ProxyS
9
9
  export type { JsonObject, JsonPrimitive, JsonValue, ProxyCheckoutFetch, ProxyCheckoutServerClientOptions, ProxyCheckoutServerRequestOptions, } from "./types.js";
10
10
  export { proxyCheckoutServerSdkName, proxyCheckoutServerSdkUserAgent, proxyCheckoutServerSdkVersion, } from "./version.js";
11
11
  export { isProxyPaymentAttemptEvent, isProxySessionEvent, isProxySubscriptionEvent, PROXY_WEBHOOK_EVENT_TYPES, type ProxyWebhookEventType, } from "./webhook-events.js";
12
- export { PROXY_WEBHOOK_RETRY_AFTER_SECONDS, type ProxyWebhookClaimResult, type ProxyWebhookHandlerOptions, type ProxyWebhookOutcome, type ProxyWebhookPayloadInput, type ProxyWebhookProcessRecord, type ProxyWebhookProcessResult, type ProxyWebhookProvisioningFailure, type ProxyWebhookRequestInput, type ProxyWebhookStore, ProxyWebhooksResource, } from "./webhook-handler.js";
12
+ export { PROXY_WEBHOOK_RETRY_AFTER_SECONDS, type ProxyWebhookClaimResult, type ProxyWebhookHandlerOptions, type ProxyWebhookOutcome, type ProxyWebhookPayloadInput, type ProxyWebhookProcessRecord, type ProxyWebhookProcessResult, type ProxyWebhookProvisioningFailure, type ProxyWebhookProvisioningSuccess, type ProxyWebhookProvisioningSuccessResult, type ProxyWebhookRequestInput, type ProxyWebhookStore, ProxyWebhooksResource, } from "./webhook-handler.js";
13
13
  export { type ConstructProxyWebhookEventInput, type CreateWebhookEndpointInput, constructProxyWebhookEvent, PROXY_SIGNATURE_HEADER, ProxyWebhookEndpointsResource, type ProxyWebhookEvent, ProxyWebhookSignatureVerificationError, proxyCheckoutWebhookEndpointEndpoints, type RotateWebhookEndpointSecretInput, type UpdateWebhookEndpointInput, type VerifyProxyWebhookSignatureInput, verifyProxyWebhookSignature, type WebhookEndpoint, type WebhookEndpointSecretResult, } from "./webhooks.js";
@@ -6,6 +6,10 @@ export interface CreateProxySessionOptions extends ProxyCheckoutServerRequestOpt
6
6
  }
7
7
  export interface CreateProxySessionInput extends CreateProxySessionOptions {
8
8
  readonly amountMinor: number;
9
+ readonly beneficiaryContact?: {
10
+ readonly email?: string;
11
+ readonly phone?: string;
12
+ };
9
13
  readonly buyerReference: string;
10
14
  readonly cartSnapshot: JsonObject;
11
15
  readonly currency: string;
@@ -34,6 +38,10 @@ export interface ProxySessionHandoff extends ProxySession {
34
38
  }
35
39
  export interface MerchantProxySession {
36
40
  readonly amountMinor: number;
41
+ readonly beneficiaryContact: {
42
+ readonly email: string | null;
43
+ readonly phone: string | null;
44
+ } | null;
37
45
  readonly buyerReference: string;
38
46
  readonly cartSnapshot: JsonObject;
39
47
  readonly cartVersion: number;
@@ -87,7 +95,14 @@ export interface ProxySessionProviderBinding {
87
95
  readonly updatedAt: string;
88
96
  }
89
97
  export interface MarkProxySessionProvisionedInput extends ProxyCheckoutServerRequestOptions {
98
+ /**
99
+ * Optional merchant-side fulfillment row id to store on Proxy's provisioned
100
+ * session/audit event, for example a pending entitlement id or durable role
101
+ * id. This is for support and reconciliation only; do not put claim tokens or
102
+ * secrets here.
103
+ */
90
104
  readonly fulfillmentReference?: string;
105
+ /** Optional non-secret metadata to store with the provisioned acknowledgement. */
91
106
  readonly metadata?: JsonObject;
92
107
  }
93
108
  export interface MarkProxySessionProvisioningFailedInput extends ProxyCheckoutServerRequestOptions {
@@ -191,6 +191,12 @@ function toCreateProxySessionBody(input) {
191
191
  cart_snapshot: input.cartSnapshot,
192
192
  currency: input.currency,
193
193
  };
194
+ if (input.beneficiaryContact !== undefined) {
195
+ body.beneficiary_contact = removeUndefinedValues({
196
+ email: input.beneficiaryContact.email,
197
+ phone: input.beneficiaryContact.phone,
198
+ });
199
+ }
194
200
  if (input.expiresAt !== undefined) {
195
201
  body.expires_at =
196
202
  input.expiresAt instanceof Date ? input.expiresAt.toISOString() : input.expiresAt;
@@ -251,6 +257,7 @@ function toMerchantProxySession(response) {
251
257
  const body = requireJsonObject(response, "sessions.retrieve");
252
258
  return {
253
259
  amountMinor: requireInteger(body.amount_minor, "sessions.retrieve.amountMinor"),
260
+ beneficiaryContact: requireNullableContact(body.beneficiary_contact, "sessions.retrieve.beneficiaryContact"),
254
261
  buyerReference: requireString(body.buyer_reference, "sessions.retrieve.buyerReference"),
255
262
  cartSnapshot: requireJsonObject(body.cart_snapshot, "sessions.retrieve.cartSnapshot"),
256
263
  cartVersion: requireInteger(body.cart_version, "sessions.retrieve.cartVersion"),
@@ -261,7 +268,7 @@ function toMerchantProxySession(response) {
261
268
  idempotencyKey: requireNullableString(body.idempotency_key, "sessions.retrieve.idempotencyKey"),
262
269
  integrationMode: requireString(body.integration_mode, "sessions.retrieve.integrationMode"),
263
270
  metadata: requireJsonObject(body.metadata, "sessions.retrieve.metadata"),
264
- payerContact: requireNullablePayerContact(body.payer_contact),
271
+ payerContact: requireNullableContact(body.payer_contact, "sessions.retrieve.payerContact"),
265
272
  payerDestinationUrl: requireNullableString(body.payer_destination_url, "sessions.retrieve.payerDestinationUrl"),
266
273
  providerCheckoutSessionId: requireNullableString(body.provider_checkout_session_id, "sessions.retrieve.providerCheckoutSessionId"),
267
274
  providerCheckoutSessionPsp: requireNullableString(body.provider_checkout_session_psp, "sessions.retrieve.providerCheckoutSessionPsp"),
@@ -277,6 +284,7 @@ function toPayerOpenedResult(response) {
277
284
  }
278
285
  return {
279
286
  amountMinor: requireInteger(body.amount_minor, "sessions.payerOpened.amountMinor"),
287
+ beneficiaryContact: requireNullableContact(body.beneficiary_contact, "sessions.payerOpened.beneficiaryContact"),
280
288
  buyerReference: requireString(body.buyer_reference, "sessions.payerOpened.buyerReference"),
281
289
  cartSnapshot: requireJsonObject(body.cart_snapshot, "sessions.payerOpened.cartSnapshot"),
282
290
  cartVersion: requireInteger(body.cart_version, "sessions.payerOpened.cartVersion"),
@@ -287,7 +295,7 @@ function toPayerOpenedResult(response) {
287
295
  idempotencyKey: requireNullableString(body.idempotency_key, "sessions.payerOpened.idempotencyKey"),
288
296
  integrationMode: requireString(body.integration_mode, "sessions.payerOpened.integrationMode"),
289
297
  metadata: requireJsonObject(body.metadata, "sessions.payerOpened.metadata"),
290
- payerContact: requireNullablePayerContact(body.payer_contact, "sessions.payerOpened"),
298
+ payerContact: requireNullableContact(body.payer_contact, "sessions.payerOpened.payerContact"),
291
299
  payerDestinationUrl: requireNullableString(body.payer_destination_url, "sessions.payerOpened.payerDestinationUrl"),
292
300
  providerCheckoutSessionId: requireNullableString(body.provider_checkout_session_id, "sessions.payerOpened.providerCheckoutSessionId"),
293
301
  providerCheckoutSessionPsp: requireNullableString(body.provider_checkout_session_psp, "sessions.payerOpened.providerCheckoutSessionPsp"),
@@ -295,14 +303,14 @@ function toPayerOpenedResult(response) {
295
303
  updatedAt: requireString(body.updated_at, "sessions.payerOpened.updatedAt"),
296
304
  };
297
305
  }
298
- function requireNullablePayerContact(value, operation = "sessions.retrieve") {
299
- if (value === null) {
306
+ function requireNullableContact(value, field) {
307
+ if (value === null || value === undefined) {
300
308
  return null;
301
309
  }
302
- const contact = requireJsonObject(value, `${operation}.payerContact`);
310
+ const contact = requireJsonObject(value, field);
303
311
  return {
304
- email: requireNullableString(contact.email, `${operation}.payerContact.email`),
305
- phone: requireNullableString(contact.phone, `${operation}.payerContact.phone`),
312
+ email: requireNullableString(contact.email, `${field}.email`),
313
+ phone: requireNullableString(contact.phone, `${field}.phone`),
306
314
  };
307
315
  }
308
316
  function requirePayerHandoffStatus(value) {
@@ -1,3 +1,3 @@
1
1
  export declare const proxyCheckoutServerSdkName = "@proxy-checkout/server-js";
2
- export declare const proxyCheckoutServerSdkVersion = "0.0.7";
3
- export declare const proxyCheckoutServerSdkUserAgent = "@proxy-checkout/server-js/0.0.7";
2
+ export declare const proxyCheckoutServerSdkVersion = "0.0.8-prx-109.81.1";
3
+ export declare const proxyCheckoutServerSdkUserAgent = "@proxy-checkout/server-js/0.0.8-prx-109.81.1";
@@ -1,3 +1,3 @@
1
1
  export const proxyCheckoutServerSdkName = "@proxy-checkout/server-js";
2
- export const proxyCheckoutServerSdkVersion = "0.0.7";
2
+ export const proxyCheckoutServerSdkVersion = "0.0.8-prx-109.81.1";
3
3
  export const proxyCheckoutServerSdkUserAgent = `${proxyCheckoutServerSdkName}/${proxyCheckoutServerSdkVersion}`;
@@ -40,6 +40,20 @@ export interface ProxyWebhookProvisioningFailure {
40
40
  readonly errorMessage: string;
41
41
  readonly metadata?: JsonObject;
42
42
  }
43
+ /**
44
+ * Optional data recorded when the handler acknowledges successful initial
45
+ * provisioning back to Proxy. This is audit/reconciliation data only. It does
46
+ * not grant access, does not participate in future claim-token validation, and
47
+ * should not contain secrets.
48
+ */
49
+ export interface ProxyWebhookProvisioningSuccess {
50
+ /** Stable merchant-side row id that fulfilled the session, such as a pending entitlement or role id. */
51
+ readonly fulfillmentReference?: string;
52
+ /** Small non-secret facts to store on Proxy's provisioned session/audit event. */
53
+ readonly metadata?: JsonObject;
54
+ }
55
+ type ProxyWebhookNoProvisioningMetadataResult = void;
56
+ export type ProxyWebhookProvisioningSuccessResult = ProxyWebhookProvisioningSuccess | null | undefined | ProxyWebhookNoProvisioningMetadataResult;
43
57
  export interface ProxyWebhookPayloadInput {
44
58
  readonly body: Buffer | string;
45
59
  readonly signature?: string | null;
@@ -56,8 +70,14 @@ export interface ProxyWebhookHandlerOptions {
56
70
  * failure payload only after the merchant knows retrying cannot grant access.
57
71
  */
58
72
  readonly classifyProvisioningFailure?: (error: unknown, resolved: ResolvedProxyEvent) => Promise<ProxyWebhookProvisioningFailure | null | undefined> | ProxyWebhookProvisioningFailure | null | undefined;
59
- /** Merchant entitlement callback, invoked once per claimed event after current-state resolution. */
60
- readonly onResolved: (resolved: ResolvedProxyEvent) => Promise<void> | void;
73
+ /**
74
+ * Merchant entitlement callback, invoked once per claimed event after
75
+ * current-state resolution. For initial provisioning, mutate the merchant's
76
+ * entitlement store first, then optionally return the merchant-side row id
77
+ * and non-secret metadata to record on Proxy's provisioned acknowledgement.
78
+ * Do not return claim tokens or other secrets here.
79
+ */
80
+ readonly onResolved: (resolved: ResolvedProxyEvent) => Promise<ProxyWebhookProvisioningSuccessResult> | ProxyWebhookProvisioningSuccessResult;
61
81
  /** Optional request id forwarded to the current-state retrieval calls. */
62
82
  readonly requestId?: string;
63
83
  /** Endpoint signing secret. */
@@ -102,3 +122,4 @@ export declare class ProxyWebhooksResource {
102
122
  private runResolvedHandler;
103
123
  private requireSessionsResource;
104
124
  }
125
+ export {};
@@ -61,9 +61,11 @@ export class ProxyWebhooksResource {
61
61
  let resolved;
62
62
  try {
63
63
  resolved = await this.events.resolveCurrentState(event, { requestId: options.requestId });
64
- const provisioningFailed = await this.runResolvedHandler(resolved, options);
65
- if (!provisioningFailed && resolved.kind === "initial_provision") {
64
+ const provisioning = await this.runResolvedHandler(resolved, options);
65
+ if (!provisioning.failed && resolved.kind === "initial_provision") {
66
66
  await this.requireSessionsResource("mark provisioned").markProvisioned(resolved.session.id, {
67
+ fulfillmentReference: provisioning.success?.fulfillmentReference,
68
+ metadata: provisioning.success?.metadata,
67
69
  requestId: options.requestId,
68
70
  });
69
71
  }
@@ -127,8 +129,11 @@ export class ProxyWebhooksResource {
127
129
  }
128
130
  async runResolvedHandler(resolved, options) {
129
131
  try {
130
- await options.onResolved(resolved);
131
- return false;
132
+ const success = await options.onResolved(resolved);
133
+ return {
134
+ failed: false,
135
+ success: normalizeProvisioningSuccess(success),
136
+ };
132
137
  }
133
138
  catch (error) {
134
139
  if (resolved.kind !== "initial_provision" || !options.classifyProvisioningFailure) {
@@ -144,7 +149,7 @@ export class ProxyWebhooksResource {
144
149
  metadata: failure.metadata,
145
150
  requestId: options.requestId,
146
151
  });
147
- return true;
152
+ return { failed: true };
148
153
  }
149
154
  }
150
155
  requireSessionsResource(operation) {
@@ -156,6 +161,21 @@ export class ProxyWebhooksResource {
156
161
  });
157
162
  }
158
163
  }
164
+ function normalizeProvisioningSuccess(value) {
165
+ if (value == null) {
166
+ return undefined;
167
+ }
168
+ const success = {};
169
+ if (value.fulfillmentReference !== undefined) {
170
+ success.fulfillmentReference = value.fulfillmentReference;
171
+ }
172
+ if (value.metadata !== undefined) {
173
+ success.metadata = value.metadata;
174
+ }
175
+ return success.fulfillmentReference === undefined && success.metadata === undefined
176
+ ? undefined
177
+ : success;
178
+ }
159
179
  function toWebhookResponse(result) {
160
180
  const headers = { "content-type": "application/json" };
161
181
  if (result.retryable) {
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "sideEffects": false,
8
8
  "type": "module",
9
9
  "types": "./dist/esm/index.d.ts",
10
- "version": "0.0.7",
10
+ "version": "0.0.8-prx-109.81.1",
11
11
  "devDependencies": {
12
12
  "@types/node": "^24.12.4",
13
13
  "@vitest/coverage-v8": "4.1.7",