@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.cjs CHANGED
@@ -25,24 +25,33 @@ __export(index_exports, {
25
25
  DEFAULT_AUTHORIZE_BASE_URL: () => DEFAULT_AUTHORIZE_BASE_URL,
26
26
  DEFAULT_OAUTH_BASE_URL: () => DEFAULT_OAUTH_BASE_URL,
27
27
  DEFAULT_TOKEN_BASE_URL: () => DEFAULT_TOKEN_BASE_URL,
28
- DELIVERY_ID_HEADER: () => DELIVERY_ID_HEADER,
29
- EVENT_HEADER: () => EVENT_HEADER,
28
+ DEFAULT_TOLERANCE_SECONDS: () => DEFAULT_TOLERANCE_SECONDS,
29
+ LEGACY_DELIVERY_ID_HEADER: () => LEGACY_DELIVERY_ID_HEADER,
30
+ LEGACY_EVENT_HEADER: () => LEGACY_EVENT_HEADER,
31
+ LEGACY_SIGNATURE_HEADER: () => LEGACY_SIGNATURE_HEADER,
32
+ LEGACY_TIMESTAMP_HEADER: () => LEGACY_TIMESTAMP_HEADER,
30
33
  REQUEST_ID_HEADER: () => REQUEST_ID_HEADER,
31
34
  SANDBOX_AUTHORIZE_BASE_URL: () => SANDBOX_AUTHORIZE_BASE_URL,
32
35
  SIGNATURE_HEADER: () => SIGNATURE_HEADER,
33
- TIMESTAMP_HEADER: () => TIMESTAMP_HEADER,
36
+ WebhookSignatureError: () => WebhookSignatureError,
34
37
  Wefunder: () => Wefunder,
35
38
  WefunderAuthError: () => WefunderAuthError,
36
39
  WefunderError: () => WefunderError,
40
+ checkWebhookSignature: () => checkWebhookSignature,
37
41
  clientCredentialsGrant: () => clientCredentialsGrant,
38
42
  collect: () => collect,
43
+ computeWebhookSignature: () => computeWebhookSignature,
39
44
  constructEvent: () => constructEvent,
45
+ constructEventFromRequest: () => constructEventFromRequest,
40
46
  createAuthorizationUrl: () => createAuthorizationUrl,
47
+ dispatchWebhook: () => dispatchWebhook,
41
48
  exchangeCode: () => exchangeCode,
42
49
  generatePkce: () => generatePkce,
43
50
  modeForToken: () => modeForToken,
44
51
  paginate: () => paginate,
52
+ parseSignatureHeader: () => parseSignatureHeader,
45
53
  refreshToken: () => refreshToken,
54
+ signWebhook: () => signWebhook,
46
55
  verifyWebhook: () => verifyWebhook
47
56
  });
48
57
  module.exports = __toCommonJS(index_exports);
