@polar-sh/sdk 1.0.0-alpha.11 → 1.0.0-alpha.12
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 +54 -0
- package/dist/2026-04/index.cjs +132 -0
- package/dist/2026-04/index.cjs.map +1 -1
- package/dist/2026-04/index.d.cts +800 -4
- package/dist/2026-04/index.d.cts.map +1 -1
- package/dist/2026-04/index.d.mts +800 -4
- package/dist/2026-04/index.d.mts.map +1 -1
- package/dist/2026-04/index.mjs +128 -2
- package/dist/2026-04/index.mjs.map +1 -1
- package/dist/2026-04/services/benefit_grants.d.cts +1 -1
- package/dist/2026-04/services/benefit_grants.d.mts +1 -1
- package/dist/2026-04/services/benefits.d.cts +1 -1
- package/dist/2026-04/services/benefits.d.mts +1 -1
- package/dist/2026-04/services/checkout_links.d.cts +1 -1
- package/dist/2026-04/services/checkout_links.d.mts +1 -1
- package/dist/2026-04/services/checkouts.d.cts +1 -1
- package/dist/2026-04/services/checkouts.d.mts +1 -1
- package/dist/2026-04/services/custom_fields.d.cts +1 -1
- package/dist/2026-04/services/custom_fields.d.mts +1 -1
- package/dist/2026-04/services/customer_meters.d.cts +1 -1
- package/dist/2026-04/services/customer_meters.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/benefit_grants.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/benefit_grants.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/customer_meters.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/customer_meters.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/customer_session.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/customer_session.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/customers.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/customers.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/downloadables.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/downloadables.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/index.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/index.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/license_keys.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/license_keys.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/members.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/members.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/orders.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/orders.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/organizations.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/organizations.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/seats.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/seats.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/subscriptions.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/subscriptions.d.mts +1 -1
- package/dist/2026-04/services/customer_portal/wallets.d.cts +1 -1
- package/dist/2026-04/services/customer_portal/wallets.d.mts +1 -1
- package/dist/2026-04/services/customer_seats.d.cts +1 -1
- package/dist/2026-04/services/customer_seats.d.mts +1 -1
- package/dist/2026-04/services/customer_sessions.d.cts +1 -1
- package/dist/2026-04/services/customer_sessions.d.mts +1 -1
- package/dist/2026-04/services/customers/index.d.cts +1 -1
- package/dist/2026-04/services/customers/index.d.mts +1 -1
- package/dist/2026-04/services/customers/members.d.cts +1 -1
- package/dist/2026-04/services/customers/members.d.mts +1 -1
- package/dist/2026-04/services/discounts.d.cts +1 -1
- package/dist/2026-04/services/discounts.d.mts +1 -1
- package/dist/2026-04/services/disputes.d.cts +1 -1
- package/dist/2026-04/services/disputes.d.mts +1 -1
- package/dist/2026-04/services/event_types.d.cts +1 -1
- package/dist/2026-04/services/event_types.d.mts +1 -1
- package/dist/2026-04/services/events.d.cts +1 -1
- package/dist/2026-04/services/events.d.mts +1 -1
- package/dist/2026-04/services/files.d.cts +1 -1
- package/dist/2026-04/services/files.d.mts +1 -1
- package/dist/2026-04/services/license_keys.d.cts +1 -1
- package/dist/2026-04/services/license_keys.d.mts +1 -1
- package/dist/2026-04/services/members.d.cts +1 -1
- package/dist/2026-04/services/members.d.mts +1 -1
- package/dist/2026-04/services/meters.d.cts +1 -1
- package/dist/2026-04/services/meters.d.mts +1 -1
- package/dist/2026-04/services/metrics.d.cts +1 -1
- package/dist/2026-04/services/metrics.d.mts +1 -1
- package/dist/2026-04/services/oauth2/clients/index.d.cts +2 -2
- package/dist/2026-04/services/oauth2/clients/index.d.mts +2 -2
- package/dist/2026-04/services/oauth2/clients/oauth2.cjs +2 -2
- package/dist/2026-04/services/oauth2/clients/oauth2.cjs.map +1 -1
- package/dist/2026-04/services/oauth2/clients/oauth2.d.cts +3 -3
- package/dist/2026-04/services/oauth2/clients/oauth2.d.mts +3 -3
- package/dist/2026-04/services/oauth2/clients/oauth2.mjs +2 -2
- package/dist/2026-04/services/oauth2/clients/oauth2.mjs.map +1 -1
- package/dist/2026-04/services/oauth2/index.d.cts +2 -2
- package/dist/2026-04/services/oauth2/index.d.mts +2 -2
- package/dist/2026-04/services/orders.d.cts +1 -1
- package/dist/2026-04/services/orders.d.mts +1 -1
- package/dist/2026-04/services/organizations.d.cts +1 -1
- package/dist/2026-04/services/organizations.d.mts +1 -1
- package/dist/2026-04/services/payments.d.cts +1 -1
- package/dist/2026-04/services/payments.d.mts +1 -1
- package/dist/2026-04/services/products.d.cts +1 -1
- package/dist/2026-04/services/products.d.mts +1 -1
- package/dist/2026-04/services/refunds.d.cts +1 -1
- package/dist/2026-04/services/refunds.d.mts +1 -1
- package/dist/2026-04/services/subscriptions.d.cts +1 -1
- package/dist/2026-04/services/subscriptions.d.mts +1 -1
- package/dist/2026-04/services/webhooks.d.cts +1 -1
- package/dist/2026-04/services/webhooks.d.mts +1 -1
- package/dist/{models-IotBovey.d.cts → models-DnY24W7g.d.mts} +671 -51
- package/dist/models-DnY24W7g.d.mts.map +1 -0
- package/dist/{models-pdZgmVG-.d.mts → models-i5yDo5sm.d.cts} +671 -51
- package/dist/models-i5yDo5sm.d.cts.map +1 -0
- package/package.json +4 -2
- package/dist/models-IotBovey.d.cts.map +0 -1
- package/dist/models-pdZgmVG-.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -52,3 +52,57 @@ const polar = createPolarCore({
|
|
|
52
52
|
const customerState = await getStateExternalCustomers(polar)("customer_external_id");
|
|
53
53
|
console.log(customerState);
|
|
54
54
|
```
|
|
55
|
+
|
|
56
|
+
## Webhooks
|
|
57
|
+
|
|
58
|
+
Use `webhooks.validateEvent` to verify that a webhook was sent by Polar and parse it into a typed
|
|
59
|
+
payload for the selected API version. Pass the raw request body, the request headers, and your
|
|
60
|
+
webhook signing secret:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import express from "express";
|
|
64
|
+
import { webhooks } from "@polar-sh/sdk/2026-04";
|
|
65
|
+
|
|
66
|
+
const app = express();
|
|
67
|
+
const webhookSecret = process.env.POLAR_WEBHOOK_SECRET;
|
|
68
|
+
|
|
69
|
+
if (!webhookSecret) {
|
|
70
|
+
throw new Error("POLAR_WEBHOOK_SECRET is required");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const rawBody = express.raw({ type: "application/json" });
|
|
74
|
+
app.post("/webhooks/polar", rawBody, async (request, response) => {
|
|
75
|
+
try {
|
|
76
|
+
const event = await webhooks.validateEvent(
|
|
77
|
+
request.body,
|
|
78
|
+
{
|
|
79
|
+
"webhook-id": request.header("webhook-id") ?? "",
|
|
80
|
+
"webhook-timestamp": request.header("webhook-timestamp") ?? "",
|
|
81
|
+
"webhook-signature": request.header("webhook-signature") ?? "",
|
|
82
|
+
},
|
|
83
|
+
webhookSecret,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (event.type === "order.created") {
|
|
87
|
+
console.log(event.data.id);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
response.status(200).json({ received: true });
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (error instanceof webhooks.PolarWebhookVerificationError) {
|
|
93
|
+
response.status(403).json({ error: "Invalid webhook signature" });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (error instanceof webhooks.PolarWebhookError) {
|
|
97
|
+
response.status(400).json({ error: "Invalid webhook payload" });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The `express.raw` middleware is required because the signature must be checked against the body
|
|
106
|
+
before it is parsed. `validateEvent` throws `PolarWebhookVerificationError` for invalid signatures
|
|
107
|
+
and `PolarWebhookUnknownTypeError` when the event is not supported by the selected API version.
|
|
108
|
+
Both inherit from `PolarWebhookError`.
|
package/dist/2026-04/index.cjs
CHANGED
|
@@ -76,6 +76,132 @@ function createPolar(options) {
|
|
|
76
76
|
//#region src/2026-04/models.ts
|
|
77
77
|
var models_exports = /* @__PURE__ */ require_errors.__exportAll({});
|
|
78
78
|
//#endregion
|
|
79
|
+
//#region src/webhooks.ts
|
|
80
|
+
const webhookToleranceSeconds = 300;
|
|
81
|
+
var PolarWebhookError = class extends require_base.PolarError {
|
|
82
|
+
constructor(message, options) {
|
|
83
|
+
super(message, options);
|
|
84
|
+
this.name = "PolarWebhookError";
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var PolarWebhookVerificationError = class extends PolarWebhookError {
|
|
88
|
+
constructor(message, options) {
|
|
89
|
+
super(message, options);
|
|
90
|
+
this.name = "PolarWebhookVerificationError";
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var PolarWebhookUnknownTypeError = class extends PolarWebhookError {
|
|
94
|
+
eventType;
|
|
95
|
+
constructor(eventType) {
|
|
96
|
+
super(`Unknown webhook event type: ${JSON.stringify(eventType)}`);
|
|
97
|
+
this.eventType = eventType;
|
|
98
|
+
this.name = "PolarWebhookUnknownTypeError";
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const validateWebhook = async (body, headers, secret, eventTypes) => {
|
|
102
|
+
const bodyText = typeof body === "string" ? body : new TextDecoder().decode(body);
|
|
103
|
+
await verifySignature(bodyText, headers, secret);
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = JSON.parse(bodyText);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new PolarWebhookError("Failed to parse webhook payload", { cause: error });
|
|
109
|
+
}
|
|
110
|
+
const eventType = typeof parsed === "object" && parsed !== null && "type" in parsed && typeof parsed.type === "string" ? parsed.type : null;
|
|
111
|
+
if (eventType === null || !eventTypes.has(eventType)) throw new PolarWebhookUnknownTypeError(eventType);
|
|
112
|
+
return parsed;
|
|
113
|
+
};
|
|
114
|
+
const verifySignature = async (body, headers, secret) => {
|
|
115
|
+
if (secret.length === 0) throw new PolarWebhookVerificationError("Secret can't be empty");
|
|
116
|
+
const normalizedHeaders = Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
|
|
117
|
+
const webhookId = normalizedHeaders["webhook-id"];
|
|
118
|
+
const webhookTimestamp = normalizedHeaders["webhook-timestamp"];
|
|
119
|
+
const webhookSignature = normalizedHeaders["webhook-signature"];
|
|
120
|
+
if (!webhookId || !webhookTimestamp || !webhookSignature) throw new PolarWebhookVerificationError("Missing required headers");
|
|
121
|
+
const timestamp = Number(webhookTimestamp);
|
|
122
|
+
if (!Number.isFinite(timestamp)) throw new PolarWebhookVerificationError("Invalid signature headers");
|
|
123
|
+
const now = Date.now() / 1e3;
|
|
124
|
+
if (timestamp < now - webhookToleranceSeconds) throw new PolarWebhookVerificationError("Message timestamp too old");
|
|
125
|
+
if (timestamp > now + webhookToleranceSeconds) throw new PolarWebhookVerificationError("Message timestamp too new");
|
|
126
|
+
const signedContent = `${webhookId}.${Math.floor(timestamp)}.${body}`;
|
|
127
|
+
const textEncoder = new TextEncoder();
|
|
128
|
+
const signedContentBytes = textEncoder.encode(signedContent);
|
|
129
|
+
const signingKey = await globalThis.crypto.subtle.importKey("raw", textEncoder.encode(secret), {
|
|
130
|
+
name: "HMAC",
|
|
131
|
+
hash: "SHA-256"
|
|
132
|
+
}, false, ["verify"]);
|
|
133
|
+
for (const versionedSignature of webhookSignature.split(" ")) {
|
|
134
|
+
const [version, signature] = versionedSignature.split(",", 2);
|
|
135
|
+
if (version !== "v1" || signature === void 0) continue;
|
|
136
|
+
const decodedSignature = decodeBase64(signature);
|
|
137
|
+
if (decodedSignature !== null && await globalThis.crypto.subtle.verify("HMAC", signingKey, decodedSignature, signedContentBytes)) return;
|
|
138
|
+
}
|
|
139
|
+
throw new PolarWebhookVerificationError("No matching signature found");
|
|
140
|
+
};
|
|
141
|
+
const decodeBase64 = (value) => {
|
|
142
|
+
try {
|
|
143
|
+
const decodedValue = globalThis.atob(value);
|
|
144
|
+
const bytes = new Uint8Array(new ArrayBuffer(decodedValue.length));
|
|
145
|
+
for (let index = 0; index < decodedValue.length; index++) bytes[index] = decodedValue.charCodeAt(index);
|
|
146
|
+
return bytes;
|
|
147
|
+
} catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/2026-04/webhooks.ts
|
|
153
|
+
var webhooks_exports = /* @__PURE__ */ require_errors.__exportAll({
|
|
154
|
+
PolarWebhookError: () => PolarWebhookError,
|
|
155
|
+
PolarWebhookUnknownTypeError: () => PolarWebhookUnknownTypeError,
|
|
156
|
+
PolarWebhookVerificationError: () => PolarWebhookVerificationError,
|
|
157
|
+
validateEvent: () => validateEvent
|
|
158
|
+
});
|
|
159
|
+
const knownEventTypes = /* @__PURE__ */ new Set([
|
|
160
|
+
"benefit.created",
|
|
161
|
+
"benefit.updated",
|
|
162
|
+
"benefit_grant.created",
|
|
163
|
+
"benefit_grant.cycled",
|
|
164
|
+
"benefit_grant.revoked",
|
|
165
|
+
"benefit_grant.updated",
|
|
166
|
+
"checkout.created",
|
|
167
|
+
"checkout.expired",
|
|
168
|
+
"checkout.updated",
|
|
169
|
+
"customer.created",
|
|
170
|
+
"customer.deleted",
|
|
171
|
+
"customer.state_changed",
|
|
172
|
+
"customer.updated",
|
|
173
|
+
"customer_seat.assigned",
|
|
174
|
+
"customer_seat.claimed",
|
|
175
|
+
"customer_seat.revoked",
|
|
176
|
+
"member.created",
|
|
177
|
+
"member.deleted",
|
|
178
|
+
"member.updated",
|
|
179
|
+
"order.created",
|
|
180
|
+
"order.paid",
|
|
181
|
+
"order.refunded",
|
|
182
|
+
"order.updated",
|
|
183
|
+
"organization.updated",
|
|
184
|
+
"product.created",
|
|
185
|
+
"product.updated",
|
|
186
|
+
"refund.created",
|
|
187
|
+
"refund.updated",
|
|
188
|
+
"subscription.active",
|
|
189
|
+
"subscription.canceled",
|
|
190
|
+
"subscription.created",
|
|
191
|
+
"subscription.past_due",
|
|
192
|
+
"subscription.paused",
|
|
193
|
+
"subscription.resumed",
|
|
194
|
+
"subscription.revoked",
|
|
195
|
+
"subscription.uncanceled",
|
|
196
|
+
"subscription.updated"
|
|
197
|
+
]);
|
|
198
|
+
/**
|
|
199
|
+
* Verify a raw Polar webhook request and return its typed payload.
|
|
200
|
+
*/
|
|
201
|
+
const validateEvent = (body, headers, secret) => {
|
|
202
|
+
return validateWebhook(body, headers, secret, knownEventTypes);
|
|
203
|
+
};
|
|
204
|
+
//#endregion
|
|
79
205
|
exports.createPolar = createPolar;
|
|
80
206
|
exports.createPolarCore = createPolarCore;
|
|
81
207
|
Object.defineProperty(exports, "errors", {
|
|
@@ -90,5 +216,11 @@ Object.defineProperty(exports, "models", {
|
|
|
90
216
|
return models_exports;
|
|
91
217
|
}
|
|
92
218
|
});
|
|
219
|
+
Object.defineProperty(exports, "webhooks", {
|
|
220
|
+
enumerable: true,
|
|
221
|
+
get: function() {
|
|
222
|
+
return webhooks_exports;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
93
225
|
|
|
94
226
|
//# sourceMappingURL=index.cjs.map
|