@wefunder/sdk 0.1.0-beta.7 → 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,21 +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,
1163
+ getPortfolio: () => getPortfolio,
1151
1164
  getSyndicate: () => getSyndicate,
1152
1165
  getSyndicateDeal: () => getSyndicateDeal,
1166
+ getSyndicatePortfolio: () => getSyndicatePortfolio,
1153
1167
  getSyndicateStatistics: () => getSyndicateStatistics,
1168
+ getWebhookEndpoint: () => getWebhookEndpoint,
1154
1169
  getWebhookSubscription: () => getWebhookSubscription,
1155
1170
  hideSyndicateMember: () => hideSyndicateMember,
1156
1171
  inviteSyndicateMember: () => inviteSyndicateMember,
@@ -1158,19 +1173,30 @@ __export(sdk_gen_exports, {
1158
1173
  listAttributedInvestments: () => listAttributedInvestments,
1159
1174
  listAttributionCampaigns: () => listAttributionCampaigns,
1160
1175
  listCampaigns: () => listCampaigns,
1176
+ listCompanyQuestions: () => listCompanyQuestions,
1177
+ listCompanyUpdates: () => listCompanyUpdates,
1161
1178
  listConnectedApps: () => listConnectedApps,
1179
+ listEligibleInstallTargets: () => listEligibleInstallTargets,
1180
+ listFollowedCompanies: () => listFollowedCompanies,
1181
+ listInstallations: () => listInstallations,
1162
1182
  listIntents: () => listIntents,
1163
1183
  listInvestments: () => listInvestments,
1184
+ listMyCompanies: () => listMyCompanies,
1164
1185
  listOfferings: () => listOfferings,
1165
1186
  listPartnerInvites: () => listPartnerInvites,
1187
+ listPortfolioPositions: () => listPortfolioPositions,
1166
1188
  listSyndicateDealInvestors: () => listSyndicateDealInvestors,
1167
1189
  listSyndicateDeals: () => listSyndicateDeals,
1168
1190
  listSyndicateMemberInvestments: () => listSyndicateMemberInvestments,
1169
1191
  listSyndicateMembers: () => listSyndicateMembers,
1192
+ listSyndicatePortfolioPositions: () => listSyndicatePortfolioPositions,
1170
1193
  listSyndicates: () => listSyndicates,
1194
+ listWebhookEndpoints: () => listWebhookEndpoints,
1171
1195
  listWebhookSubscriptions: () => listWebhookSubscriptions,
1196
+ previewIntent: () => previewIntent,
1172
1197
  promoteSyndicateMember: () => promoteSyndicateMember,
1173
1198
  reactivateWebhookSubscription: () => reactivateWebhookSubscription,
1199
+ reenableWebhookEndpoint: () => reenableWebhookEndpoint,
1174
1200
  regenerateWebhookSecret: () => regenerateWebhookSecret,
1175
1201
  registerAsPartner: () => registerAsPartner,
1176
1202
  removeSyndicateMember: () => removeSyndicateMember,
@@ -1178,10 +1204,16 @@ __export(sdk_gen_exports, {
1178
1204
  resendSyndicateInvite: () => resendSyndicateInvite,
1179
1205
  restoreSyndicateMember: () => restoreSyndicateMember,
1180
1206
  revokeConnectedApp: () => revokeConnectedApp,
1207
+ revokeInstallation: () => revokeInstallation,
1181
1208
  revokePartnerInvite: () => revokePartnerInvite,
1209
+ rotateWebhookEndpointSecret: () => rotateWebhookEndpointSecret,
1210
+ searchCompanies: () => searchCompanies,
1211
+ testWebhookEndpoint: () => testWebhookEndpoint,
1182
1212
  testWebhookSubscription: () => testWebhookSubscription,
1213
+ unfollowCompany: () => unfollowCompany,
1183
1214
  updateSyndicate: () => updateSyndicate,
1184
- updateSyndicateMember: () => updateSyndicateMember
1215
+ updateSyndicateMember: () => updateSyndicateMember,
1216
+ updateWebhookEndpoint: () => updateWebhookEndpoint
1185
1217
  });
1186
1218
 
1187
1219
  // src/generated/client.gen.ts
@@ -1189,6 +1221,12 @@ var client = createClient(createConfig());
1189
1221
 
1190
1222
  // src/generated/sdk.gen.ts
1191
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
+ },
1192
1230
  security: [{ scheme: "bearer", type: "http" }],
1193
1231
  url: "/explore",
1194
1232
  ...options
@@ -1198,16 +1236,97 @@ var getOffering = (options) => (options.client ?? client).get({
1198
1236
  url: "/offerings/{external_id}",
1199
1237
  ...options
1200
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
+ });
1201
1280
  var getCurrentUser = (options) => (options?.client ?? client).get({
1202
1281
  security: [{ scheme: "bearer", type: "http" }],
1203
1282
  url: "/users/me",
1204
1283
  ...options
1205
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
+ });
1206
1305
  var listInvestments = (options) => (options?.client ?? client).get({
1207
1306
  security: [{ scheme: "bearer", type: "http" }],
1208
1307
  url: "/investments",
1209
1308
  ...options
1210
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
+ });
1320
+ var getPortfolio = (options) => (options?.client ?? client).get({
1321
+ security: [{ scheme: "bearer", type: "http" }],
1322
+ url: "/portfolio",
1323
+ ...options
1324
+ });
1325
+ var listPortfolioPositions = (options) => (options?.client ?? client).get({
1326
+ security: [{ scheme: "bearer", type: "http" }],
1327
+ url: "/portfolio/positions",
1328
+ ...options
1329
+ });
1211
1330
  var listCampaigns = (options) => (options?.client ?? client).get({
1212
1331
  security: [{ scheme: "bearer", type: "http" }],
1213
1332
  url: "/campaigns",
@@ -1329,6 +1448,16 @@ var getSyndicateStatistics = (options) => (options.client ?? client).get({
1329
1448
  url: "/syndicates/{syndicate_id}/statistics",
1330
1449
  ...options
1331
1450
  });
1451
+ var getSyndicatePortfolio = (options) => (options.client ?? client).get({
1452
+ security: [{ scheme: "bearer", type: "http" }],
1453
+ url: "/syndicates/{syndicate_id}/portfolio",
1454
+ ...options
1455
+ });
1456
+ var listSyndicatePortfolioPositions = (options) => (options.client ?? client).get({
1457
+ security: [{ scheme: "bearer", type: "http" }],
1458
+ url: "/syndicates/{syndicate_id}/portfolio/positions",
1459
+ ...options
1460
+ });
1332
1461
  var closeSyndicateDeal = (options) => (options.client ?? client).post({
1333
1462
  security: [{ scheme: "bearer", type: "http" }],
1334
1463
  url: "/syndicates/{syndicate_id}/deals/{fundraise_id}/close",
@@ -1339,6 +1468,15 @@ var finalizeSyndicateDeal = (options) => (options.client ?? client).post({
1339
1468
  url: "/syndicates/{syndicate_id}/deals/{fundraise_id}/finalize",
1340
1469
  ...options
1341
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
+ });
1342
1480
  var listIntents = (options) => (options?.client ?? client).get({
1343
1481
  security: [{ scheme: "bearer", type: "http" }],
1344
1482
  url: "/intents",
@@ -1383,6 +1521,96 @@ var listAttributedInvestments = (options) => (options.client ?? client).get({
1383
1521
  url: "/campaigns/{campaign_id}/attribution/investments",
1384
1522
  ...options
1385
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
+ });
1386
1614
  var listWebhookSubscriptions = (options) => (options.client ?? client).get({
1387
1615
  security: [{ scheme: "bearer", type: "http" }],
1388
1616
  url: "/campaigns/{campaign_id}/attribution/webhooks",
@@ -1600,10 +1828,27 @@ var Wefunder = class _Wefunder {
1600
1828
  getOffering({ client: this.#client, path: { external_id: externalId } })
1601
1829
  )
1602
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
+ */
1603
1836
  investments = {
1604
1837
  list: this.#page(listInvestments),
1605
- all: () => paginate((cursor) => this.investments.list({ cursor })),
1606
- 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 } }))
1842
+ };
1843
+ portfolio = {
1844
+ get: (query) => this.#unwrapData(getPortfolio({ client: this.#client, query })),
1845
+ positions: {
1846
+ list: this.#page(
1847
+ listPortfolioPositions
1848
+ ),
1849
+ all: (query) => paginate((cursor) => this.portfolio.positions.list({ ...query, cursor })),
1850
+ collect: (query) => collect((cursor) => this.portfolio.positions.list({ ...query, cursor }))
1851
+ }
1607
1852
  };
1608
1853
  campaigns = {
1609
1854
  list: this.#page(listCampaigns),
@@ -1623,17 +1868,76 @@ var Wefunder = class _Wefunder {
1623
1868
  attribution = {
1624
1869
  me: () => this.#unwrapData(getAttributionMe({ client: this.#client }))
1625
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
+ };
1626
1918
  };
1627
1919
 
1628
1920
  // src/webhooks.ts
1629
1921
  import { createHmac, timingSafeEqual } from "crypto";
1630
- var SIGNATURE_HEADER = "x-wefunder-signature";
1631
- var TIMESTAMP_HEADER = "x-wefunder-timestamp";
1632
- var EVENT_HEADER = "x-wefunder-event";
1633
- var DELIVERY_ID_HEADER = "x-wefunder-delivery-id";
1634
- function computeSignature(secret, timestamp, payload) {
1635
- const mac = createHmac("sha256", secret).update(`${timestamp}.${payload}`).digest("hex");
1636
- 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");
1637
1941
  }
1638
1942
  function constantTimeEqual(a, b) {
1639
1943
  const ab = Buffer.from(a);
@@ -1641,66 +1945,175 @@ function constantTimeEqual(a, b) {
1641
1945
  if (ab.length !== bb.length) return false;
1642
1946
  return timingSafeEqual(ab, bb);
1643
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
+ }
1644
1983
  function verifyWebhook(opts) {
1645
- const tolerance = opts.toleranceSeconds ?? 300;
1646
- 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;
1647
1989
  const ts = Number(opts.timestamp);
1648
1990
  if (!Number.isFinite(ts)) return false;
1649
- if (tolerance > 0 && Math.abs(now / 1e3 - ts) > tolerance) return false;
1650
- 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)}`;
1651
1993
  return constantTimeEqual(opts.signature, expected);
1652
1994
  }
1653
- function constructEvent(payload, headers, secret, opts) {
1654
- const get = (name) => {
1655
- if (headers instanceof Headers) return headers.get(name) ?? void 0;
1656
- 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
+ }
1657
2006
  return Array.isArray(v) ? v[0] : v;
1658
2007
  };
1659
- const signature = get(SIGNATURE_HEADER);
1660
- const timestamp = get(TIMESTAMP_HEADER);
1661
- if (!signature || !timestamp) {
1662
- throw new Error("Missing X-Wefunder-Signature or X-Wefunder-Timestamp header");
1663
- }
1664
- const ok = verifyWebhook({
1665
- payload,
1666
- signature,
1667
- timestamp,
1668
- secret,
1669
- toleranceSeconds: opts?.toleranceSeconds,
1670
- now: opts?.now
1671
- });
1672
- 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);
1673
2022
  return {
1674
- event: get(EVENT_HEADER) ?? "",
1675
- deliveryId: get(DELIVERY_ID_HEADER) ?? "",
1676
- timestamp: Number(timestamp),
1677
- 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
1678
2029
  };
1679
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
+ }
1680
2084
  export {
1681
2085
  DEFAULT_API_BASE_URL,
1682
2086
  DEFAULT_API_VERSION,
1683
2087
  DEFAULT_AUTHORIZE_BASE_URL,
1684
2088
  DEFAULT_OAUTH_BASE_URL,
1685
2089
  DEFAULT_TOKEN_BASE_URL,
1686
- DELIVERY_ID_HEADER,
1687
- EVENT_HEADER,
2090
+ DEFAULT_TOLERANCE_SECONDS,
2091
+ LEGACY_DELIVERY_ID_HEADER,
2092
+ LEGACY_EVENT_HEADER,
2093
+ LEGACY_SIGNATURE_HEADER,
2094
+ LEGACY_TIMESTAMP_HEADER,
1688
2095
  REQUEST_ID_HEADER,
1689
2096
  SANDBOX_AUTHORIZE_BASE_URL,
1690
2097
  SIGNATURE_HEADER,
1691
- TIMESTAMP_HEADER,
2098
+ WebhookSignatureError,
1692
2099
  Wefunder,
1693
2100
  WefunderAuthError,
1694
2101
  WefunderError,
2102
+ checkWebhookSignature,
1695
2103
  clientCredentialsGrant,
1696
2104
  collect,
2105
+ computeWebhookSignature,
1697
2106
  constructEvent,
2107
+ constructEventFromRequest,
1698
2108
  createAuthorizationUrl,
2109
+ dispatchWebhook,
1699
2110
  exchangeCode,
1700
2111
  generatePkce,
1701
2112
  modeForToken,
1702
2113
  paginate,
2114
+ parseSignatureHeader,
1703
2115
  refreshToken,
2116
+ signWebhook,
1704
2117
  verifyWebhook
1705
2118
  };
1706
2119
  //# sourceMappingURL=index.js.map