@@ -1179,21 +1188,36 @@ var sdk_gen_exports = {};
1179
1188
  __export(sdk_gen_exports, {
1180
1189
  approveSyndicateMember: () => approveSyndicateMember,
1181
1190
  closeSyndicateDeal: () => closeSyndicateDeal,
1191
+ createInstallation: () => createInstallation,
1192
+ createInstallationToken: () => createInstallationToken,
1182
1193
  createIntent: () => createIntent,
1183
1194
  createPartnerInvite: () => createPartnerInvite,
1195
+ createWebhookEndpoint: () => createWebhookEndpoint,
1184
1196
  createWebhookSubscription: () => createWebhookSubscription,
1197
+ deleteWebhookEndpoint: () => deleteWebhookEndpoint,
1185
1198
  deleteWebhookSubscription: () => deleteWebhookSubscription,
1186
1199
  demoteSyndicateMember: () => demoteSyndicateMember,
1187
1200
  exportSyndicateMembersCsv: () => exportSyndicateMembersCsv,
1188
1201
  finalizeSyndicateDeal: () => finalizeSyndicateDeal,
1202
+ followCompany: () => followCompany,
1189
1203
  getAttributionMe: () => getAttributionMe,
1190
1204
  getAttributionStats: () => getAttributionStats,
1205
+ getCompany: () => getCompany,
1206
+ getCompanyDisclosures: () => getCompanyDisclosures,
1207
+ getCompanyPitch: () => getCompanyPitch,
1208
+ getCompanyUpdate: () => getCompanyUpdate,
1191
1209
  getCurrentUser: () => getCurrentUser,
1210
+ getInstallation: () => getInstallation,
1192
1211
  getIntent: () => getIntent,
1212
+ getInvestment: () => getInvestment,
1193
1213
  getOffering: () => getOffering,
1214
+ getOfferingStats: () => getOfferingStats,
1215
+ getPortfolio: () => getPortfolio,
1194
1216
  getSyndicate: () => getSyndicate,
1195
1217
  getSyndicateDeal: () => getSyndicateDeal,
1218
+ getSyndicatePortfolio: () => getSyndicatePortfolio,
1196
1219
  getSyndicateStatistics: () => getSyndicateStatistics,
1220
+ getWebhookEndpoint: () => getWebhookEndpoint,
1197
1221
  getWebhookSubscription: () => getWebhookSubscription,
1198
1222
  hideSyndicateMember: () => hideSyndicateMember,
1199
1223
  inviteSyndicateMember: () => inviteSyndicateMember,
@@ -1201,19 +1225,30 @@ __export(sdk_gen_exports, {
1201
1225
  listAttributedInvestments: () => listAttributedInvestments,
1202
1226
  listAttributionCampaigns: () => listAttributionCampaigns,
1203
1227
  listCampaigns: () => listCampaigns,
1228
+ listCompanyQuestions: () => listCompanyQuestions,
1229
+ listCompanyUpdates: () => listCompanyUpdates,
1204
1230
  listConnectedApps: () => listConnectedApps,
1231
+ listEligibleInstallTargets: () => listEligibleInstallTargets,
1232
+ listFollowedCompanies: () => listFollowedCompanies,
1233
+ listInstallations: () => listInstallations,
1205
1234
  listIntents: () => listIntents,
1206
1235
  listInvestments: () => listInvestments,
1236
+ listMyCompanies: () => listMyCompanies,
1207
1237
  listOfferings: () => listOfferings,
1208
1238
  listPartnerInvites: () => listPartnerInvites,
1239
+ listPortfolioPositions: () => listPortfolioPositions,
1209
1240
  listSyndicateDealInvestors: () => listSyndicateDealInvestors,
1210
1241
  listSyndicateDeals: () => listSyndicateDeals,
1211
1242
  listSyndicateMemberInvestments: () => listSyndicateMemberInvestments,
1212
1243
  listSyndicateMembers: () => listSyndicateMembers,
1244
+ listSyndicatePortfolioPositions: () => listSyndicatePortfolioPositions,
1213
1245
  listSyndicates: () => listSyndicates,
1246
+ listWebhookEndpoints: () => listWebhookEndpoints,
1214
1247
  listWebhookSubscriptions: () => listWebhookSubscriptions,
1248
+ previewIntent: () => previewIntent,
1215
1249
  promoteSyndicateMember: () => promoteSyndicateMember,
1216
1250
  reactivateWebhookSubscription: () => reactivateWebhookSubscription,
1251
+ reenableWebhookEndpoint: () => reenableWebhookEndpoint,
1217
1252
  regenerateWebhookSecret: () => regenerateWebhookSecret,
1218
1253
  registerAsPartner: () => registerAsPartner,
1219
1254
  removeSyndicateMember: () => removeSyndicateMember,
@@ -1221,10 +1256,16 @@ __export(sdk_gen_exports, {
1221
1256
  resendSyndicateInvite: () => resendSyndicateInvite,
1222
1257
  restoreSyndicateMember: () => restoreSyndicateMember,
1223
1258
  revokeConnectedApp: () => revokeConnectedApp,
1259
+ revokeInstallation: () => revokeInstallation,
1224
1260
  revokePartnerInvite: () => revokePartnerInvite,
1261
+ rotateWebhookEndpointSecret: () => rotateWebhookEndpointSecret,
1262
+ searchCompanies: () => searchCompanies,
1263
+ testWebhookEndpoint: () => testWebhookEndpoint,
1225
1264
  testWebhookSubscription: () => testWebhookSubscription,
1265
+ unfollowCompany: () => unfollowCompany,
1226
1266
  updateSyndicate: () => updateSyndicate,
1227
- updateSyndicateMember: () => updateSyndicateMember
1267
+ updateSyndicateMember: () => updateSyndicateMember,
1268
+ updateWebhookEndpoint: () => updateWebhookEndpoint
1228
1269
  });
1229
1270
 
1230
1271
  // src/generated/client.gen.ts
@@ -1232,6 +1273,12 @@ var client = createClient(createConfig());
1232
1273
 
1233
1274
  // src/generated/sdk.gen.ts
1234
1275
  var listOfferings = (options) => (options?.client ?? client).get({
1276
+ querySerializer: {
1277
+ parameters: {
1278
+ industry: { array: { explode: false } },
1279
+ business_model: { array: { explode: false } }
1280
+ }
1281
+ },
1235
1282
  security: [{ scheme: "bearer", type: "http" }],
1236
1283
  url: "/explore",
1237
1284
  ...options
@@ -1241,16 +1288,97 @@ var getOffering = (options) => (options.client ?? client).get({
1241
1288
  url: "/offerings/{external_id}",
1242
1289
  ...options
1243
1290
  });
1291
+ var getCompanyDisclosures = (options) => (options.client ?? client).get({
1292
+ querySerializer: {
1293
+ parameters: { sections: { array: { explode: false } } }
1294
+ },
1295
+ security: [{ scheme: "bearer", type: "http" }],
1296
+ url: "/companies/{id}/disclosures",
1297
+ ...options
1298
+ });
1299
+ var getCompanyPitch = (options) => (options.client ?? client).get({
1300
+ querySerializer: {
1301
+ parameters: { sections: { array: { explode: false } } }
1302
+ },
1303
+ security: [{ scheme: "bearer", type: "http" }],
1304
+ url: "/companies/{id}/pitch",
1305
+ ...options
1306
+ });
1307
+ var listCompanyUpdates = (options) => (options.client ?? client).get({
1308
+ security: [{ scheme: "bearer", type: "http" }],
1309
+ url: "/companies/{id}/updates",
1310
+ ...options
1311
+ });
1312
+ var getCompanyUpdate = (options) => (options.client ?? client).get({
1313
+ security: [{ scheme: "bearer", type: "http" }],
1314
+ url: "/companies/{id}/updates/{update_id}",
1315
+ ...options
1316
+ });
1317
+ var listCompanyQuestions = (options) => (options.client ?? client).get({
1318
+ security: [{ scheme: "bearer", type: "http" }],
1319
+ url: "/companies/{id}/questions",
1320
+ ...options
1321
+ });
1322
+ var searchCompanies = (options) => (options.client ?? client).get({
1323
+ security: [{ scheme: "bearer", type: "http" }],
1324
+ url: "/companies/search",
1325
+ ...options
1326
+ });
1327
+ var getCompany = (options) => (options.client ?? client).get({
1328
+ security: [{ scheme: "bearer", type: "http" }],
1329
+ url: "/companies/{id}",
1330
+ ...options
1331
+ });
1244
1332
  var getCurrentUser = (options) => (options?.client ?? client).get({
1245
1333
  security: [{ scheme: "bearer", type: "http" }],
1246
1334
  url: "/users/me",
1247
1335
  ...options
1248
1336
  });
1337
+ var listMyCompanies = (options) => (options?.client ?? client).get({
1338
+ security: [{ scheme: "bearer", type: "http" }],
1339
+ url: "/users/me/companies",
1340
+ ...options
1341
+ });
1342
+ var listFollowedCompanies = (options) => (options?.client ?? client).get({
1343
+ security: [{ scheme: "bearer", type: "http" }],
1344
+ url: "/users/me/follows",
1345
+ ...options
1346
+ });
1347
+ var unfollowCompany = (options) => (options.client ?? client).delete({
1348
+ security: [{ scheme: "bearer", type: "http" }],
1349
+ url: "/users/me/follows/{company_id}",
1350
+ ...options
1351
+ });
1352
+ var followCompany = (options) => (options.client ?? client).put({
1353
+ security: [{ scheme: "bearer", type: "http" }],
1354
+ url: "/users/me/follows/{company_id}",
1355
+ ...options
1356
+ });
1249
1357
  var listInvestments = (options) => (options?.client ?? client).get({
1250
1358
  security: [{ scheme: "bearer", type: "http" }],
1251
1359
  url: "/investments",
1252
1360
  ...options
1253
1361
  });
1362
+ var getInvestment = (options) => (options.client ?? client).get({
1363
+ security: [{ scheme: "bearer", type: "http" }],
1364
+ url: "/investments/{id}",
1365
+ ...options
1366
+ });
1367
+ var getOfferingStats = (options) => (options.client ?? client).get({
1368
+ security: [{ scheme: "bearer", type: "http" }],
1369
+ url: "/offerings/{offering_id}/stats",
1370
+ ...options
1371
+ });
1372
+ var getPortfolio = (options) => (options?.client ?? client).get({
1373
+ security: [{ scheme: "bearer", type: "http" }],
1374
+ url: "/portfolio",
1375
+ ...options
1376
+ });
1377
+ var listPortfolioPositions = (options) => (options?.client ?? client).get({
1378
+ security: [{ scheme: "bearer", type: "http" }],
1379
+ url: "/portfolio/positions",
1380
+ ...options
1381
+ });
1254
1382
  var listCampaigns = (options) => (options?.client ?? client).get({
1255
1383
  security: [{ scheme: "bearer", type: "http" }],
1256
1384
  url: "/campaigns",
@@ -1372,6 +1500,16 @@ var getSyndicateStatistics = (options) => (options.client ?? client).get({
1372
1500
  url: "/syndicates/{syndicate_id}/statistics",
1373
1501
  ...options
1374
1502
  });
1503
+ var getSyndicatePortfolio = (options) => (options.client ?? client).get({
1504
+ security: [{ scheme: "bearer", type: "http" }],
1505
+ url: "/syndicates/{syndicate_id}/portfolio",
1506
+ ...options
1507
+ });
1508
+ var listSyndicatePortfolioPositions = (options) => (options.client ?? client).get({
1509
+ security: [{ scheme: "bearer", type: "http" }],
1510
+ url: "/syndicates/{syndicate_id}/portfolio/positions",
1511
+ ...options
1512
+ });
1375
1513
  var closeSyndicateDeal = (options) => (options.client ?? client).post({
1376
1514
  security: [{ scheme: "bearer", type: "http" }],
1377
1515
  url: "/syndicates/{syndicate_id}/deals/{fundraise_id}/close",
@@ -1382,6 +1520,15 @@ var finalizeSyndicateDeal = (options) => (options.client ?? client).post({
1382
1520
  url: "/syndicates/{syndicate_id}/deals/{fundraise_id}/finalize",
1383
1521
  ...options
1384
1522
  });
1523
+ var previewIntent = (options) => (options.client ?? client).post({
1524
+ security: [{ scheme: "bearer", type: "http" }],
1525
+ url: "/intents/preview",
1526
+ ...options,
1527
+ headers: {
1528
+ "Content-Type": "application/json",
1529
+ ...options.headers
1530
+ }
1531
+ });
1385
1532
  var listIntents = (options) => (options?.client ?? client).get({
1386
1533
  security: [{ scheme: "bearer", type: "http" }],
1387
1534
  url: "/intents",
@@ -1426,6 +1573,96 @@ var listAttributedInvestments = (options) => (options.client ?? client).get({
1426
1573
  url: "/campaigns/{campaign_id}/attribution/investments",
1427
1574
  ...options
1428
1575
  });
1576
+ var listInstallations = (options) => (options?.client ?? client).get({
1577
+ security: [{ scheme: "bearer", type: "http" }],
1578
+ url: "/installations",
1579
+ ...options
1580
+ });
1581
+ var createInstallation = (options) => (options.client ?? client).post({
1582
+ security: [{ scheme: "bearer", type: "http" }],
1583
+ url: "/installations",
1584
+ ...options,
1585
+ headers: {
1586
+ "Content-Type": "application/json",
1587
+ ...options.headers
1588
+ }
1589
+ });
1590
+ var listEligibleInstallTargets = (options) => (options?.client ?? client).get({
1591
+ security: [{ scheme: "bearer", type: "http" }],
1592
+ url: "/installations/eligible",
1593
+ ...options
1594
+ });
1595
+ var revokeInstallation = (options) => (options.client ?? client).delete({
1596
+ security: [{ scheme: "bearer", type: "http" }],
1597
+ url: "/installations/{external_id}",
1598
+ ...options
1599
+ });
1600
+ var getInstallation = (options) => (options.client ?? client).get({
1601
+ security: [{ scheme: "bearer", type: "http" }],
1602
+ url: "/installations/{external_id}",
1603
+ ...options
1604
+ });
1605
+ var createInstallationToken = (options) => (options.client ?? client).post({
1606
+ security: [{ scheme: "bearer", type: "http" }],
1607
+ url: "/installations/{external_id}/tokens",
1608
+ ...options,
1609
+ headers: {
1610
+ "Content-Type": "application/json",
1611
+ ...options.headers
1612
+ }
1613
+ });
1614
+ var listWebhookEndpoints = (options) => (options?.client ?? client).get({
1615
+ security: [{ scheme: "bearer", type: "http" }],
1616
+ url: "/webhook_endpoints",
1617
+ ...options
1618
+ });
1619
+ var createWebhookEndpoint = (options) => (options.client ?? client).post({
1620
+ security: [{ scheme: "bearer", type: "http" }],
1621
+ url: "/webhook_endpoints",
1622
+ ...options,
1623
+ headers: {
1624
+ "Content-Type": "application/json",
1625
+ ...options.headers
1626
+ }
1627
+ });
1628
+ var deleteWebhookEndpoint = (options) => (options.client ?? client).delete({
1629
+ security: [{ scheme: "bearer", type: "http" }],
1630
+ url: "/webhook_endpoints/{external_id}",
1631
+ ...options
1632
+ });
1633
+ var getWebhookEndpoint = (options) => (options.client ?? client).get({
1634
+ security: [{ scheme: "bearer", type: "http" }],
1635
+ url: "/webhook_endpoints/{external_id}",
1636
+ ...options
1637
+ });
1638
+ var updateWebhookEndpoint = (options) => (options.client ?? client).patch({
1639
+ security: [{ scheme: "bearer", type: "http" }],
1640
+ url: "/webhook_endpoints/{external_id}",
1641
+ ...options,
1642
+ headers: {
1643
+ "Content-Type": "application/json",
1644
+ ...options.headers
1645
+ }
1646
+ });
1647
+ var rotateWebhookEndpointSecret = (options) => (options.client ?? client).post({
1648
+ security: [{ scheme: "bearer", type: "http" }],
1649
+ url: "/webhook_endpoints/{external_id}/rotate_secret",
1650
+ ...options
1651
+ });
1652
+ var reenableWebhookEndpoint = (options) => (options.client ?? client).post({
1653
+ security: [{ scheme: "bearer", type: "http" }],
1654
+ url: "/webhook_endpoints/{external_id}/reenable",
1655
+ ...options
1656
+ });
1657
+ var testWebhookEndpoint = (options) => (options.client ?? client).post({
1658
+ security: [{ scheme: "bearer", type: "http" }],
1659
+ url: "/webhook_endpoints/{external_id}/test",
1660
+ ...options,
1661
+ headers: {
1662
+ "Content-Type": "application/json",
1663
+ ...options.headers
1664
+ }
1665
+ });
1429
1666
  var listWebhookSubscriptions = (options) => (options.client ?? client).get({
1430
1667
  security: [{ scheme: "bearer", type: "http" }],
1431
1668
  url: "/campaigns/{campaign_id}/attribution/webhooks",
@@ -1643,10 +1880,27 @@ var Wefunder = class _Wefunder {
1643
1880
  getOffering({ client: this.#client, path: { external_id: externalId } })
1644
1881
  )
1645
1882
  };
1883
+ /**
1884
+ * Investments (`read:investments`). `list` is a bootstrap listing; pass `updated_since`
1885
+ * or a saved `cursor` for sync mode (`meta.mode === "delta"`). Persist `meta.next_cursor`
1886
+ * from your last page — it is always present — and resume from it next time.
1887
+ */
1646
1888
  investments = {
1647
1889
  list: this.#page(listInvestments),
1648
- all: () => paginate((cursor) => this.investments.list({ cursor })),
1649
- collect: () => collect((cursor) => this.investments.list({ cursor }))
1890
+ all: (query) => paginate((cursor) => this.investments.list({ ...query, cursor })),
1891
+ collect: (query) => collect((cursor) => this.investments.list({ ...query, cursor })),
1892
+ /** The current record (not the published projection) for one investment (`inv_…`). */
1893
+ get: (id) => this.#unwrapData(getInvestment({ client: this.#client, path: { id } }))
1894
+ };
1895
+ portfolio = {
1896
+ get: (query) => this.#unwrapData(getPortfolio({ client: this.#client, query })),
1897
+ positions: {
1898
+ list: this.#page(
1899
+ listPortfolioPositions
1900
+ ),
1901
+ all: (query) => paginate((cursor) => this.portfolio.positions.list({ ...query, cursor })),
1902
+ collect: (query) => collect((cursor) => this.portfolio.positions.list({ ...query, cursor }))
1903
+ }
1650
1904
  };
1651
1905
  campaigns = {
1652
1906
  list: this.#page(listCampaigns),
@@ -1666,17 +1920,76 @@ var Wefunder = class _Wefunder {
1666
1920
  attribution = {
1667
1921
  me: () => this.#unwrapData(getAttributionMe({ client: this.#client }))
1668
1922
  };
1923
+ /**
1924
+ * Webhook endpoints (`/webhook_endpoints`, scopes `read:webhooks` / `write:webhooks`).
1925
+ * Endpoints belong to your application and are managed through the LIVE API —
1926
+ * create sandbox receivers there with `mode: "test"`; they're mirrored into
1927
+ * sandbox. The signing `secret` is returned ONLY by `create` and `rotateSecret`.
1928
+ * Verify deliveries with `constructEvent` (see the webhooks module).
1929
+ */
1930
+ webhookEndpoints = {
1931
+ /** All of your app's endpoints (secret omitted). `meta.quota` is the per-app limit. */
1932
+ list: () => this.#unwrap(listWebhookEndpoints({ client: this.#client })),
1933
+ get: (id) => this.#unwrapData(
1934
+ getWebhookEndpoint({ client: this.#client, path: { external_id: id } })
1935
+ ),
1936
+ /** Store `attributes.secret` from the result — it is never shown again. */
1937
+ create: (input) => this.#unwrapData(createWebhookEndpoint({ client: this.#client, body: input })),
1938
+ /** `events` replaces the subscription list wholesale (no merge); omit to leave unchanged. */
1939
+ update: (id, input) => this.#unwrapData(
1940
+ updateWebhookEndpoint({ client: this.#client, path: { external_id: id }, body: input })
1941
+ ),
1942
+ /** Stops deliveries immediately. Removal is permanent — create a new endpoint to resume. */
1943
+ remove: (id) => this.#unwrapData(
1944
+ deleteWebhookEndpoint({ client: this.#client, path: { external_id: id } })
1945
+ ),
1946
+ /**
1947
+ * New secret (shown once). The old one keeps signing for a 24h overlap — deliveries
1948
+ * carry a `v1` for both, and `constructEvent` accepts either.
1949
+ */
1950
+ rotateSecret: (id) => this.#unwrapData(
1951
+ rotateWebhookEndpointSecret({ client: this.#client, path: { external_id: id } })
1952
+ ),
1953
+ /** Recover an auto-disabled endpoint after fixing your server. Idempotent. */
1954
+ reenable: (id) => this.#unwrapData(
1955
+ reenableWebhookEndpoint({ client: this.#client, path: { external_id: id } })
1956
+ ),
1957
+ /**
1958
+ * POST a real, signed example event at the endpoint (production envelope + signature)
1959
+ * and report the outcome inline. Defaults to the endpoint's first subscribed event.
1960
+ * Doesn't affect delivery health. Rate-limited to 10/min per endpoint.
1961
+ */
1962
+ test: (id, event) => this.#unwrapData(
1963
+ testWebhookEndpoint({
1964
+ client: this.#client,
1965
+ path: { external_id: id },
1966
+ body: event ? { event } : void 0
1967
+ })
1968
+ )
1969
+ };
1669
1970
  };
1670
1971
 
1671
1972
  // src/webhooks.ts
1672
1973
  var import_node_crypto2 = require("crypto");
1673
- var SIGNATURE_HEADER = "x-wefunder-signature";
1674
- var TIMESTAMP_HEADER = "x-wefunder-timestamp";
1675
- var EVENT_HEADER = "x-wefunder-event";
1676
- var DELIVERY_ID_HEADER = "x-wefunder-delivery-id";
1677
- function computeSignature(secret, timestamp, payload) {
1678
- const mac = (0, import_node_crypto2.createHmac)("sha256", secret).update(`${timestamp}.${payload}`).digest("hex");
1679
- return `sha256=${mac}`;
1974
+ var SIGNATURE_HEADER = "wefunder-signature";
1975
+ var DEFAULT_TOLERANCE_SECONDS = 300;
1976
+ var LEGACY_SIGNATURE_HEADER = "x-wefunder-signature";
1977
+ var LEGACY_TIMESTAMP_HEADER = "x-wefunder-timestamp";
1978
+ var LEGACY_EVENT_HEADER = "x-wefunder-event";
1979
+ var LEGACY_DELIVERY_ID_HEADER = "x-wefunder-delivery-id";
1980
+ var WebhookSignatureError = class extends Error {
1981
+ reason;
1982
+ constructor(reason, message) {
1983
+ super(message);
1984
+ this.name = "WebhookSignatureError";
1985
+ this.reason = reason;
1986
+ }
1987
+ };
1988
+ function bodyBuffer(payload) {
1989
+ return typeof payload === "string" ? Buffer.from(payload, "utf8") : Buffer.from(payload);
1990
+ }
1991
+ function computeWebhookSignature(secret, timestamp, payload) {
1992
+ return (0, import_node_crypto2.createHmac)("sha256", secret).update(`${timestamp}.`).update(bodyBuffer(payload)).digest("hex");
1680
1993
  }
1681
1994
  function constantTimeEqual(a, b) {
1682
1995
  const ab = Buffer.from(a);
@@ -1684,42 +1997,142 @@ function constantTimeEqual(a, b) {
1684
1997
  if (ab.length !== bb.length) return false;
1685
1998
  return (0, import_node_crypto2.timingSafeEqual)(ab, bb);
1686
1999
  }
2000
+ function parseSignatureHeader(header) {
2001
+ let timestamp;
2002
+ const signatures = [];
2003
+ for (const part of header.split(",")) {
2004
+ const eq = part.indexOf("=");
2005
+ if (eq < 0) continue;
2006
+ const key = part.slice(0, eq).trim();
2007
+ const value = part.slice(eq + 1).trim();
2008
+ if (key === "t") {
2009
+ if (!/^\d+$/.test(value)) return null;
2010
+ timestamp = Number(value);
2011
+ } else if (key === "v1" && value) {
2012
+ signatures.push(value);
2013
+ }
2014
+ }
2015
+ if (timestamp === void 0 || signatures.length === 0) return null;
2016
+ return { timestamp, signatures };
2017
+ }
2018
+ function signWebhook(opts) {
2019
+ const t = opts.timestamp ?? Math.floor(Date.now() / 1e3);
2020
+ const secrets = [opts.secret, ...opts.additionalSecrets ?? []];
2021
+ const entries = secrets.map((s) => `v1=${computeWebhookSignature(s, t, opts.payload)}`);
2022
+ return [`t=${t}`, ...entries].join(",");
2023
+ }
2024
+ function checkWebhookSignature(opts) {
2025
+ const parsed = parseSignatureHeader(opts.header);
2026
+ if (!parsed) return "malformed_header";
2027
+ const tolerance = opts.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
2028
+ if (tolerance > 0) {
2029
+ const nowSec = (opts.now ?? Date.now)() / 1e3;
2030
+ if (Math.abs(nowSec - parsed.timestamp) > tolerance) return "timestamp_out_of_tolerance";
2031
+ }
2032
+ const expected = computeWebhookSignature(opts.secret, parsed.timestamp, opts.payload);
2033
+ return parsed.signatures.some((sig) => constantTimeEqual(sig, expected)) ? null : "signature_mismatch";
2034
+ }
1687
2035
  function verifyWebhook(opts) {
1688
- const tolerance = opts.toleranceSeconds ?? 300;
1689
- const now = (opts.now ?? Date.now)();
2036
+ if ("header" in opts) return checkWebhookSignature(opts) === null;
2037
+ return verifyLegacyWebhook(opts);
2038
+ }
2039
+ function verifyLegacyWebhook(opts) {
2040
+ const tolerance = opts.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
1690
2041
  const ts = Number(opts.timestamp);
1691
2042
  if (!Number.isFinite(ts)) return false;
1692
- if (tolerance > 0 && Math.abs(now / 1e3 - ts) > tolerance) return false;
1693
- const expected = computeSignature(opts.secret, opts.timestamp, opts.payload);
2043
+ if (tolerance > 0 && Math.abs((opts.now ?? Date.now)() / 1e3 - ts) > tolerance) return false;
2044
+ const expected = `sha256=${computeWebhookSignature(opts.secret, opts.timestamp, opts.payload)}`;
1694
2045
  return constantTimeEqual(opts.signature, expected);
1695
2046
  }
1696
- function constructEvent(payload, headers, secret, opts) {
1697
- const get = (name) => {
1698
- if (headers instanceof Headers) return headers.get(name) ?? void 0;
1699
- const v = headers[name] ?? headers[name.toLowerCase()];
2047
+ function headerGetter(headers) {
2048
+ if (typeof headers === "string") {
2049
+ return (name) => name === SIGNATURE_HEADER ? headers : void 0;
2050
+ }
2051
+ if (headers instanceof Headers) return (name) => headers.get(name) ?? void 0;
2052
+ return (name) => {
2053
+ let v = headers[name];
2054
+ if (v === void 0) {
2055
+ const hit = Object.keys(headers).find((k) => k.toLowerCase() === name);
2056
+ if (hit) v = headers[hit];
2057
+ }
1700
2058
  return Array.isArray(v) ? v[0] : v;
1701
2059
  };
1702
- const signature = get(SIGNATURE_HEADER);
1703
- const timestamp = get(TIMESTAMP_HEADER);
1704
- if (!signature || !timestamp) {
1705
- throw new Error("Missing X-Wefunder-Signature or X-Wefunder-Timestamp header");
1706
- }
1707
- const ok = verifyWebhook({
1708
- payload,
1709
- signature,
1710
- timestamp,
1711
- secret,
1712
- toleranceSeconds: opts?.toleranceSeconds,
1713
- now: opts?.now
1714
- });
1715
- if (!ok) throw new Error("Webhook signature verification failed");
2060
+ }
2061
+ function constructEvent(payload, headers, secret, opts) {
2062
+ const get = headerGetter(headers);
2063
+ const header = get(SIGNATURE_HEADER);
2064
+ if (!header) {
2065
+ const legacySig = get(LEGACY_SIGNATURE_HEADER);
2066
+ const legacyTs = get(LEGACY_TIMESTAMP_HEADER);
2067
+ if (legacySig && legacyTs) return constructLegacyEvent(payload, get, legacySig, legacyTs, secret, opts);
2068
+ throw new WebhookSignatureError("missing_header", describeFailure("missing_header"));
2069
+ }
2070
+ const failure = checkWebhookSignature({ payload, header, secret, ...opts });
2071
+ if (failure) throw new WebhookSignatureError(failure, describeFailure(failure));
2072
+ const parsed = parseSignatureHeader(header);
2073
+ const env = parseEnvelope(payload);
1716
2074
  return {
1717
- event: get(EVENT_HEADER) ?? "",
1718
- deliveryId: get(DELIVERY_ID_HEADER) ?? "",
1719
- timestamp: Number(timestamp),
1720
- data: JSON.parse(payload)
2075
+ id: String(env.id ?? ""),
2076
+ event: String(env.event ?? ""),
2077
+ created_at: String(env.created_at ?? ""),
2078
+ mode: env.mode === "test" ? "test" : "live",
2079
+ data: env.data,
2080
+ timestamp: parsed.timestamp
1721
2081
  };
1722
2082
  }
2083
+ function constructLegacyEvent(payload, get, signature, timestamp, secret, opts) {
2084
+ if (!verifyLegacyWebhook({ payload, signature, timestamp, secret, ...opts })) {
2085
+ throw new WebhookSignatureError("signature_mismatch", describeFailure("signature_mismatch"));
2086
+ }
2087
+ const env = parseEnvelope(payload);
2088
+ return {
2089
+ id: String(env.id ?? get(LEGACY_DELIVERY_ID_HEADER) ?? ""),
2090
+ event: String(env.event ?? get(LEGACY_EVENT_HEADER) ?? ""),
2091
+ created_at: String(env.created_at ?? ""),
2092
+ mode: env.mode === "test" ? "test" : "live",
2093
+ data: env.data ?? env,
2094
+ timestamp: Number(timestamp)
2095
+ };
2096
+ }
2097
+ function parseEnvelope(payload) {
2098
+ try {
2099
+ const parsed = JSON.parse(bodyBuffer(payload).toString("utf8"));
2100
+ if (parsed === null || typeof parsed !== "object") throw new Error("not an object");
2101
+ return parsed;
2102
+ } catch {
2103
+ throw new WebhookSignatureError("invalid_payload", describeFailure("invalid_payload"));
2104
+ }
2105
+ }
2106
+ function describeFailure(reason) {
2107
+ switch (reason) {
2108
+ case "missing_header":
2109
+ return "Missing Wefunder-Signature header";
2110
+ case "malformed_header":
2111
+ return "Wefunder-Signature header is malformed (expected t=<unix>,v1=<hex>)";
2112
+ case "timestamp_out_of_tolerance":
2113
+ return "Webhook timestamp is outside the replay tolerance";
2114
+ case "signature_mismatch":
2115
+ return "Webhook signature verification failed";
2116
+ case "invalid_payload":
2117
+ return "Webhook body is not a JSON object";
2118
+ }
2119
+ }
2120
+ async function constructEventFromRequest(request, secret, opts) {
2121
+ const payload = await request.text();
2122
+ return constructEvent(payload, request.headers, secret, opts);
2123
+ }
2124
+ async function dispatchWebhook(event, handlers) {
2125
+ const specific = event.event === "default" ? void 0 : handlers[event.event];
2126
+ if (specific) {
2127
+ await specific(event);
2128
+ return true;
2129
+ }
2130
+ if (handlers.default) {
2131
+ await handlers.default(event);
2132
+ return true;
2133
+ }
2134
+ return false;
2135
+ }
1723
2136
  // Annotate the CommonJS export names for ESM import in node:
1724
2137
  0 && (module.exports = {
1725
2138
  DEFAULT_API_BASE_URL,
@@ -1727,24 +2140,33 @@ function constructEvent(payload, headers, secret, opts) {
1727
2140
  DEFAULT_AUTHORIZE_BASE_URL,
1728
2141
  DEFAULT_OAUTH_BASE_URL,
1729
2142
  DEFAULT_TOKEN_BASE_URL,
1730
- DELIVERY_ID_HEADER,
1731
- EVENT_HEADER,
2143
+ DEFAULT_TOLERANCE_SECONDS,
2144
+ LEGACY_DELIVERY_ID_HEADER,
2145
+ LEGACY_EVENT_HEADER,
2146
+ LEGACY_SIGNATURE_HEADER,
2147
+ LEGACY_TIMESTAMP_HEADER,
1732
2148
  REQUEST_ID_HEADER,
1733
2149
  SANDBOX_AUTHORIZE_BASE_URL,
1734
2150
  SIGNATURE_HEADER,
1735
- TIMESTAMP_HEADER,
2151
+ WebhookSignatureError,
1736
2152
  Wefunder,
1737
2153
  WefunderAuthError,
1738
2154
  WefunderError,
2155
+ checkWebhookSignature,
1739
2156
  clientCredentialsGrant,
1740
2157
  collect,
2158
+ computeWebhookSignature,
1741
2159
  constructEvent,
2160
+ constructEventFromRequest,
1742
2161
  createAuthorizationUrl,
2162
+ dispatchWebhook,
1743
2163
  exchangeCode,
1744
2164
  generatePkce,
1745
2165
  modeForToken,
1746
2166
  paginate,
2167
+ parseSignatureHeader,
1747
2168
  refreshToken,
2169
+ signWebhook,
1748
2170
  verifyWebhook
1749
2171
  });
1750
2172
  //# sourceMappingURL=index.cjs.map