@proxy-checkout/server-js 0.0.2 → 0.0.3-prx-58.10.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 +23 -7
- package/dist/client.d.ts +2 -0
- package/dist/client.js +7 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/response-validators.d.ts +8 -0
- package/dist/response-validators.js +51 -0
- package/dist/sessions.d.ts +41 -3
- package/dist/sessions.js +122 -22
- package/dist/subscriptions.d.ts +32 -0
- package/dist/subscriptions.js +41 -0
- package/dist/types.d.ts +2 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/dist/webhooks.d.ts +11 -1
- package/dist/webhooks.js +22 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,9 +9,12 @@ This package should expose the merchant-authenticated backend routes that exist
|
|
|
9
9
|
| SDK method | HTTP endpoint | Purpose |
|
|
10
10
|
| --- | --- | --- |
|
|
11
11
|
| `proxy.sessions.create` | `POST /proxy_sessions` | Create a Proxy Elements session. |
|
|
12
|
+
| `proxy.sessions.createHandoff` | `POST /proxy_sessions/handoff` | Create a Proxy session and atomically mark it ready for hosted payer handoff. |
|
|
13
|
+
| `proxy.sessions.retrieve` | `GET /proxy_sessions/:id/merchant` | Retrieve current merchant-owned session state after a webhook or before creating PSP objects. |
|
|
12
14
|
| `proxy.sessions.cart.set` | `PUT /proxy_sessions/:id/cart` | Replace the current cart snapshot before payment orchestration. |
|
|
13
15
|
| `proxy.sessions.payerHandoff` | `POST /proxy_sessions/:id/payer_handoff` | Record merchant handoff issuance before the payer loads checkout. |
|
|
14
|
-
| `proxy.sessions.payerOpened` | `POST /proxy_sessions/:id/payer_opened` | Record checkout open and read the current cart
|
|
16
|
+
| `proxy.sessions.payerOpened` | `POST /proxy_sessions/:id/payer_opened` | Record checkout open and read the current merchant session/cart state. |
|
|
17
|
+
| `proxy.subscriptions.retrieve` | `GET /subscriptions/:id` | Retrieve current Proxy-linked subscription lifecycle state. |
|
|
15
18
|
| `proxy.webhookEndpoints.list` | `GET /webhook_endpoints` | List outbound merchant webhook endpoints. |
|
|
16
19
|
| `proxy.webhookEndpoints.create` | `POST /webhook_endpoints` | Create an outbound endpoint and receive its one-time signing secret. |
|
|
17
20
|
| `proxy.webhookEndpoints.get` | `GET /webhook_endpoints/:id` | Read one outbound endpoint. |
|
|
@@ -26,9 +29,11 @@ import { createProxyCheckoutServerClient } from "@proxy-checkout/server-js";
|
|
|
26
29
|
|
|
27
30
|
const proxy = createProxyCheckoutServerClient({
|
|
28
31
|
apiKey: process.env.PROXY_SECRET_KEY!,
|
|
32
|
+
publishableKey: process.env.PROXY_PUBLISHABLE_KEY!,
|
|
33
|
+
payHost: process.env.PROXY_PAY_HOST,
|
|
29
34
|
});
|
|
30
35
|
|
|
31
|
-
const
|
|
36
|
+
const handoff = await proxy.sessions.createHandoff({
|
|
32
37
|
amountMinor: 5000,
|
|
33
38
|
buyerReference: "buyer_123",
|
|
34
39
|
currency: "usd",
|
|
@@ -38,7 +43,13 @@ const session = await proxy.sessions.create({
|
|
|
38
43
|
idempotencyKey: "order_123",
|
|
39
44
|
});
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
console.log(handoff.handoffUrl);
|
|
47
|
+
|
|
48
|
+
const currentSession = await proxy.sessions.retrieve(handoff.id);
|
|
49
|
+
console.log(currentSession.buyerReference);
|
|
50
|
+
|
|
51
|
+
const opened = await proxy.sessions.payerOpened(handoff.id);
|
|
52
|
+
console.log(opened.buyerReference, opened.cartSnapshot);
|
|
42
53
|
|
|
43
54
|
const endpoint = await proxy.webhookEndpoints.create({
|
|
44
55
|
url: "https://example.com/proxy-webhooks",
|
|
@@ -48,16 +59,21 @@ const endpoint = await proxy.webhookEndpoints.create({
|
|
|
48
59
|
console.log(endpoint.signingSecret);
|
|
49
60
|
```
|
|
50
61
|
|
|
51
|
-
Verify outbound
|
|
62
|
+
Verify and parse outbound webhooks with the exact raw request body:
|
|
52
63
|
|
|
53
64
|
```ts
|
|
54
|
-
import {
|
|
65
|
+
import { constructProxyWebhookEvent } from "@proxy-checkout/server-js";
|
|
55
66
|
|
|
56
|
-
const
|
|
67
|
+
const event = constructProxyWebhookEvent({
|
|
57
68
|
body: rawBodyBuffer,
|
|
58
69
|
header: request.headers["proxy-signature"],
|
|
59
70
|
secret: process.env.PROXY_WEBHOOK_SIGNING_SECRET!,
|
|
60
71
|
});
|
|
72
|
+
|
|
73
|
+
if (event.type === "subscription.renewed") {
|
|
74
|
+
const subscription = await proxy.subscriptions.retrieve(event.data.subscription_id);
|
|
75
|
+
console.log(subscription.currentPeriodEnd);
|
|
76
|
+
}
|
|
61
77
|
```
|
|
62
78
|
|
|
63
79
|
Production calls default to `https://api.proxycheckout.com`. Tests, local
|
|
@@ -65,7 +81,7 @@ development, and previews can pass `apiHost`.
|
|
|
65
81
|
|
|
66
82
|
## First Publish Decisions
|
|
67
83
|
|
|
68
|
-
The first public package
|
|
84
|
+
The first public package versions are intentionally `0.0.x` because the SDK API is
|
|
69
85
|
early and expected to change. The npm package is MIT-licensed under the
|
|
70
86
|
package-scoped `LICENSE` file.
|
|
71
87
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ProxySessionsResource } from "./sessions.js";
|
|
2
|
+
import { ProxySubscriptionsResource } from "./subscriptions.js";
|
|
2
3
|
import type { ProxyCheckoutServerClientOptions } from "./types.js";
|
|
3
4
|
import { ProxyWebhookEndpointsResource } from "./webhooks.js";
|
|
4
5
|
export declare class ProxyCheckoutServerClient {
|
|
5
6
|
readonly apiHost: string;
|
|
6
7
|
readonly sessions: ProxySessionsResource;
|
|
8
|
+
readonly subscriptions: ProxySubscriptionsResource;
|
|
7
9
|
readonly webhookEndpoints: ProxyWebhookEndpointsResource;
|
|
8
10
|
constructor(options: ProxyCheckoutServerClientOptions);
|
|
9
11
|
}
|
package/dist/client.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ProxyCheckoutHttpClient } from "./http-client.js";
|
|
2
2
|
import { ProxySessionsResource } from "./sessions.js";
|
|
3
|
+
import { ProxySubscriptionsResource } from "./subscriptions.js";
|
|
3
4
|
import { ProxyWebhookEndpointsResource } from "./webhooks.js";
|
|
4
5
|
export class ProxyCheckoutServerClient {
|
|
5
6
|
apiHost;
|
|
6
7
|
sessions;
|
|
8
|
+
subscriptions;
|
|
7
9
|
webhookEndpoints;
|
|
8
10
|
constructor(options) {
|
|
9
11
|
const httpClient = new ProxyCheckoutHttpClient({
|
|
@@ -12,7 +14,11 @@ export class ProxyCheckoutServerClient {
|
|
|
12
14
|
fetchImpl: options.fetch,
|
|
13
15
|
});
|
|
14
16
|
this.apiHost = httpClient.apiHost;
|
|
15
|
-
this.sessions = new ProxySessionsResource(httpClient
|
|
17
|
+
this.sessions = new ProxySessionsResource(httpClient, {
|
|
18
|
+
payHost: options.payHost,
|
|
19
|
+
publishableKey: options.publishableKey,
|
|
20
|
+
});
|
|
21
|
+
this.subscriptions = new ProxySubscriptionsResource(httpClient);
|
|
16
22
|
this.webhookEndpoints = new ProxyWebhookEndpointsResource(httpClient);
|
|
17
23
|
}
|
|
18
24
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { createProxyCheckoutServerClient, ProxyCheckoutServerClient, } from "./client.js";
|
|
2
2
|
export { ProxyCheckoutApiError, type ProxyCheckoutApiErrorDetails } from "./errors.js";
|
|
3
|
-
export { type CreateProxySessionInput, type CreateProxySessionOptions, type PayerHandoffResult, type PayerOpenedResult, type ProxySession, ProxySessionCartResource, type ProxySessionCartResult, ProxySessionsResource, proxyCheckoutServerEndpoints, type SetProxySessionCartInput, } from "./sessions.js";
|
|
3
|
+
export { type CreateProxySessionHandoffInput, type CreateProxySessionInput, type CreateProxySessionOptions, type MerchantProxySession, type PayerHandoffResult, type PayerOpenedResult, type ProxySession, ProxySessionCartResource, type ProxySessionCartResult, type ProxySessionHandoff, ProxySessionsResource, proxyCheckoutServerEndpoints, type SetProxySessionCartInput, } from "./sessions.js";
|
|
4
|
+
export { type MerchantProxySubscription, ProxySubscriptionsResource, proxyCheckoutSubscriptionEndpoints, } from "./subscriptions.js";
|
|
4
5
|
export type { JsonObject, JsonPrimitive, JsonValue, ProxyCheckoutFetch, ProxyCheckoutServerClientOptions, ProxyCheckoutServerRequestOptions, } from "./types.js";
|
|
5
6
|
export { proxyCheckoutServerSdkName, proxyCheckoutServerSdkUserAgent, proxyCheckoutServerSdkVersion, } from "./version.js";
|
|
6
|
-
export { type CreateWebhookEndpointInput, ProxyWebhookEndpointsResource, proxyCheckoutWebhookEndpointEndpoints, type RotateWebhookEndpointSecretInput, type UpdateWebhookEndpointInput, type VerifyProxyWebhookSignatureInput, verifyProxyWebhookSignature, type WebhookEndpoint, type WebhookEndpointSecretResult, } from "./webhooks.js";
|
|
7
|
+
export { type ConstructProxyWebhookEventInput, type CreateWebhookEndpointInput, constructProxyWebhookEvent, PROXY_SIGNATURE_HEADER, ProxyWebhookEndpointsResource, type ProxyWebhookEvent, proxyCheckoutWebhookEndpointEndpoints, type RotateWebhookEndpointSecretInput, type UpdateWebhookEndpointInput, type VerifyProxyWebhookSignatureInput, verifyProxyWebhookSignature, type WebhookEndpoint, type WebhookEndpointSecretResult, } from "./webhooks.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { createProxyCheckoutServerClient, ProxyCheckoutServerClient, } from "./client.js";
|
|
2
2
|
export { ProxyCheckoutApiError } from "./errors.js";
|
|
3
3
|
export { ProxySessionCartResource, ProxySessionsResource, proxyCheckoutServerEndpoints, } from "./sessions.js";
|
|
4
|
+
export { ProxySubscriptionsResource, proxyCheckoutSubscriptionEndpoints, } from "./subscriptions.js";
|
|
4
5
|
export { proxyCheckoutServerSdkName, proxyCheckoutServerSdkUserAgent, proxyCheckoutServerSdkVersion, } from "./version.js";
|
|
5
|
-
export { ProxyWebhookEndpointsResource, proxyCheckoutWebhookEndpointEndpoints, verifyProxyWebhookSignature, } from "./webhooks.js";
|
|
6
|
+
export { constructProxyWebhookEvent, PROXY_SIGNATURE_HEADER, ProxyWebhookEndpointsResource, proxyCheckoutWebhookEndpointEndpoints, verifyProxyWebhookSignature, } from "./webhooks.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { JsonObject } from "./types.js";
|
|
2
|
+
export declare function requireJsonObject(value: unknown, operation: string): JsonObject;
|
|
3
|
+
export declare function requireString(value: unknown, field: string): string;
|
|
4
|
+
export declare function requireNullableString(value: unknown, field: string): string | null;
|
|
5
|
+
export declare function requireInteger(value: unknown, field: string): number;
|
|
6
|
+
export declare function requireNullableInteger(value: unknown, field: string): number | null;
|
|
7
|
+
export declare function requireBoolean(value: unknown, field: string): boolean;
|
|
8
|
+
export declare function requireStringArrayOrNull(value: unknown, field: string): string[] | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function requireJsonObject(value, operation) {
|
|
2
|
+
if (!isRecord(value)) {
|
|
3
|
+
throw new Error(`Proxy API response for ${operation} must be a JSON object.`);
|
|
4
|
+
}
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
export function requireString(value, field) {
|
|
8
|
+
if (typeof value !== "string") {
|
|
9
|
+
throw new Error(`Proxy API response field ${field} must be a string.`);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
export function requireNullableString(value, field) {
|
|
14
|
+
if (value === null) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return requireString(value, field);
|
|
18
|
+
}
|
|
19
|
+
export function requireInteger(value, field) {
|
|
20
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
21
|
+
throw new Error(`Proxy API response field ${field} must be an integer.`);
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
export function requireNullableInteger(value, field) {
|
|
26
|
+
if (value === null) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
30
|
+
throw new Error(`Proxy API response field ${field} must be an integer or null.`);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
export function requireBoolean(value, field) {
|
|
35
|
+
if (typeof value !== "boolean") {
|
|
36
|
+
throw new Error(`Proxy API response field ${field} must be a boolean.`);
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
export function requireStringArrayOrNull(value, field) {
|
|
41
|
+
if (value === null) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
45
|
+
throw new Error(`Proxy API response field ${field} must be an array or null.`);
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
function isRecord(value) {
|
|
50
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
51
|
+
}
|
package/dist/sessions.d.ts
CHANGED
|
@@ -16,16 +16,40 @@ export interface CreateProxySessionInput extends CreateProxySessionOptions {
|
|
|
16
16
|
readonly phone?: string;
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
export interface CreateProxySessionHandoffInput extends CreateProxySessionInput {
|
|
20
|
+
readonly payHost?: string;
|
|
21
|
+
readonly publishableKey?: string;
|
|
22
|
+
}
|
|
19
23
|
export interface ProxySession {
|
|
20
24
|
readonly expiresAt: string;
|
|
21
25
|
readonly id: string;
|
|
22
26
|
readonly integrationMode: string;
|
|
23
27
|
readonly status: string;
|
|
24
28
|
}
|
|
25
|
-
export interface
|
|
29
|
+
export interface ProxySessionHandoff extends ProxySession {
|
|
30
|
+
readonly handoffUrl: string;
|
|
31
|
+
readonly status: "payer_handoff_pending" | "payer_opened";
|
|
32
|
+
}
|
|
33
|
+
export interface MerchantProxySession {
|
|
26
34
|
readonly amountMinor: number;
|
|
27
|
-
readonly
|
|
35
|
+
readonly buyerReference: string;
|
|
36
|
+
readonly cartSnapshot: JsonObject;
|
|
37
|
+
readonly createdAt: string;
|
|
28
38
|
readonly currency: string;
|
|
39
|
+
readonly expiresAt: string;
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly idempotencyKey: string | null;
|
|
42
|
+
readonly integrationMode: string;
|
|
43
|
+
readonly metadata: JsonObject;
|
|
44
|
+
readonly payerContact: {
|
|
45
|
+
readonly email: string | null;
|
|
46
|
+
readonly phone: string | null;
|
|
47
|
+
} | null;
|
|
48
|
+
readonly status: string;
|
|
49
|
+
readonly updatedAt: string;
|
|
50
|
+
}
|
|
51
|
+
export interface PayerOpenedResult extends MerchantProxySession {
|
|
52
|
+
readonly status: "payer_opened";
|
|
29
53
|
}
|
|
30
54
|
export interface PayerHandoffResult {
|
|
31
55
|
readonly status: "payer_handoff_pending" | "payer_opened";
|
|
@@ -44,6 +68,14 @@ export declare const proxyCheckoutServerEndpoints: readonly [{
|
|
|
44
68
|
readonly method: "POST";
|
|
45
69
|
readonly operation: "sessions.create";
|
|
46
70
|
readonly path: "/proxy_sessions";
|
|
71
|
+
}, {
|
|
72
|
+
readonly method: "POST";
|
|
73
|
+
readonly operation: "sessions.createHandoff";
|
|
74
|
+
readonly path: "/proxy_sessions/handoff";
|
|
75
|
+
}, {
|
|
76
|
+
readonly method: "GET";
|
|
77
|
+
readonly operation: "sessions.retrieve";
|
|
78
|
+
readonly path: "/proxy_sessions/:id/merchant";
|
|
47
79
|
}, {
|
|
48
80
|
readonly method: "PUT";
|
|
49
81
|
readonly operation: "sessions.cart.set";
|
|
@@ -59,9 +91,15 @@ export declare const proxyCheckoutServerEndpoints: readonly [{
|
|
|
59
91
|
}];
|
|
60
92
|
export declare class ProxySessionsResource {
|
|
61
93
|
private readonly httpClient;
|
|
94
|
+
private readonly options;
|
|
62
95
|
readonly cart: ProxySessionCartResource;
|
|
63
|
-
constructor(httpClient: ProxyCheckoutHttpClient
|
|
96
|
+
constructor(httpClient: ProxyCheckoutHttpClient, options?: {
|
|
97
|
+
payHost?: string;
|
|
98
|
+
publishableKey?: string;
|
|
99
|
+
});
|
|
64
100
|
create(input: CreateProxySessionInput): Promise<ProxySession>;
|
|
101
|
+
createHandoff(input: CreateProxySessionHandoffInput): Promise<ProxySessionHandoff>;
|
|
102
|
+
retrieve(proxySessionId: string, options?: ProxyCheckoutServerRequestOptions): Promise<MerchantProxySession>;
|
|
65
103
|
payerHandoff(proxySessionId: string, options?: ProxyCheckoutServerRequestOptions): Promise<PayerHandoffResult>;
|
|
66
104
|
payerOpened(proxySessionId: string, options?: ProxyCheckoutServerRequestOptions): Promise<PayerOpenedResult>;
|
|
67
105
|
}
|
package/dist/sessions.js
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
|
+
import { requireInteger, requireJsonObject, requireNullableString, requireString, } from "./response-validators.js";
|
|
1
2
|
export const proxyCheckoutServerEndpoints = [
|
|
2
3
|
{
|
|
3
4
|
method: "POST",
|
|
4
5
|
operation: "sessions.create",
|
|
5
6
|
path: "/proxy_sessions",
|
|
6
7
|
},
|
|
8
|
+
{
|
|
9
|
+
method: "POST",
|
|
10
|
+
operation: "sessions.createHandoff",
|
|
11
|
+
path: "/proxy_sessions/handoff",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
method: "GET",
|
|
15
|
+
operation: "sessions.retrieve",
|
|
16
|
+
path: "/proxy_sessions/:id/merchant",
|
|
17
|
+
},
|
|
7
18
|
{
|
|
8
19
|
method: "PUT",
|
|
9
20
|
operation: "sessions.cart.set",
|
|
@@ -22,9 +33,11 @@ export const proxyCheckoutServerEndpoints = [
|
|
|
22
33
|
];
|
|
23
34
|
export class ProxySessionsResource {
|
|
24
35
|
httpClient;
|
|
36
|
+
options;
|
|
25
37
|
cart;
|
|
26
|
-
constructor(httpClient) {
|
|
38
|
+
constructor(httpClient, options = {}) {
|
|
27
39
|
this.httpClient = httpClient;
|
|
40
|
+
this.options = options;
|
|
28
41
|
this.cart = new ProxySessionCartResource(httpClient);
|
|
29
42
|
}
|
|
30
43
|
async create(input) {
|
|
@@ -34,6 +47,36 @@ export class ProxySessionsResource {
|
|
|
34
47
|
});
|
|
35
48
|
return toProxySession(response);
|
|
36
49
|
}
|
|
50
|
+
async createHandoff(input) {
|
|
51
|
+
const publishableKey = input.publishableKey ?? this.options.publishableKey;
|
|
52
|
+
if (!publishableKey) {
|
|
53
|
+
throw new Error("Proxy Checkout sessions.createHandoff requires a publishableKey option or input field.");
|
|
54
|
+
}
|
|
55
|
+
const payHost = input.payHost ?? this.options.payHost;
|
|
56
|
+
if (!payHost && this.httpClient.apiHost !== "https://api.proxycheckout.com") {
|
|
57
|
+
throw new Error("Proxy Checkout sessions.createHandoff requires a payHost option or input field when apiHost is overridden.");
|
|
58
|
+
}
|
|
59
|
+
const response = await this.httpClient.request("POST", "/proxy_sessions/handoff", {
|
|
60
|
+
...toCreateProxySessionBody(input),
|
|
61
|
+
publishable_key: publishableKey,
|
|
62
|
+
}, {
|
|
63
|
+
idempotencyKey: input.idempotencyKey,
|
|
64
|
+
requestId: input.requestId,
|
|
65
|
+
});
|
|
66
|
+
const session = toProxySessionHandoff(response);
|
|
67
|
+
return {
|
|
68
|
+
...session,
|
|
69
|
+
handoffUrl: buildHandoffUrl({
|
|
70
|
+
payHost,
|
|
71
|
+
proxySessionId: session.id,
|
|
72
|
+
publishableKey,
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async retrieve(proxySessionId, options = {}) {
|
|
77
|
+
const response = await this.httpClient.request("GET", `/proxy_sessions/${encodeURIComponent(proxySessionId)}/merchant`, undefined, options);
|
|
78
|
+
return toMerchantProxySession(response);
|
|
79
|
+
}
|
|
37
80
|
async payerHandoff(proxySessionId, options = {}) {
|
|
38
81
|
const response = await this.httpClient.request("POST", `/proxy_sessions/${encodeURIComponent(proxySessionId)}/payer_handoff`, {}, options);
|
|
39
82
|
const body = requireJsonObject(response, "sessions.payerHandoff");
|
|
@@ -43,12 +86,7 @@ export class ProxySessionsResource {
|
|
|
43
86
|
}
|
|
44
87
|
async payerOpened(proxySessionId, options = {}) {
|
|
45
88
|
const response = await this.httpClient.request("POST", `/proxy_sessions/${encodeURIComponent(proxySessionId)}/payer_opened`, {}, options);
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
amountMinor: requireInteger(body.amount_minor, "sessions.payerOpened.amountMinor"),
|
|
49
|
-
cartDetails: requireJsonObject(body.cart_details, "sessions.payerOpened"),
|
|
50
|
-
currency: requireString(body.currency, "sessions.payerOpened.currency"),
|
|
51
|
-
};
|
|
89
|
+
return toPayerOpenedResult(response);
|
|
52
90
|
}
|
|
53
91
|
}
|
|
54
92
|
export class ProxySessionCartResource {
|
|
@@ -114,23 +152,67 @@ function toProxySession(response) {
|
|
|
114
152
|
status,
|
|
115
153
|
};
|
|
116
154
|
}
|
|
117
|
-
function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return
|
|
155
|
+
function toProxySessionHandoff(response) {
|
|
156
|
+
const body = requireJsonObject(response, "sessions.createHandoff");
|
|
157
|
+
const status = requirePayerHandoffStatus(body.status);
|
|
158
|
+
const integrationMode = requireString(body.integration_mode, "sessions.createHandoff.integrationMode");
|
|
159
|
+
return {
|
|
160
|
+
expiresAt: requireString(body.expires_at, "sessions.createHandoff.expiresAt"),
|
|
161
|
+
handoffUrl: "",
|
|
162
|
+
id: requireString(body.id, "sessions.createHandoff.id"),
|
|
163
|
+
integrationMode,
|
|
164
|
+
status,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function toMerchantProxySession(response) {
|
|
168
|
+
const body = requireJsonObject(response, "sessions.retrieve");
|
|
169
|
+
return {
|
|
170
|
+
amountMinor: requireInteger(body.amount_minor, "sessions.retrieve.amountMinor"),
|
|
171
|
+
buyerReference: requireString(body.buyer_reference, "sessions.retrieve.buyerReference"),
|
|
172
|
+
cartSnapshot: requireJsonObject(body.cart_snapshot, "sessions.retrieve.cartSnapshot"),
|
|
173
|
+
createdAt: requireString(body.created_at, "sessions.retrieve.createdAt"),
|
|
174
|
+
currency: requireString(body.currency, "sessions.retrieve.currency"),
|
|
175
|
+
expiresAt: requireString(body.expires_at, "sessions.retrieve.expiresAt"),
|
|
176
|
+
id: requireString(body.id, "sessions.retrieve.id"),
|
|
177
|
+
idempotencyKey: requireNullableString(body.idempotency_key, "sessions.retrieve.idempotencyKey"),
|
|
178
|
+
integrationMode: requireString(body.integration_mode, "sessions.retrieve.integrationMode"),
|
|
179
|
+
metadata: requireJsonObject(body.metadata, "sessions.retrieve.metadata"),
|
|
180
|
+
payerContact: requireNullablePayerContact(body.payer_contact),
|
|
181
|
+
status: requireString(body.status, "sessions.retrieve.status"),
|
|
182
|
+
updatedAt: requireString(body.updated_at, "sessions.retrieve.updatedAt"),
|
|
183
|
+
};
|
|
122
184
|
}
|
|
123
|
-
function
|
|
124
|
-
|
|
125
|
-
|
|
185
|
+
function toPayerOpenedResult(response) {
|
|
186
|
+
const body = requireJsonObject(response, "sessions.payerOpened");
|
|
187
|
+
const status = requireString(body.status, "sessions.payerOpened.status");
|
|
188
|
+
if (status !== "payer_opened") {
|
|
189
|
+
throw new Error("Proxy API response field sessions.payerOpened.status is unsupported.");
|
|
126
190
|
}
|
|
127
|
-
return
|
|
191
|
+
return {
|
|
192
|
+
amountMinor: requireInteger(body.amount_minor, "sessions.payerOpened.amountMinor"),
|
|
193
|
+
buyerReference: requireString(body.buyer_reference, "sessions.payerOpened.buyerReference"),
|
|
194
|
+
cartSnapshot: requireJsonObject(body.cart_snapshot, "sessions.payerOpened.cartSnapshot"),
|
|
195
|
+
createdAt: requireString(body.created_at, "sessions.payerOpened.createdAt"),
|
|
196
|
+
currency: requireString(body.currency, "sessions.payerOpened.currency"),
|
|
197
|
+
expiresAt: requireString(body.expires_at, "sessions.payerOpened.expiresAt"),
|
|
198
|
+
id: requireString(body.id, "sessions.payerOpened.id"),
|
|
199
|
+
idempotencyKey: requireNullableString(body.idempotency_key, "sessions.payerOpened.idempotencyKey"),
|
|
200
|
+
integrationMode: requireString(body.integration_mode, "sessions.payerOpened.integrationMode"),
|
|
201
|
+
metadata: requireJsonObject(body.metadata, "sessions.payerOpened.metadata"),
|
|
202
|
+
payerContact: requireNullablePayerContact(body.payer_contact, "sessions.payerOpened"),
|
|
203
|
+
status,
|
|
204
|
+
updatedAt: requireString(body.updated_at, "sessions.payerOpened.updatedAt"),
|
|
205
|
+
};
|
|
128
206
|
}
|
|
129
|
-
function
|
|
130
|
-
if (
|
|
131
|
-
|
|
207
|
+
function requireNullablePayerContact(value, operation = "sessions.retrieve") {
|
|
208
|
+
if (value === null) {
|
|
209
|
+
return null;
|
|
132
210
|
}
|
|
133
|
-
|
|
211
|
+
const contact = requireJsonObject(value, `${operation}.payerContact`);
|
|
212
|
+
return {
|
|
213
|
+
email: requireNullableString(contact.email, `${operation}.payerContact.email`),
|
|
214
|
+
phone: requireNullableString(contact.phone, `${operation}.payerContact.phone`),
|
|
215
|
+
};
|
|
134
216
|
}
|
|
135
217
|
function requirePayerHandoffStatus(value) {
|
|
136
218
|
const status = requireString(value, "sessions.payerHandoff.status");
|
|
@@ -139,6 +221,24 @@ function requirePayerHandoffStatus(value) {
|
|
|
139
221
|
}
|
|
140
222
|
throw new Error("Proxy API response field sessions.payerHandoff.status is unsupported.");
|
|
141
223
|
}
|
|
142
|
-
function
|
|
143
|
-
|
|
224
|
+
function buildHandoffUrl({ payHost, proxySessionId, publishableKey, }) {
|
|
225
|
+
const url = new URL(`${normalizePayHost(payHost)}/s/${encodeURIComponent(proxySessionId)}`);
|
|
226
|
+
url.searchParams.set("pk", publishableKey);
|
|
227
|
+
return url.toString();
|
|
228
|
+
}
|
|
229
|
+
function normalizePayHost(payHost) {
|
|
230
|
+
if (payHost === undefined) {
|
|
231
|
+
return "https://pay.proxycheckout.com";
|
|
232
|
+
}
|
|
233
|
+
let url;
|
|
234
|
+
try {
|
|
235
|
+
url = new URL(payHost);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
throw new Error(`Invalid payHost URL: ${payHost}. Make sure it is an absolute HTTP or HTTPS URL.`);
|
|
239
|
+
}
|
|
240
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
241
|
+
throw new Error(`Invalid payHost URL: ${payHost}. Make sure it is an absolute HTTP or HTTPS URL.`);
|
|
242
|
+
}
|
|
243
|
+
return `${url.origin}${url.pathname}`.replace(/\/$/, "");
|
|
144
244
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ProxyCheckoutHttpClient } from "./http-client.js";
|
|
2
|
+
import type { ProxyCheckoutServerRequestOptions } from "./types.js";
|
|
3
|
+
export interface MerchantProxySubscription {
|
|
4
|
+
readonly buyerReference: string;
|
|
5
|
+
readonly cancelAtPeriodEnd: boolean;
|
|
6
|
+
readonly createdAt: string;
|
|
7
|
+
readonly currentPeriodEnd: string | null;
|
|
8
|
+
readonly currentPeriodStart: string | null;
|
|
9
|
+
readonly endedAt: string | null;
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly latestInvoiceAmountMinor: number | null;
|
|
12
|
+
readonly latestInvoiceCurrency: string | null;
|
|
13
|
+
readonly latestInvoiceId: string | null;
|
|
14
|
+
readonly latestPaymentStatus: string | null;
|
|
15
|
+
readonly originalProxySessionId: string;
|
|
16
|
+
readonly providerCheckoutSessionId: string | null;
|
|
17
|
+
readonly providerSubscriptionId: string;
|
|
18
|
+
readonly psp: string;
|
|
19
|
+
readonly status: string;
|
|
20
|
+
readonly trialEnd: string | null;
|
|
21
|
+
readonly updatedAt: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const proxyCheckoutSubscriptionEndpoints: readonly [{
|
|
24
|
+
readonly method: "GET";
|
|
25
|
+
readonly operation: "subscriptions.retrieve";
|
|
26
|
+
readonly path: "/subscriptions/:id";
|
|
27
|
+
}];
|
|
28
|
+
export declare class ProxySubscriptionsResource {
|
|
29
|
+
private readonly httpClient;
|
|
30
|
+
constructor(httpClient: ProxyCheckoutHttpClient);
|
|
31
|
+
retrieve(subscriptionId: string, options?: ProxyCheckoutServerRequestOptions): Promise<MerchantProxySubscription>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { requireBoolean, requireJsonObject, requireNullableInteger, requireNullableString, requireString, } from "./response-validators.js";
|
|
2
|
+
export const proxyCheckoutSubscriptionEndpoints = [
|
|
3
|
+
{
|
|
4
|
+
method: "GET",
|
|
5
|
+
operation: "subscriptions.retrieve",
|
|
6
|
+
path: "/subscriptions/:id",
|
|
7
|
+
},
|
|
8
|
+
];
|
|
9
|
+
export class ProxySubscriptionsResource {
|
|
10
|
+
httpClient;
|
|
11
|
+
constructor(httpClient) {
|
|
12
|
+
this.httpClient = httpClient;
|
|
13
|
+
}
|
|
14
|
+
async retrieve(subscriptionId, options = {}) {
|
|
15
|
+
const response = await this.httpClient.request("GET", `/subscriptions/${encodeURIComponent(subscriptionId)}`, undefined, options);
|
|
16
|
+
return toMerchantProxySubscription(response);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function toMerchantProxySubscription(response) {
|
|
20
|
+
const body = requireJsonObject(response, "subscriptions.retrieve");
|
|
21
|
+
return {
|
|
22
|
+
buyerReference: requireString(body.buyer_reference, "subscriptions.retrieve.buyerReference"),
|
|
23
|
+
cancelAtPeriodEnd: requireBoolean(body.cancel_at_period_end, "subscriptions.retrieve.cancelAtPeriodEnd"),
|
|
24
|
+
createdAt: requireString(body.created_at, "subscriptions.retrieve.createdAt"),
|
|
25
|
+
currentPeriodEnd: requireNullableString(body.current_period_end, "subscriptions.retrieve.currentPeriodEnd"),
|
|
26
|
+
currentPeriodStart: requireNullableString(body.current_period_start, "subscriptions.retrieve.currentPeriodStart"),
|
|
27
|
+
endedAt: requireNullableString(body.ended_at, "subscriptions.retrieve.endedAt"),
|
|
28
|
+
id: requireString(body.id, "subscriptions.retrieve.id"),
|
|
29
|
+
latestInvoiceAmountMinor: requireNullableInteger(body.latest_invoice_amount_minor, "subscriptions.retrieve.latestInvoiceAmountMinor"),
|
|
30
|
+
latestInvoiceCurrency: requireNullableString(body.latest_invoice_currency, "subscriptions.retrieve.latestInvoiceCurrency"),
|
|
31
|
+
latestInvoiceId: requireNullableString(body.latest_invoice_id, "subscriptions.retrieve.latestInvoiceId"),
|
|
32
|
+
latestPaymentStatus: requireNullableString(body.latest_payment_status, "subscriptions.retrieve.latestPaymentStatus"),
|
|
33
|
+
originalProxySessionId: requireString(body.original_proxy_session_id, "subscriptions.retrieve.originalProxySessionId"),
|
|
34
|
+
providerCheckoutSessionId: requireNullableString(body.provider_checkout_session_id, "subscriptions.retrieve.providerCheckoutSessionId"),
|
|
35
|
+
providerSubscriptionId: requireString(body.provider_subscription_id, "subscriptions.retrieve.providerSubscriptionId"),
|
|
36
|
+
psp: requireString(body.psp, "subscriptions.retrieve.psp"),
|
|
37
|
+
status: requireString(body.status, "subscriptions.retrieve.status"),
|
|
38
|
+
trialEnd: requireNullableString(body.trial_end, "subscriptions.retrieve.trialEnd"),
|
|
39
|
+
updatedAt: requireString(body.updated_at, "subscriptions.retrieve.updatedAt"),
|
|
40
|
+
};
|
|
41
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface ProxyCheckoutServerClientOptions {
|
|
|
8
8
|
readonly apiHost?: string;
|
|
9
9
|
readonly apiKey: string;
|
|
10
10
|
readonly fetch?: ProxyCheckoutFetch;
|
|
11
|
+
readonly payHost?: string;
|
|
12
|
+
readonly publishableKey?: string;
|
|
11
13
|
}
|
|
12
14
|
export interface ProxyCheckoutServerRequestOptions {
|
|
13
15
|
readonly requestId?: string;
|
package/dist/version.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare const proxyCheckoutServerSdkName = "@proxy-checkout/server-js";
|
|
2
|
-
export declare const proxyCheckoutServerSdkVersion = "0.0.
|
|
3
|
-
export declare const proxyCheckoutServerSdkUserAgent = "@proxy-checkout/server-js/0.0.
|
|
2
|
+
export declare const proxyCheckoutServerSdkVersion = "0.0.3-prx-58.10.1";
|
|
3
|
+
export declare const proxyCheckoutServerSdkUserAgent = "@proxy-checkout/server-js/0.0.3-prx-58.10.1";
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export const proxyCheckoutServerSdkName = "@proxy-checkout/server-js";
|
|
2
|
-
export const proxyCheckoutServerSdkVersion = "0.0.
|
|
2
|
+
export const proxyCheckoutServerSdkVersion = "0.0.3-prx-58.10.1";
|
|
3
3
|
export const proxyCheckoutServerSdkUserAgent = `${proxyCheckoutServerSdkName}/${proxyCheckoutServerSdkVersion}`;
|
package/dist/webhooks.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ProxyCheckoutHttpClient } from "./http-client.js";
|
|
2
|
-
import type { ProxyCheckoutServerRequestOptions } from "./types.js";
|
|
2
|
+
import type { JsonObject, ProxyCheckoutServerRequestOptions } from "./types.js";
|
|
3
3
|
export interface WebhookEndpoint {
|
|
4
4
|
readonly createdAt: string;
|
|
5
5
|
readonly eventSchemaVersion: string;
|
|
@@ -32,6 +32,15 @@ export interface VerifyProxyWebhookSignatureInput {
|
|
|
32
32
|
readonly secret: string;
|
|
33
33
|
readonly toleranceSeconds?: number;
|
|
34
34
|
}
|
|
35
|
+
export interface ConstructProxyWebhookEventInput extends VerifyProxyWebhookSignatureInput {
|
|
36
|
+
}
|
|
37
|
+
export interface ProxyWebhookEvent {
|
|
38
|
+
readonly data: JsonObject;
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly schemaVersion: string;
|
|
41
|
+
readonly type: string;
|
|
42
|
+
}
|
|
43
|
+
export declare const PROXY_SIGNATURE_HEADER = "proxy-signature";
|
|
35
44
|
export declare const proxyCheckoutWebhookEndpointEndpoints: readonly [{
|
|
36
45
|
readonly method: "GET";
|
|
37
46
|
readonly operation: "webhookEndpoints.list";
|
|
@@ -68,3 +77,4 @@ export declare class ProxyWebhookEndpointsResource {
|
|
|
68
77
|
rotateSecret(webhookEndpointId: string, input: RotateWebhookEndpointSecretInput): Promise<WebhookEndpointSecretResult>;
|
|
69
78
|
}
|
|
70
79
|
export declare function verifyProxyWebhookSignature(input: VerifyProxyWebhookSignatureInput): boolean;
|
|
80
|
+
export declare function constructProxyWebhookEvent(input: ConstructProxyWebhookEventInput): ProxyWebhookEvent;
|
package/dist/webhooks.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { requireStringArrayOrNull as readStringArrayOrNull, requireNullableString as readStringOrNull, requireJsonObject, requireString, } from "./response-validators.js";
|
|
3
|
+
export const PROXY_SIGNATURE_HEADER = "proxy-signature";
|
|
2
4
|
export const proxyCheckoutWebhookEndpointEndpoints = [
|
|
3
5
|
{
|
|
4
6
|
method: "GET",
|
|
@@ -86,6 +88,26 @@ export function verifyProxyWebhookSignature(input) {
|
|
|
86
88
|
.digest("hex");
|
|
87
89
|
return parsed.signatures.some((signature) => timingSafeEqualString(expected, signature));
|
|
88
90
|
}
|
|
91
|
+
export function constructProxyWebhookEvent(input) {
|
|
92
|
+
if (!verifyProxyWebhookSignature(input)) {
|
|
93
|
+
throw new Error("Proxy webhook signature verification failed.");
|
|
94
|
+
}
|
|
95
|
+
const body = typeof input.body === "string" ? input.body : input.body.toString("utf8");
|
|
96
|
+
let parsed;
|
|
97
|
+
try {
|
|
98
|
+
parsed = JSON.parse(body);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
throw new Error("Proxy webhook body must be valid JSON.");
|
|
102
|
+
}
|
|
103
|
+
const event = requireJsonObject(parsed, "webhookEvent");
|
|
104
|
+
return {
|
|
105
|
+
data: requireJsonObject(event.data, "webhookEvent.data"),
|
|
106
|
+
id: requireString(event.id, "webhookEvent.id"),
|
|
107
|
+
schemaVersion: requireString(event.schema_version, "webhookEvent.schemaVersion"),
|
|
108
|
+
type: requireString(event.type, "webhookEvent.type"),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
89
111
|
function toWebhookEndpointBody(input) {
|
|
90
112
|
return {
|
|
91
113
|
...(input.eventTypes === undefined ? {} : { event_types: input.eventTypes }),
|
|
@@ -147,27 +169,3 @@ function timingSafeEqualString(left, right) {
|
|
|
147
169
|
const rightBuffer = Buffer.from(right, "hex");
|
|
148
170
|
return leftBuffer.length === rightBuffer.length && timingSafeEqual(leftBuffer, rightBuffer);
|
|
149
171
|
}
|
|
150
|
-
function requireJsonObject(value, operation) {
|
|
151
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
152
|
-
throw new Error(`Proxy API response for ${operation} must be a JSON object.`);
|
|
153
|
-
}
|
|
154
|
-
return value;
|
|
155
|
-
}
|
|
156
|
-
function requireString(value, field) {
|
|
157
|
-
if (typeof value !== "string") {
|
|
158
|
-
throw new Error(`Proxy API response field ${field} must be a string.`);
|
|
159
|
-
}
|
|
160
|
-
return value;
|
|
161
|
-
}
|
|
162
|
-
function readStringOrNull(value, field) {
|
|
163
|
-
return value === null ? null : requireString(value, field);
|
|
164
|
-
}
|
|
165
|
-
function readStringArrayOrNull(value, field) {
|
|
166
|
-
if (value === null) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
170
|
-
throw new Error(`Proxy API response field ${field} must be an array or null.`);
|
|
171
|
-
}
|
|
172
|
-
return value;
|
|
173
|
-
}
|