@wefunder/sdk 0.1.0-beta.8 → 0.1.0-beta.9

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.js CHANGED
@@ -1136,23 +1136,36 @@ var sdk_gen_exports = {};
1136
1136
  __export(sdk_gen_exports, {
1137
1137
  approveSyndicateMember: () => approveSyndicateMember,
1138
1138
  closeSyndicateDeal: () => closeSyndicateDeal,
1139
+ createInstallation: () => createInstallation,
1140
+ createInstallationToken: () => createInstallationToken,
1139
1141
  createIntent: () => createIntent,
1140
1142
  createPartnerInvite: () => createPartnerInvite,
1143
+ createWebhookEndpoint: () => createWebhookEndpoint,
1141
1144
  createWebhookSubscription: () => createWebhookSubscription,
1145
+ deleteWebhookEndpoint: () => deleteWebhookEndpoint,
1142
1146
  deleteWebhookSubscription: () => deleteWebhookSubscription,
1143
1147
  demoteSyndicateMember: () => demoteSyndicateMember,
1144
1148
  exportSyndicateMembersCsv: () => exportSyndicateMembersCsv,
1145
1149
  finalizeSyndicateDeal: () => finalizeSyndicateDeal,
1150
+ followCompany: () => followCompany,
1146
1151
  getAttributionMe: () => getAttributionMe,
1147
1152
  getAttributionStats: () => getAttributionStats,
1153
+ getCompany: () => getCompany,
1154
+ getCompanyDisclosures: () => getCompanyDisclosures,
1155
+ getCompanyPitch: () => getCompanyPitch,
1156
+ getCompanyUpdate: () => getCompanyUpdate,
1148
1157
  getCurrentUser: () => getCurrentUser,
1158
+ getInstallation: () => getInstallation,
1149
1159
  getIntent: () => getIntent,
1160
+ getInvestment: () => getInvestment,
1150
1161
  getOffering: () => getOffering,
1162
+ getOfferingStats: () => getOfferingStats,
1151
1163
  getPortfolio: () => getPortfolio,
1152
1164
  getSyndicate: () => getSyndicate,
1153
1165
  getSyndicateDeal: () => getSyndicateDeal,
1154
1166
  getSyndicatePortfolio: () => getSyndicatePortfolio,
1155
1167
  getSyndicateStatistics: () => getSyndicateStatistics,
1168
+ getWebhookEndpoint: () => getWebhookEndpoint,
1156
1169
  getWebhookSubscription: () => getWebhookSubscription,
1157
1170
  hideSyndicateMember: () => hideSyndicateMember,
1158
1171
  inviteSyndicateMember: () => inviteSyndicateMember,
@@ -1160,9 +1173,15 @@ __export(sdk_gen_exports, {
1160
1173
  listAttributedInvestments: () => listAttributedInvestments,
1161
1174
  listAttributionCampaigns: () => listAttributionCampaigns,
1162
1175
  listCampaigns: () => listCampaigns,
1176
+ listCompanyQuestions: () => listCompanyQuestions,
1177
+ listCompanyUpdates: () => listCompanyUpdates,
1163
1178
  listConnectedApps: () => listConnectedApps,
1179
+ listEligibleInstallTargets: () => listEligibleInstallTargets,
1180
+ listFollowedCompanies: () => listFollowedCompanies,
1181
+ listInstallations: () => listInstallations,
1164
1182
  listIntents: () => listIntents,
1165
1183
  listInvestments: () => listInvestments,
1184
+ listMyCompanies: () => listMyCompanies,
1166
1185
  listOfferings: () => listOfferings,
1167
1186
  listPartnerInvites: () => listPartnerInvites,
1168
1187
  listPortfolioPositions: () => listPortfolioPositions,
@@ -1172,9 +1191,12 @@ __export(sdk_gen_exports, {
1172
1191
  listSyndicateMembers: () => listSyndicateMembers,
1173
1192
  listSyndicatePortfolioPositions: () => listSyndicatePortfolioPositions,
1174
1193
  listSyndicates: () => listSyndicates,
1194
+ listWebhookEndpoints: () => listWebhookEndpoints,
1175
1195
  listWebhookSubscriptions: () => listWebhookSubscriptions,
1196
+ previewIntent: () => previewIntent,
1176
1197
  promoteSyndicateMember: () => promoteSyndicateMember,
1177
1198
  reactivateWebhookSubscription: () => reactivateWebhookSubscription,
1199
+ reenableWebhookEndpoint: () => reenableWebhookEndpoint,
1178
1200
  regenerateWebhookSecret: () => regenerateWebhookSecret,
1179
1201
  registerAsPartner: () => registerAsPartner,
1180
1202
  removeSyndicateMember: () => removeSyndicateMember,
@@ -1182,10 +1204,16 @@ __export(sdk_gen_exports, {
1182
1204
  resendSyndicateInvite: () => resendSyndicateInvite,
1183
1205
  restoreSyndicateMember: () => restoreSyndicateMember,
1184
1206
  revokeConnectedApp: () => revokeConnectedApp,
1207
+ revokeInstallation: () => revokeInstallation,
1185
1208
  revokePartnerInvite: () => revokePartnerInvite,
1209
+ rotateWebhookEndpointSecret: () => rotateWebhookEndpointSecret,
1210
+ searchCompanies: () => searchCompanies,
1211
+ testWebhookEndpoint: () => testWebhookEndpoint,
1186
1212
  testWebhookSubscription: () => testWebhookSubscription,
1213
+ unfollowCompany: () => unfollowCompany,
1187
1214
  updateSyndicate: () => updateSyndicate,
1188
- updateSyndicateMember: () => updateSyndicateMember
1215
+ updateSyndicateMember: () => updateSyndicateMember,
1216
+ updateWebhookEndpoint: () => updateWebhookEndpoint
1189
1217
  });
1190
1218
 
1191
1219
  // src/generated/client.gen.ts
@@ -1193,6 +1221,12 @@ var client = createClient(createConfig());
1193
1221
 
1194
1222
  // src/generated/sdk.gen.ts
1195
1223
  var listOfferings = (options) => (options?.client ?? client).get({
1224
+ querySerializer: {
1225
+ parameters: {
1226
+ industry: { array: { explode: false } },
1227
+ business_model: { array: { explode: false } }
1228
+ }
1229
+ },
1196
1230
  security: [{ scheme: "bearer", type: "http" }],
1197
1231
  url: "/explore",
1198
1232
  ...options
@@ -1202,16 +1236,87 @@ var getOffering = (options) => (options.client ?? client).get({
1202
1236
  url: "/offerings/{external_id}",
1203
1237
  ...options
1204
1238
  });
1239
+ var getCompanyDisclosures = (options) => (options.client ?? client).get({
1240
+ querySerializer: {
1241
+ parameters: { sections: { array: { explode: false } } }
1242
+ },
1243
+ security: [{ scheme: "bearer", type: "http" }],
1244
+ url: "/companies/{id}/disclosures",
1245
+ ...options
1246
+ });
1247
+ var getCompanyPitch = (options) => (options.client ?? client).get({
1248
+ querySerializer: {
1249
+ parameters: { sections: { array: { explode: false } } }
1250
+ },
1251
+ security: [{ scheme: "bearer", type: "http" }],
1252
+ url: "/companies/{id}/pitch",
1253
+ ...options
1254
+ });
1255
+ var listCompanyUpdates = (options) => (options.client ?? client).get({
1256
+ security: [{ scheme: "bearer", type: "http" }],
1257
+ url: "/companies/{id}/updates",
1258
+ ...options
1259
+ });
1260
+ var getCompanyUpdate = (options) => (options.client ?? client).get({
1261
+ security: [{ scheme: "bearer", type: "http" }],
1262
+ url: "/companies/{id}/updates/{update_id}",
1263
+ ...options
1264
+ });
1265
+ var listCompanyQuestions = (options) => (options.client ?? client).get({
1266
+ security: [{ scheme: "bearer", type: "http" }],
1267
+ url: "/companies/{id}/questions",
1268
+ ...options
1269
+ });
1270
+ var searchCompanies = (options) => (options.client ?? client).get({
1271
+ security: [{ scheme: "bearer", type: "http" }],
1272
+ url: "/companies/search",
1273
+ ...options
1274
+ });
1275
+ var getCompany = (options) => (options.client ?? client).get({
1276
+ security: [{ scheme: "bearer", type: "http" }],
1277
+ url: "/companies/{id}",
1278
+ ...options
1279
+ });
1205
1280
  var getCurrentUser = (options) => (options?.client ?? client).get({
1206
1281
  security: [{ scheme: "bearer", type: "http" }],
1207
1282
  url: "/users/me",
1208
1283
  ...options
1209
1284
  });
1285
+ var listMyCompanies = (options) => (options?.client ?? client).get({
1286
+ security: [{ scheme: "bearer", type: "http" }],
1287
+ url: "/users/me/companies",
1288
+ ...options
1289
+ });
1290
+ var listFollowedCompanies = (options) => (options?.client ?? client).get({
1291
+ security: [{ scheme: "bearer", type: "http" }],
1292
+ url: "/users/me/follows",
1293
+ ...options
1294
+ });
1295
+ var unfollowCompany = (options) => (options.client ?? client).delete({
1296
+ security: [{ scheme: "bearer", type: "http" }],
1297
+ url: "/users/me/follows/{company_id}",
1298
+ ...options
1299
+ });
1300
+ var followCompany = (options) => (options.client ?? client).put({
1301
+ security: [{ scheme: "bearer", type: "http" }],
1302
+ url: "/users/me/follows/{company_id}",
1303
+ ...options
1304
+ });
1210
1305
  var listInvestments = (options) => (options?.client ?? client).get({
1211
1306
  security: [{ scheme: "bearer", type: "http" }],
1212
1307
  url: "/investments",
1213
1308
  ...options
1214
1309
  });
1310
+ var getInvestment = (options) => (options.client ?? client).get({
1311
+ security: [{ scheme: "bearer", type: "http" }],
1312
+ url: "/investments/{id}",
1313
+ ...options
1314
+ });
1315
+ var getOfferingStats = (options) => (options.client ?? client).get({
1316
+ security: [{ scheme: "bearer", type: "http" }],
1317
+ url: "/offerings/{offering_id}/stats",
1318
+ ...options
1319
+ });
1215
1320
  var getPortfolio = (options) => (options?.client ?? client).get({
1216
1321
  security: [{ scheme: "bearer", type: "http" }],
1217
1322
  url: "/portfolio",
@@ -1363,6 +1468,15 @@ var finalizeSyndicateDeal = (options) => (options.client ?? client).post({
1363
1468
  url: "/syndicates/{syndicate_id}/deals/{fundraise_id}/finalize",
1364
1469
  ...options
1365
1470
  });
1471
+ var previewIntent = (options) => (options.client ?? client).post({
1472
+ security: [{ scheme: "bearer", type: "http" }],
1473
+ url: "/intents/preview",
1474
+ ...options,
1475
+ headers: {
1476
+ "Content-Type": "application/json",
1477
+ ...options.headers
1478
+ }
1479
+ });
1366
1480
  var listIntents = (options) => (options?.client ?? client).get({
1367
1481
  security: [{ scheme: "bearer", type: "http" }],
1368
1482
  url: "/intents",
@@ -1407,6 +1521,96 @@ var listAttributedInvestments = (options) => (options.client ?? client).get({
1407
1521
  url: "/campaigns/{campaign_id}/attribution/investments",
1408
1522
  ...options
1409
1523
  });
1524
+ var listInstallations = (options) => (options?.client ?? client).get({
1525
+ security: [{ scheme: "bearer", type: "http" }],
1526
+ url: "/installations",
1527
+ ...options
1528
+ });
1529
+ var createInstallation = (options) => (options.client ?? client).post({
1530
+ security: [{ scheme: "bearer", type: "http" }],
1531
+ url: "/installations",
1532
+ ...options,
1533
+ headers: {
1534
+ "Content-Type": "application/json",
1535
+ ...options.headers
1536
+ }
1537
+ });
1538
+ var listEligibleInstallTargets = (options) => (options?.client ?? client).get({
1539
+ security: [{ scheme: "bearer", type: "http" }],
1540
+ url: "/installations/eligible",
1541
+ ...options
1542
+ });
1543
+ var revokeInstallation = (options) => (options.client ?? client).delete({
1544
+ security: [{ scheme: "bearer", type: "http" }],
1545
+ url: "/installations/{external_id}",
1546
+ ...options
1547
+ });
1548
+ var getInstallation = (options) => (options.client ?? client).get({
1549
+ security: [{ scheme: "bearer", type: "http" }],
1550
+ url: "/installations/{external_id}",
1551
+ ...options
1552
+ });
1553
+ var createInstallationToken = (options) => (options.client ?? client).post({
1554
+ security: [{ scheme: "bearer", type: "http" }],
1555
+ url: "/installations/{external_id}/tokens",
1556
+ ...options,
1557
+ headers: {
1558
+ "Content-Type": "application/json",
1559
+ ...options.headers
1560
+ }
1561
+ });
1562
+ var listWebhookEndpoints = (options) => (options?.client ?? client).get({
1563
+ security: [{ scheme: "bearer", type: "http" }],
1564
+ url: "/webhook_endpoints",
1565
+ ...options
1566
+ });
1567
+ var createWebhookEndpoint = (options) => (options.client ?? client).post({
1568
+ security: [{ scheme: "bearer", type: "http" }],
1569
+ url: "/webhook_endpoints",
1570
+ ...options,
1571
+ headers: {
1572
+ "Content-Type": "application/json",
1573
+ ...options.headers
1574
+ }
1575
+ });
1576
+ var deleteWebhookEndpoint = (options) => (options.client ?? client).delete({
1577
+ security: [{ scheme: "bearer", type: "http" }],
1578
+ url: "/webhook_endpoints/{external_id}",
1579
+ ...options
1580
+ });
1581
+ var getWebhookEndpoint = (options) => (options.client ?? client).get({
1582
+ security: [{ scheme: "bearer", type: "http" }],
1583
+ url: "/webhook_endpoints/{external_id}",
1584
+ ...options
1585
+ });
1586
+ var updateWebhookEndpoint = (options) => (options.client ?? client).patch({
1587
+ security: [{ scheme: "bearer", type: "http" }],
1588
+ url: "/webhook_endpoints/{external_id}",
1589
+ ...options,
1590
+ headers: {
1591
+ "Content-Type": "application/json",
1592
+ ...options.headers
1593
+ }
1594
+ });
1595
+ var rotateWebhookEndpointSecret = (options) => (options.client ?? client).post({
1596
+ security: [{ scheme: "bearer", type: "http" }],
1597
+ url: "/webhook_endpoints/{external_id}/rotate_secret",
1598
+ ...options
1599
+ });
1600
+ var reenableWebhookEndpoint = (options) => (options.client ?? client).post({
1601
+ security: [{ scheme: "bearer", type: "http" }],
1602
+ url: "/webhook_endpoints/{external_id}/reenable",
1603
+ ...options
1604
+ });
1605
+ var testWebhookEndpoint = (options) => (options.client ?? client).post({
1606
+ security: [{ scheme: "bearer", type: "http" }],
1607
+ url: "/webhook_endpoints/{external_id}/test",
1608
+ ...options,
1609
+ headers: {
1610
+ "Content-Type": "application/json",
1611
+ ...options.headers
1612
+ }
1613
+ });
1410
1614
  var listWebhookSubscriptions = (options) => (options.client ?? client).get({
1411
1615
  security: [{ scheme: "bearer", type: "http" }],
1412
1616
  url: "/campaigns/{campaign_id}/attribution/webhooks",
@@ -1624,10 +1828,17 @@ var Wefunder = class _Wefunder {
1624
1828
  getOffering({ client: this.#client, path: { external_id: externalId } })
1625
1829
  )
1626
1830
  };
1831
+ /**
1832
+ * Investments (`read:investments`). `list` is a bootstrap listing; pass `updated_since`
1833
+ * or a saved `cursor` for sync mode (`meta.mode === "delta"`). Persist `meta.next_cursor`
1834
+ * from your last page — it is always present — and resume from it next time.
1835
+ */
1627
1836
  investments = {
1628
1837
  list: this.#page(listInvestments),
1629
- all: () => paginate((cursor) => this.investments.list({ cursor })),
1630
- collect: () => collect((cursor) => this.investments.list({ cursor }))
1838
+ all: (query) => paginate((cursor) => this.investments.list({ ...query, cursor })),
1839
+ collect: (query) => collect((cursor) => this.investments.list({ ...query, cursor })),
1840
+ /** The current record (not the published projection) for one investment (`inv_…`). */
1841
+ get: (id) => this.#unwrapData(getInvestment({ client: this.#client, path: { id } }))
1631
1842
  };
1632
1843
  portfolio = {
1633
1844
  get: (query) => this.#unwrapData(getPortfolio({ client: this.#client, query })),
@@ -1657,17 +1868,76 @@ var Wefunder = class _Wefunder {
1657
1868
  attribution = {
1658
1869
  me: () => this.#unwrapData(getAttributionMe({ client: this.#client }))
1659
1870
  };
1871
+ /**
1872
+ * Webhook endpoints (`/webhook_endpoints`, scopes `read:webhooks` / `write:webhooks`).
1873
+ * Endpoints belong to your application and are managed through the LIVE API —
1874
+ * create sandbox receivers there with `mode: "test"`; they're mirrored into
1875
+ * sandbox. The signing `secret` is returned ONLY by `create` and `rotateSecret`.
1876
+ * Verify deliveries with `constructEvent` (see the webhooks module).
1877
+ */
1878
+ webhookEndpoints = {
1879
+ /** All of your app's endpoints (secret omitted). `meta.quota` is the per-app limit. */
1880
+ list: () => this.#unwrap(listWebhookEndpoints({ client: this.#client })),
1881
+ get: (id) => this.#unwrapData(
1882
+ getWebhookEndpoint({ client: this.#client, path: { external_id: id } })
1883
+ ),
1884
+ /** Store `attributes.secret` from the result — it is never shown again. */
1885
+ create: (input) => this.#unwrapData(createWebhookEndpoint({ client: this.#client, body: input })),
1886
+ /** `events` replaces the subscription list wholesale (no merge); omit to leave unchanged. */
1887
+ update: (id, input) => this.#unwrapData(
1888
+ updateWebhookEndpoint({ client: this.#client, path: { external_id: id }, body: input })
1889
+ ),
1890
+ /** Stops deliveries immediately. Removal is permanent — create a new endpoint to resume. */
1891
+ remove: (id) => this.#unwrapData(
1892
+ deleteWebhookEndpoint({ client: this.#client, path: { external_id: id } })
1893
+ ),
1894
+ /**
1895
+ * New secret (shown once). The old one keeps signing for a 24h overlap — deliveries
1896
+ * carry a `v1` for both, and `constructEvent` accepts either.
1897
+ */
1898
+ rotateSecret: (id) => this.#unwrapData(
1899
+ rotateWebhookEndpointSecret({ client: this.#client, path: { external_id: id } })
1900
+ ),
1901
+ /** Recover an auto-disabled endpoint after fixing your server. Idempotent. */
1902
+ reenable: (id) => this.#unwrapData(
1903
+ reenableWebhookEndpoint({ client: this.#client, path: { external_id: id } })
1904
+ ),
1905
+ /**
1906
+ * POST a real, signed example event at the endpoint (production envelope + signature)
1907
+ * and report the outcome inline. Defaults to the endpoint's first subscribed event.
1908
+ * Doesn't affect delivery health. Rate-limited to 10/min per endpoint.
1909
+ */
1910
+ test: (id, event) => this.#unwrapData(
1911
+ testWebhookEndpoint({
1912
+ client: this.#client,
1913
+ path: { external_id: id },
1914
+ body: event ? { event } : void 0
1915
+ })
1916
+ )
1917
+ };
1660
1918
  };
1661
1919
 
1662
1920
  // src/webhooks.ts
1663
1921
  import { createHmac, timingSafeEqual } from "crypto";
1664
- var SIGNATURE_HEADER = "x-wefunder-signature";
1665
- var TIMESTAMP_HEADER = "x-wefunder-timestamp";
1666
- var EVENT_HEADER = "x-wefunder-event";
1667
- var DELIVERY_ID_HEADER = "x-wefunder-delivery-id";
1668
- function computeSignature(secret, timestamp, payload) {
1669
- const mac = createHmac("sha256", secret).update(`${timestamp}.${payload}`).digest("hex");
1670
- return `sha256=${mac}`;
1922
+ var SIGNATURE_HEADER = "wefunder-signature";
1923
+ var DEFAULT_TOLERANCE_SECONDS = 300;
1924
+ var LEGACY_SIGNATURE_HEADER = "x-wefunder-signature";
1925
+ var LEGACY_TIMESTAMP_HEADER = "x-wefunder-timestamp";
1926
+ var LEGACY_EVENT_HEADER = "x-wefunder-event";
1927
+ var LEGACY_DELIVERY_ID_HEADER = "x-wefunder-delivery-id";
1928
+ var WebhookSignatureError = class extends Error {
1929
+ reason;
1930
+ constructor(reason, message) {
1931
+ super(message);
1932
+ this.name = "WebhookSignatureError";
1933
+ this.reason = reason;
1934
+ }
1935
+ };
1936
+ function bodyBuffer(payload) {
1937
+ return typeof payload === "string" ? Buffer.from(payload, "utf8") : Buffer.from(payload);
1938
+ }
1939
+ function computeWebhookSignature(secret, timestamp, payload) {
1940
+ return createHmac("sha256", secret).update(`${timestamp}.`).update(bodyBuffer(payload)).digest("hex");
1671
1941
  }
1672
1942
  function constantTimeEqual(a, b) {
1673
1943
  const ab = Buffer.from(a);
@@ -1675,66 +1945,175 @@ function constantTimeEqual(a, b) {
1675
1945
  if (ab.length !== bb.length) return false;
1676
1946
  return timingSafeEqual(ab, bb);
1677
1947
  }
1948
+ function parseSignatureHeader(header) {
1949
+ let timestamp;
1950
+ const signatures = [];
1951
+ for (const part of header.split(",")) {
1952
+ const eq = part.indexOf("=");
1953
+ if (eq < 0) continue;
1954
+ const key = part.slice(0, eq).trim();
1955
+ const value = part.slice(eq + 1).trim();
1956
+ if (key === "t") {
1957
+ if (!/^\d+$/.test(value)) return null;
1958
+ timestamp = Number(value);
1959
+ } else if (key === "v1" && value) {
1960
+ signatures.push(value);
1961
+ }
1962
+ }
1963
+ if (timestamp === void 0 || signatures.length === 0) return null;
1964
+ return { timestamp, signatures };
1965
+ }
1966
+ function signWebhook(opts) {
1967
+ const t = opts.timestamp ?? Math.floor(Date.now() / 1e3);
1968
+ const secrets = [opts.secret, ...opts.additionalSecrets ?? []];
1969
+ const entries = secrets.map((s) => `v1=${computeWebhookSignature(s, t, opts.payload)}`);
1970
+ return [`t=${t}`, ...entries].join(",");
1971
+ }
1972
+ function checkWebhookSignature(opts) {
1973
+ const parsed = parseSignatureHeader(opts.header);
1974
+ if (!parsed) return "malformed_header";
1975
+ const tolerance = opts.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
1976
+ if (tolerance > 0) {
1977
+ const nowSec = (opts.now ?? Date.now)() / 1e3;
1978
+ if (Math.abs(nowSec - parsed.timestamp) > tolerance) return "timestamp_out_of_tolerance";
1979
+ }
1980
+ const expected = computeWebhookSignature(opts.secret, parsed.timestamp, opts.payload);
1981
+ return parsed.signatures.some((sig) => constantTimeEqual(sig, expected)) ? null : "signature_mismatch";
1982
+ }
1678
1983
  function verifyWebhook(opts) {
1679
- const tolerance = opts.toleranceSeconds ?? 300;
1680
- const now = (opts.now ?? Date.now)();
1984
+ if ("header" in opts) return checkWebhookSignature(opts) === null;
1985
+ return verifyLegacyWebhook(opts);
1986
+ }
1987
+ function verifyLegacyWebhook(opts) {
1988
+ const tolerance = opts.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
1681
1989
  const ts = Number(opts.timestamp);
1682
1990
  if (!Number.isFinite(ts)) return false;
1683
- if (tolerance > 0 && Math.abs(now / 1e3 - ts) > tolerance) return false;
1684
- const expected = computeSignature(opts.secret, opts.timestamp, opts.payload);
1991
+ if (tolerance > 0 && Math.abs((opts.now ?? Date.now)() / 1e3 - ts) > tolerance) return false;
1992
+ const expected = `sha256=${computeWebhookSignature(opts.secret, opts.timestamp, opts.payload)}`;
1685
1993
  return constantTimeEqual(opts.signature, expected);
1686
1994
  }
1687
- function constructEvent(payload, headers, secret, opts) {
1688
- const get = (name) => {
1689
- if (headers instanceof Headers) return headers.get(name) ?? void 0;
1690
- const v = headers[name] ?? headers[name.toLowerCase()];
1995
+ function headerGetter(headers) {
1996
+ if (typeof headers === "string") {
1997
+ return (name) => name === SIGNATURE_HEADER ? headers : void 0;
1998
+ }
1999
+ if (headers instanceof Headers) return (name) => headers.get(name) ?? void 0;
2000
+ return (name) => {
2001
+ let v = headers[name];
2002
+ if (v === void 0) {
2003
+ const hit = Object.keys(headers).find((k) => k.toLowerCase() === name);
2004
+ if (hit) v = headers[hit];
2005
+ }
1691
2006
  return Array.isArray(v) ? v[0] : v;
1692
2007
  };
1693
- const signature = get(SIGNATURE_HEADER);
1694
- const timestamp = get(TIMESTAMP_HEADER);
1695
- if (!signature || !timestamp) {
1696
- throw new Error("Missing X-Wefunder-Signature or X-Wefunder-Timestamp header");
1697
- }
1698
- const ok = verifyWebhook({
1699
- payload,
1700
- signature,
1701
- timestamp,
1702
- secret,
1703
- toleranceSeconds: opts?.toleranceSeconds,
1704
- now: opts?.now
1705
- });
1706
- if (!ok) throw new Error("Webhook signature verification failed");
2008
+ }
2009
+ function constructEvent(payload, headers, secret, opts) {
2010
+ const get = headerGetter(headers);
2011
+ const header = get(SIGNATURE_HEADER);
2012
+ if (!header) {
2013
+ const legacySig = get(LEGACY_SIGNATURE_HEADER);
2014
+ const legacyTs = get(LEGACY_TIMESTAMP_HEADER);
2015
+ if (legacySig && legacyTs) return constructLegacyEvent(payload, get, legacySig, legacyTs, secret, opts);
2016
+ throw new WebhookSignatureError("missing_header", describeFailure("missing_header"));
2017
+ }
2018
+ const failure = checkWebhookSignature({ payload, header, secret, ...opts });
2019
+ if (failure) throw new WebhookSignatureError(failure, describeFailure(failure));
2020
+ const parsed = parseSignatureHeader(header);
2021
+ const env = parseEnvelope(payload);
1707
2022
  return {
1708
- event: get(EVENT_HEADER) ?? "",
1709
- deliveryId: get(DELIVERY_ID_HEADER) ?? "",
1710
- timestamp: Number(timestamp),
1711
- data: JSON.parse(payload)
2023
+ id: String(env.id ?? ""),
2024
+ event: String(env.event ?? ""),
2025
+ created_at: String(env.created_at ?? ""),
2026
+ mode: env.mode === "test" ? "test" : "live",
2027
+ data: env.data,
2028
+ timestamp: parsed.timestamp
1712
2029
  };
1713
2030
  }
2031
+ function constructLegacyEvent(payload, get, signature, timestamp, secret, opts) {
2032
+ if (!verifyLegacyWebhook({ payload, signature, timestamp, secret, ...opts })) {
2033
+ throw new WebhookSignatureError("signature_mismatch", describeFailure("signature_mismatch"));
2034
+ }
2035
+ const env = parseEnvelope(payload);
2036
+ return {
2037
+ id: String(env.id ?? get(LEGACY_DELIVERY_ID_HEADER) ?? ""),
2038
+ event: String(env.event ?? get(LEGACY_EVENT_HEADER) ?? ""),
2039
+ created_at: String(env.created_at ?? ""),
2040
+ mode: env.mode === "test" ? "test" : "live",
2041
+ data: env.data ?? env,
2042
+ timestamp: Number(timestamp)
2043
+ };
2044
+ }
2045
+ function parseEnvelope(payload) {
2046
+ try {
2047
+ const parsed = JSON.parse(bodyBuffer(payload).toString("utf8"));
2048
+ if (parsed === null || typeof parsed !== "object") throw new Error("not an object");
2049
+ return parsed;
2050
+ } catch {
2051
+ throw new WebhookSignatureError("invalid_payload", describeFailure("invalid_payload"));
2052
+ }
2053
+ }
2054
+ function describeFailure(reason) {
2055
+ switch (reason) {
2056
+ case "missing_header":
2057
+ return "Missing Wefunder-Signature header";
2058
+ case "malformed_header":
2059
+ return "Wefunder-Signature header is malformed (expected t=<unix>,v1=<hex>)";
2060
+ case "timestamp_out_of_tolerance":
2061
+ return "Webhook timestamp is outside the replay tolerance";
2062
+ case "signature_mismatch":
2063
+ return "Webhook signature verification failed";
2064
+ case "invalid_payload":
2065
+ return "Webhook body is not a JSON object";
2066
+ }
2067
+ }
2068
+ async function constructEventFromRequest(request, secret, opts) {
2069
+ const payload = await request.text();
2070
+ return constructEvent(payload, request.headers, secret, opts);
2071
+ }
2072
+ async function dispatchWebhook(event, handlers) {
2073
+ const specific = event.event === "default" ? void 0 : handlers[event.event];
2074
+ if (specific) {
2075
+ await specific(event);
2076
+ return true;
2077
+ }
2078
+ if (handlers.default) {
2079
+ await handlers.default(event);
2080
+ return true;
2081
+ }
2082
+ return false;
2083
+ }
1714
2084
  export {
1715
2085
  DEFAULT_API_BASE_URL,
1716
2086
  DEFAULT_API_VERSION,
1717
2087
  DEFAULT_AUTHORIZE_BASE_URL,
1718
2088
  DEFAULT_OAUTH_BASE_URL,
1719
2089
  DEFAULT_TOKEN_BASE_URL,
1720
- DELIVERY_ID_HEADER,
1721
- EVENT_HEADER,
2090
+ DEFAULT_TOLERANCE_SECONDS,
2091
+ LEGACY_DELIVERY_ID_HEADER,
2092
+ LEGACY_EVENT_HEADER,
2093
+ LEGACY_SIGNATURE_HEADER,
2094
+ LEGACY_TIMESTAMP_HEADER,
1722
2095
  REQUEST_ID_HEADER,
1723
2096
  SANDBOX_AUTHORIZE_BASE_URL,
1724
2097
  SIGNATURE_HEADER,
1725
- TIMESTAMP_HEADER,
2098
+ WebhookSignatureError,
1726
2099
  Wefunder,
1727
2100
  WefunderAuthError,
1728
2101
  WefunderError,
2102
+ checkWebhookSignature,
1729
2103
  clientCredentialsGrant,
1730
2104
  collect,
2105
+ computeWebhookSignature,
1731
2106
  constructEvent,
2107
+ constructEventFromRequest,
1732
2108
  createAuthorizationUrl,
2109
+ dispatchWebhook,
1733
2110
  exchangeCode,
1734
2111
  generatePkce,
1735
2112
  modeForToken,
1736
2113
  paginate,
2114
+ parseSignatureHeader,
1737
2115
  refreshToken,
2116
+ signWebhook,
1738
2117
  verifyWebhook
1739
2118
  };
1740
2119
  //# sourceMappingURL=index.js.map