@wefunder/sdk 0.1.0-beta.0

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 ADDED
@@ -0,0 +1,1264 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DEFAULT_API_BASE_URL: () => DEFAULT_API_BASE_URL,
24
+ DEFAULT_API_VERSION: () => DEFAULT_API_VERSION,
25
+ DEFAULT_AUTHORIZE_BASE_URL: () => DEFAULT_AUTHORIZE_BASE_URL,
26
+ DEFAULT_OAUTH_BASE_URL: () => DEFAULT_OAUTH_BASE_URL,
27
+ DEFAULT_TOKEN_BASE_URL: () => DEFAULT_TOKEN_BASE_URL,
28
+ DELIVERY_ID_HEADER: () => DELIVERY_ID_HEADER,
29
+ EVENT_HEADER: () => EVENT_HEADER,
30
+ REQUEST_ID_HEADER: () => REQUEST_ID_HEADER,
31
+ SIGNATURE_HEADER: () => SIGNATURE_HEADER,
32
+ TIMESTAMP_HEADER: () => TIMESTAMP_HEADER,
33
+ Wefunder: () => Wefunder,
34
+ WefunderAuthError: () => WefunderAuthError,
35
+ WefunderError: () => WefunderError,
36
+ clientCredentialsGrant: () => clientCredentialsGrant,
37
+ collect: () => collect,
38
+ constructEvent: () => constructEvent,
39
+ createAuthorizationUrl: () => createAuthorizationUrl,
40
+ exchangeCode: () => exchangeCode,
41
+ generatePkce: () => generatePkce,
42
+ modeForToken: () => modeForToken,
43
+ paginate: () => paginate,
44
+ refreshToken: () => refreshToken,
45
+ verifyWebhook: () => verifyWebhook
46
+ });
47
+ module.exports = __toCommonJS(index_exports);
48
+
49
+ // src/client.ts
50
+ var import_client_fetch2 = require("@hey-api/client-fetch");
51
+
52
+ // src/http.ts
53
+ var IDEMPOTENT = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
54
+ function methodOf(input, init) {
55
+ if (init?.method) return init.method.toUpperCase();
56
+ if (input instanceof Request) return input.method.toUpperCase();
57
+ return "GET";
58
+ }
59
+ function rateLimitWaitMs(response, now, maxDelayMs) {
60
+ const raw = response.headers.get("x-ratelimit-reset");
61
+ if (!raw) return Math.min(1e3, maxDelayMs);
62
+ const n = Number(raw);
63
+ if (!Number.isFinite(n)) return Math.min(1e3, maxDelayMs);
64
+ const wait = n > 1e9 ? n * 1e3 - now : n * 1e3;
65
+ return Math.max(0, Math.min(wait, maxDelayMs));
66
+ }
67
+ function backoffMs(attempt, opts, random) {
68
+ const exp = opts.baseDelayMs * 2 ** attempt;
69
+ const jitter = exp * 0.5 * random();
70
+ return Math.min(exp + jitter, opts.maxDelayMs);
71
+ }
72
+ function withBearer(input, init, token) {
73
+ const headers = new Headers(
74
+ init?.headers ?? (input instanceof Request ? input.headers : void 0)
75
+ );
76
+ headers.set("Authorization", `Bearer ${token}`);
77
+ return { ...init, headers };
78
+ }
79
+ function createFetch(deps) {
80
+ const baseFetch = deps.fetch ?? fetch;
81
+ const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
82
+ const now = deps.now ?? Date.now;
83
+ const random = deps.random ?? Math.random;
84
+ const retry = {
85
+ maxRetries: deps.retry?.maxRetries ?? 2,
86
+ baseDelayMs: deps.retry?.baseDelayMs ?? 250,
87
+ maxDelayMs: deps.retry?.maxDelayMs ?? 6e4
88
+ };
89
+ return async function wrappedFetch(input, init) {
90
+ const method = methodOf(input, init);
91
+ const idempotent = IDEMPOTENT.has(method);
92
+ let refreshed = false;
93
+ let attempt = 0;
94
+ for (; ; ) {
95
+ let response;
96
+ let networkError;
97
+ try {
98
+ response = await baseFetch(input, init);
99
+ } catch (err) {
100
+ networkError = err;
101
+ }
102
+ const replayable = !(input instanceof Request && input.bodyUsed);
103
+ if (response?.status === 401 && !refreshed && replayable && deps.tokenManager?.canRefresh) {
104
+ refreshed = true;
105
+ const next = await deps.tokenManager.refresh();
106
+ init = withBearer(input, init, next.accessToken);
107
+ continue;
108
+ }
109
+ if (response?.status === 429 && attempt < retry.maxRetries) {
110
+ attempt++;
111
+ await sleep(rateLimitWaitMs(response, now(), retry.maxDelayMs));
112
+ continue;
113
+ }
114
+ const transient = networkError !== void 0 || response !== void 0 && response.status >= 500;
115
+ if (transient && idempotent && attempt < retry.maxRetries) {
116
+ attempt++;
117
+ await sleep(backoffMs(attempt, retry, random));
118
+ continue;
119
+ }
120
+ if (response) return response;
121
+ throw networkError;
122
+ }
123
+ };
124
+ }
125
+
126
+ // src/oauth.ts
127
+ var import_node_crypto = require("crypto");
128
+ var DEFAULT_AUTHORIZE_BASE_URL = "https://wefunder.com/oauth";
129
+ var DEFAULT_TOKEN_BASE_URL = "https://wefunder.com/oauth";
130
+ var DEFAULT_OAUTH_BASE_URL = DEFAULT_AUTHORIZE_BASE_URL;
131
+ function resolveAuthorizeBase(o) {
132
+ return o.authorizeBaseUrl ?? o.oauthBaseUrl ?? DEFAULT_AUTHORIZE_BASE_URL;
133
+ }
134
+ function resolveTokenBase(o) {
135
+ return o.tokenBaseUrl ?? o.oauthBaseUrl ?? DEFAULT_TOKEN_BASE_URL;
136
+ }
137
+ function toTokenSet(raw, now) {
138
+ return {
139
+ accessToken: raw.access_token,
140
+ refreshToken: raw.refresh_token,
141
+ expiresAt: raw.expires_in ? now + raw.expires_in * 1e3 : void 0,
142
+ scope: raw.scope,
143
+ tokenType: raw.token_type
144
+ };
145
+ }
146
+ async function postToken(oauthBaseUrl, params, fetchImpl, now) {
147
+ const res = await fetchImpl(`${oauthBaseUrl}/token`, {
148
+ method: "POST",
149
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
150
+ body: new URLSearchParams(params).toString()
151
+ });
152
+ if (!res.ok) {
153
+ let detail = "";
154
+ try {
155
+ detail = JSON.stringify(await res.json());
156
+ } catch {
157
+ detail = await res.text().catch(() => "");
158
+ }
159
+ throw new Error(`OAuth token request failed (${res.status}): ${detail}`);
160
+ }
161
+ return toTokenSet(await res.json(), now());
162
+ }
163
+ function base64Url(buf) {
164
+ return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
165
+ }
166
+ function generatePkce() {
167
+ const codeVerifier = base64Url((0, import_node_crypto.randomBytes)(32));
168
+ const codeChallenge = base64Url((0, import_node_crypto.createHash)("sha256").update(codeVerifier).digest());
169
+ return { codeVerifier, codeChallenge, codeChallengeMethod: "S256" };
170
+ }
171
+ function createAuthorizationUrl(opts) {
172
+ const base = resolveAuthorizeBase(opts);
173
+ const q = new URLSearchParams({
174
+ response_type: "code",
175
+ client_id: opts.clientId,
176
+ redirect_uri: opts.redirectUri,
177
+ scope: opts.scopes.join(" "),
178
+ state: opts.state,
179
+ code_challenge: opts.pkce.codeChallenge,
180
+ code_challenge_method: opts.pkce.codeChallengeMethod
181
+ });
182
+ return `${base}/authorize?${q.toString()}`;
183
+ }
184
+ function exchangeCode(opts) {
185
+ const params = {
186
+ grant_type: "authorization_code",
187
+ client_id: opts.clientId,
188
+ code: opts.code,
189
+ redirect_uri: opts.redirectUri,
190
+ code_verifier: opts.codeVerifier
191
+ };
192
+ if (opts.clientSecret) params.client_secret = opts.clientSecret;
193
+ return postToken(resolveTokenBase(opts), params, opts.fetch ?? fetch, opts.now ?? Date.now);
194
+ }
195
+ function clientCredentialsGrant(opts) {
196
+ const params = {
197
+ grant_type: "client_credentials",
198
+ client_id: opts.clientId,
199
+ client_secret: opts.clientSecret
200
+ };
201
+ if (opts.scopes?.length) params.scope = opts.scopes.join(" ");
202
+ return postToken(resolveTokenBase(opts), params, opts.fetch ?? fetch, opts.now ?? Date.now);
203
+ }
204
+ function refreshToken(opts) {
205
+ const params = {
206
+ grant_type: "refresh_token",
207
+ client_id: opts.clientId,
208
+ refresh_token: opts.refreshToken
209
+ };
210
+ if (opts.clientSecret) params.client_secret = opts.clientSecret;
211
+ return postToken(resolveTokenBase(opts), params, opts.fetch ?? fetch, opts.now ?? Date.now);
212
+ }
213
+
214
+ // src/errors.ts
215
+ var REQUEST_ID_HEADER = "x-wf-request-id";
216
+ function requestIdFrom(response, bodyRequestId) {
217
+ return response?.headers.get(REQUEST_ID_HEADER) ?? bodyRequestId;
218
+ }
219
+ var WefunderError = class extends Error {
220
+ status;
221
+ type;
222
+ requestId;
223
+ details;
224
+ /** Server-provided hint on how to resolve the error, when present. */
225
+ remediation;
226
+ /** Documentation pointer surfaced to developers in stack traces / logs. */
227
+ documentationUrl = "https://docs.wefunder.com/api-reference";
228
+ constructor(args) {
229
+ super(args.message);
230
+ this.name = "WefunderError";
231
+ this.status = args.status;
232
+ this.type = args.type;
233
+ this.requestId = args.requestId;
234
+ this.details = args.details;
235
+ this.remediation = args.remediation;
236
+ }
237
+ };
238
+ var WefunderAuthError = class extends WefunderError {
239
+ constructor(message) {
240
+ super({ status: 401, type: "unauthorized", message });
241
+ this.name = "WefunderAuthError";
242
+ }
243
+ };
244
+
245
+ // src/token-manager.ts
246
+ var TokenManager = class {
247
+ #tokens;
248
+ #clientId;
249
+ #clientSecret;
250
+ #reMint;
251
+ #tokenBaseUrl;
252
+ #onTokenRefresh;
253
+ #store;
254
+ #fetch;
255
+ #now;
256
+ #leeway;
257
+ #inflight;
258
+ constructor(opts) {
259
+ this.#tokens = opts.tokens;
260
+ this.#clientId = opts.clientId;
261
+ this.#clientSecret = opts.clientSecret;
262
+ this.#reMint = opts.reMint;
263
+ this.#tokenBaseUrl = resolveTokenBase(opts);
264
+ this.#onTokenRefresh = opts.onTokenRefresh;
265
+ this.#store = opts.store;
266
+ this.#fetch = opts.fetch ?? fetch;
267
+ this.#now = opts.now ?? Date.now;
268
+ this.#leeway = opts.expiryLeewayMs ?? 3e4;
269
+ }
270
+ get current() {
271
+ return this.#tokens;
272
+ }
273
+ /** True if the manager can recover an expired token (rotate a refresh token or re-mint). */
274
+ get canRefresh() {
275
+ return Boolean(this.#tokens.refreshToken && this.#clientId || this.#reMint);
276
+ }
277
+ /** Returns a valid access token, refreshing proactively if it's expired/near-expiry. */
278
+ async getAccessToken() {
279
+ const { expiresAt } = this.#tokens;
280
+ if (expiresAt !== void 0 && this.#now() >= expiresAt - this.#leeway && this.canRefresh) {
281
+ await this.refresh();
282
+ }
283
+ return this.#tokens.accessToken;
284
+ }
285
+ /**
286
+ * Recover an expired/rejected token (e.g. after a 401): rotates the refresh token
287
+ * if there is one, otherwise re-mints (client_credentials). Coalesces concurrent
288
+ * calls into one network round-trip, then persists. Returns the new token set.
289
+ */
290
+ async refresh() {
291
+ if (this.#inflight) return this.#inflight;
292
+ const strategy = this.#recoveryStrategy();
293
+ if (!strategy) {
294
+ throw new WefunderAuthError(
295
+ "Access token expired and no refresh token / re-mint capability is configured."
296
+ );
297
+ }
298
+ this.#inflight = (async () => {
299
+ const next = await strategy();
300
+ this.#tokens = next;
301
+ await this.#store?.save(next);
302
+ await this.#onTokenRefresh?.(next);
303
+ return next;
304
+ })();
305
+ try {
306
+ return await this.#inflight;
307
+ } finally {
308
+ this.#inflight = void 0;
309
+ }
310
+ }
311
+ // Pick the recovery strategy: refresh_token rotation, else cc re-mint, else none.
312
+ #recoveryStrategy() {
313
+ const refreshTokenValue = this.#tokens.refreshToken;
314
+ if (refreshTokenValue && this.#clientId) {
315
+ const clientId = this.#clientId;
316
+ return async () => {
317
+ const next = await refreshToken({
318
+ clientId,
319
+ clientSecret: this.#clientSecret,
320
+ refreshToken: refreshTokenValue,
321
+ tokenBaseUrl: this.#tokenBaseUrl,
322
+ fetch: this.#fetch,
323
+ now: this.#now
324
+ });
325
+ if (!next.refreshToken) next.refreshToken = refreshTokenValue;
326
+ return next;
327
+ };
328
+ }
329
+ return this.#reMint;
330
+ }
331
+ };
332
+
333
+ // src/pagination.ts
334
+ async function* paginate(fetchPage) {
335
+ let cursor;
336
+ const seen = /* @__PURE__ */ new Set();
337
+ for (; ; ) {
338
+ const page = await fetchPage(cursor);
339
+ for (const item of page.data ?? []) yield item;
340
+ const meta = page.meta ?? {};
341
+ const next = meta.next_cursor;
342
+ if (meta.has_more === false) return;
343
+ if (next === void 0 || next === null) return;
344
+ if (seen.has(next)) return;
345
+ seen.add(next);
346
+ cursor = next;
347
+ }
348
+ }
349
+ async function collect(fetchPage) {
350
+ const out = [];
351
+ for await (const item of paginate(fetchPage)) out.push(item);
352
+ return out;
353
+ }
354
+
355
+ // src/generated/sdk.gen.ts
356
+ var sdk_gen_exports = {};
357
+ __export(sdk_gen_exports, {
358
+ approveSyndicateMember: () => approveSyndicateMember,
359
+ closeSyndicateDeal: () => closeSyndicateDeal,
360
+ createIntent: () => createIntent,
361
+ createPartnerInvite: () => createPartnerInvite,
362
+ createWebhookSubscription: () => createWebhookSubscription,
363
+ deleteWebhookSubscription: () => deleteWebhookSubscription,
364
+ demoteSyndicateMember: () => demoteSyndicateMember,
365
+ exportSyndicateMembersCsv: () => exportSyndicateMembersCsv,
366
+ finalizeSyndicateDeal: () => finalizeSyndicateDeal,
367
+ getAttributionMe: () => getAttributionMe,
368
+ getAttributionStats: () => getAttributionStats,
369
+ getCurrentUser: () => getCurrentUser,
370
+ getIntent: () => getIntent,
371
+ getOffering: () => getOffering,
372
+ getSyndicate: () => getSyndicate,
373
+ getSyndicateDeal: () => getSyndicateDeal,
374
+ getSyndicateStatistics: () => getSyndicateStatistics,
375
+ getWebhookSubscription: () => getWebhookSubscription,
376
+ hideSyndicateMember: () => hideSyndicateMember,
377
+ inviteSyndicateMember: () => inviteSyndicateMember,
378
+ listActivity: () => listActivity,
379
+ listAttributedInvestments: () => listAttributedInvestments,
380
+ listAttributionCampaigns: () => listAttributionCampaigns,
381
+ listCampaigns: () => listCampaigns,
382
+ listConnectedApps: () => listConnectedApps,
383
+ listIntents: () => listIntents,
384
+ listInvestments: () => listInvestments,
385
+ listOfferings: () => listOfferings,
386
+ listPartnerInvites: () => listPartnerInvites,
387
+ listSyndicateDealInvestors: () => listSyndicateDealInvestors,
388
+ listSyndicateDeals: () => listSyndicateDeals,
389
+ listSyndicateMemberInvestments: () => listSyndicateMemberInvestments,
390
+ listSyndicateMembers: () => listSyndicateMembers,
391
+ listSyndicates: () => listSyndicates,
392
+ listWebhookSubscriptions: () => listWebhookSubscriptions,
393
+ promoteSyndicateMember: () => promoteSyndicateMember,
394
+ reactivateWebhookSubscription: () => reactivateWebhookSubscription,
395
+ regenerateWebhookSecret: () => regenerateWebhookSecret,
396
+ registerAsPartner: () => registerAsPartner,
397
+ removeSyndicateMember: () => removeSyndicateMember,
398
+ reorderSyndicateMembers: () => reorderSyndicateMembers,
399
+ resendSyndicateInvite: () => resendSyndicateInvite,
400
+ restoreSyndicateMember: () => restoreSyndicateMember,
401
+ revokeConnectedApp: () => revokeConnectedApp,
402
+ revokePartnerInvite: () => revokePartnerInvite,
403
+ testWebhookSubscription: () => testWebhookSubscription,
404
+ updateSyndicate: () => updateSyndicate,
405
+ updateSyndicateMember: () => updateSyndicateMember
406
+ });
407
+
408
+ // src/generated/client.gen.ts
409
+ var import_client_fetch = require("@hey-api/client-fetch");
410
+ var client = (0, import_client_fetch.createClient)((0, import_client_fetch.createConfig)());
411
+
412
+ // src/generated/sdk.gen.ts
413
+ var listOfferings = (options) => {
414
+ return (options?.client ?? client).get({
415
+ security: [
416
+ {
417
+ scheme: "bearer",
418
+ type: "http"
419
+ }
420
+ ],
421
+ url: "/explore",
422
+ ...options
423
+ });
424
+ };
425
+ var getOffering = (options) => {
426
+ return (options.client ?? client).get({
427
+ security: [
428
+ {
429
+ scheme: "bearer",
430
+ type: "http"
431
+ }
432
+ ],
433
+ url: "/offerings/{external_id}",
434
+ ...options
435
+ });
436
+ };
437
+ var getCurrentUser = (options) => {
438
+ return (options?.client ?? client).get({
439
+ security: [
440
+ {
441
+ scheme: "bearer",
442
+ type: "http"
443
+ }
444
+ ],
445
+ url: "/users/me",
446
+ ...options
447
+ });
448
+ };
449
+ var listInvestments = (options) => {
450
+ return (options?.client ?? client).get({
451
+ security: [
452
+ {
453
+ scheme: "bearer",
454
+ type: "http"
455
+ }
456
+ ],
457
+ url: "/investments",
458
+ ...options
459
+ });
460
+ };
461
+ var listCampaigns = (options) => {
462
+ return (options?.client ?? client).get({
463
+ security: [
464
+ {
465
+ scheme: "bearer",
466
+ type: "http"
467
+ }
468
+ ],
469
+ url: "/campaigns",
470
+ ...options
471
+ });
472
+ };
473
+ var listSyndicates = (options) => {
474
+ return (options?.client ?? client).get({
475
+ security: [
476
+ {
477
+ scheme: "bearer",
478
+ type: "http"
479
+ }
480
+ ],
481
+ url: "/syndicates",
482
+ ...options
483
+ });
484
+ };
485
+ var getSyndicate = (options) => {
486
+ return (options.client ?? client).get({
487
+ security: [
488
+ {
489
+ scheme: "bearer",
490
+ type: "http"
491
+ }
492
+ ],
493
+ url: "/syndicates/{syndicate_id}",
494
+ ...options
495
+ });
496
+ };
497
+ var updateSyndicate = (options) => {
498
+ return (options.client ?? client).patch({
499
+ security: [
500
+ {
501
+ scheme: "bearer",
502
+ type: "http"
503
+ }
504
+ ],
505
+ url: "/syndicates/{syndicate_id}",
506
+ ...options,
507
+ headers: {
508
+ "Content-Type": "application/json",
509
+ ...options?.headers
510
+ }
511
+ });
512
+ };
513
+ var listSyndicateMembers = (options) => {
514
+ return (options.client ?? client).get({
515
+ security: [
516
+ {
517
+ scheme: "bearer",
518
+ type: "http"
519
+ }
520
+ ],
521
+ url: "/syndicates/{syndicate_id}/members",
522
+ ...options
523
+ });
524
+ };
525
+ var inviteSyndicateMember = (options) => {
526
+ return (options.client ?? client).post({
527
+ security: [
528
+ {
529
+ scheme: "bearer",
530
+ type: "http"
531
+ }
532
+ ],
533
+ url: "/syndicates/{syndicate_id}/members/invite",
534
+ ...options,
535
+ headers: {
536
+ "Content-Type": "application/json",
537
+ ...options?.headers
538
+ }
539
+ });
540
+ };
541
+ var removeSyndicateMember = (options) => {
542
+ return (options.client ?? client).delete({
543
+ security: [
544
+ {
545
+ scheme: "bearer",
546
+ type: "http"
547
+ }
548
+ ],
549
+ url: "/syndicates/{syndicate_id}/members/{member_id}",
550
+ ...options
551
+ });
552
+ };
553
+ var updateSyndicateMember = (options) => {
554
+ return (options.client ?? client).patch({
555
+ security: [
556
+ {
557
+ scheme: "bearer",
558
+ type: "http"
559
+ }
560
+ ],
561
+ url: "/syndicates/{syndicate_id}/members/{member_id}",
562
+ ...options,
563
+ headers: {
564
+ "Content-Type": "application/json",
565
+ ...options?.headers
566
+ }
567
+ });
568
+ };
569
+ var approveSyndicateMember = (options) => {
570
+ return (options.client ?? client).post({
571
+ security: [
572
+ {
573
+ scheme: "bearer",
574
+ type: "http"
575
+ }
576
+ ],
577
+ url: "/syndicates/{syndicate_id}/members/{member_id}/approve",
578
+ ...options
579
+ });
580
+ };
581
+ var hideSyndicateMember = (options) => {
582
+ return (options.client ?? client).post({
583
+ security: [
584
+ {
585
+ scheme: "bearer",
586
+ type: "http"
587
+ }
588
+ ],
589
+ url: "/syndicates/{syndicate_id}/members/{member_id}/hide",
590
+ ...options
591
+ });
592
+ };
593
+ var promoteSyndicateMember = (options) => {
594
+ return (options.client ?? client).post({
595
+ security: [
596
+ {
597
+ scheme: "bearer",
598
+ type: "http"
599
+ }
600
+ ],
601
+ url: "/syndicates/{syndicate_id}/members/{member_id}/promote",
602
+ ...options
603
+ });
604
+ };
605
+ var demoteSyndicateMember = (options) => {
606
+ return (options.client ?? client).post({
607
+ security: [
608
+ {
609
+ scheme: "bearer",
610
+ type: "http"
611
+ }
612
+ ],
613
+ url: "/syndicates/{syndicate_id}/members/{member_id}/demote",
614
+ ...options
615
+ });
616
+ };
617
+ var restoreSyndicateMember = (options) => {
618
+ return (options.client ?? client).post({
619
+ security: [
620
+ {
621
+ scheme: "bearer",
622
+ type: "http"
623
+ }
624
+ ],
625
+ url: "/syndicates/{syndicate_id}/members/{member_id}/restore",
626
+ ...options
627
+ });
628
+ };
629
+ var resendSyndicateInvite = (options) => {
630
+ return (options.client ?? client).post({
631
+ security: [
632
+ {
633
+ scheme: "bearer",
634
+ type: "http"
635
+ }
636
+ ],
637
+ url: "/syndicates/{syndicate_id}/members/{member_id}/resend_invite",
638
+ ...options
639
+ });
640
+ };
641
+ var reorderSyndicateMembers = (options) => {
642
+ return (options.client ?? client).post({
643
+ security: [
644
+ {
645
+ scheme: "bearer",
646
+ type: "http"
647
+ }
648
+ ],
649
+ url: "/syndicates/{syndicate_id}/members/reorder",
650
+ ...options,
651
+ headers: {
652
+ "Content-Type": "application/json",
653
+ ...options?.headers
654
+ }
655
+ });
656
+ };
657
+ var exportSyndicateMembersCsv = (options) => {
658
+ return (options.client ?? client).post({
659
+ security: [
660
+ {
661
+ scheme: "bearer",
662
+ type: "http"
663
+ }
664
+ ],
665
+ url: "/syndicates/{syndicate_id}/members/export_csv",
666
+ ...options
667
+ });
668
+ };
669
+ var listSyndicateDeals = (options) => {
670
+ return (options.client ?? client).get({
671
+ security: [
672
+ {
673
+ scheme: "bearer",
674
+ type: "http"
675
+ }
676
+ ],
677
+ url: "/syndicates/{syndicate_id}/deals",
678
+ ...options
679
+ });
680
+ };
681
+ var getSyndicateDeal = (options) => {
682
+ return (options.client ?? client).get({
683
+ security: [
684
+ {
685
+ scheme: "bearer",
686
+ type: "http"
687
+ }
688
+ ],
689
+ url: "/syndicates/{syndicate_id}/deals/{fundraise_id}",
690
+ ...options
691
+ });
692
+ };
693
+ var listSyndicateDealInvestors = (options) => {
694
+ return (options.client ?? client).get({
695
+ security: [
696
+ {
697
+ scheme: "bearer",
698
+ type: "http"
699
+ }
700
+ ],
701
+ url: "/syndicates/{syndicate_id}/deals/{fundraise_id}/investors",
702
+ ...options
703
+ });
704
+ };
705
+ var listSyndicateMemberInvestments = (options) => {
706
+ return (options.client ?? client).get({
707
+ security: [
708
+ {
709
+ scheme: "bearer",
710
+ type: "http"
711
+ }
712
+ ],
713
+ url: "/syndicates/{syndicate_id}/members/{member_id}/investments",
714
+ ...options
715
+ });
716
+ };
717
+ var getSyndicateStatistics = (options) => {
718
+ return (options.client ?? client).get({
719
+ security: [
720
+ {
721
+ scheme: "bearer",
722
+ type: "http"
723
+ }
724
+ ],
725
+ url: "/syndicates/{syndicate_id}/statistics",
726
+ ...options
727
+ });
728
+ };
729
+ var closeSyndicateDeal = (options) => {
730
+ return (options.client ?? client).post({
731
+ security: [
732
+ {
733
+ scheme: "bearer",
734
+ type: "http"
735
+ }
736
+ ],
737
+ url: "/syndicates/{syndicate_id}/deals/{fundraise_id}/close",
738
+ ...options
739
+ });
740
+ };
741
+ var finalizeSyndicateDeal = (options) => {
742
+ return (options.client ?? client).post({
743
+ security: [
744
+ {
745
+ scheme: "bearer",
746
+ type: "http"
747
+ }
748
+ ],
749
+ url: "/syndicates/{syndicate_id}/deals/{fundraise_id}/finalize",
750
+ ...options
751
+ });
752
+ };
753
+ var listIntents = (options) => {
754
+ return (options?.client ?? client).get({
755
+ security: [
756
+ {
757
+ scheme: "bearer",
758
+ type: "http"
759
+ }
760
+ ],
761
+ url: "/intents",
762
+ ...options
763
+ });
764
+ };
765
+ var createIntent = (options) => {
766
+ return (options.client ?? client).post({
767
+ security: [
768
+ {
769
+ scheme: "bearer",
770
+ type: "http"
771
+ }
772
+ ],
773
+ url: "/intents",
774
+ ...options,
775
+ headers: {
776
+ "Content-Type": "application/json",
777
+ ...options?.headers
778
+ }
779
+ });
780
+ };
781
+ var getIntent = (options) => {
782
+ return (options.client ?? client).get({
783
+ security: [
784
+ {
785
+ scheme: "bearer",
786
+ type: "http"
787
+ }
788
+ ],
789
+ url: "/intents/{intent_id}",
790
+ ...options
791
+ });
792
+ };
793
+ var listActivity = (options) => {
794
+ return (options?.client ?? client).get({
795
+ security: [
796
+ {
797
+ scheme: "bearer",
798
+ type: "http"
799
+ }
800
+ ],
801
+ url: "/activity",
802
+ ...options
803
+ });
804
+ };
805
+ var listConnectedApps = (options) => {
806
+ return (options?.client ?? client).get({
807
+ security: [
808
+ {
809
+ scheme: "bearer",
810
+ type: "http"
811
+ }
812
+ ],
813
+ url: "/connected-apps",
814
+ ...options
815
+ });
816
+ };
817
+ var revokeConnectedApp = (options) => {
818
+ return (options.client ?? client).delete({
819
+ security: [
820
+ {
821
+ scheme: "bearer",
822
+ type: "http"
823
+ }
824
+ ],
825
+ url: "/connected-apps/{app_id}",
826
+ ...options
827
+ });
828
+ };
829
+ var getAttributionStats = (options) => {
830
+ return (options.client ?? client).get({
831
+ security: [
832
+ {
833
+ scheme: "bearer",
834
+ type: "http"
835
+ }
836
+ ],
837
+ url: "/campaigns/{campaign_id}/attribution/stats",
838
+ ...options
839
+ });
840
+ };
841
+ var listAttributedInvestments = (options) => {
842
+ return (options.client ?? client).get({
843
+ security: [
844
+ {
845
+ scheme: "bearer",
846
+ type: "http"
847
+ }
848
+ ],
849
+ url: "/campaigns/{campaign_id}/attribution/investments",
850
+ ...options
851
+ });
852
+ };
853
+ var listWebhookSubscriptions = (options) => {
854
+ return (options.client ?? client).get({
855
+ security: [
856
+ {
857
+ scheme: "bearer",
858
+ type: "http"
859
+ }
860
+ ],
861
+ url: "/campaigns/{campaign_id}/attribution/webhooks",
862
+ ...options
863
+ });
864
+ };
865
+ var createWebhookSubscription = (options) => {
866
+ return (options.client ?? client).post({
867
+ security: [
868
+ {
869
+ scheme: "bearer",
870
+ type: "http"
871
+ }
872
+ ],
873
+ url: "/campaigns/{campaign_id}/attribution/webhooks",
874
+ ...options,
875
+ headers: {
876
+ "Content-Type": "application/json",
877
+ ...options?.headers
878
+ }
879
+ });
880
+ };
881
+ var deleteWebhookSubscription = (options) => {
882
+ return (options.client ?? client).delete({
883
+ security: [
884
+ {
885
+ scheme: "bearer",
886
+ type: "http"
887
+ }
888
+ ],
889
+ url: "/campaigns/{campaign_id}/attribution/webhooks/{webhook_id}",
890
+ ...options
891
+ });
892
+ };
893
+ var getWebhookSubscription = (options) => {
894
+ return (options.client ?? client).get({
895
+ security: [
896
+ {
897
+ scheme: "bearer",
898
+ type: "http"
899
+ }
900
+ ],
901
+ url: "/campaigns/{campaign_id}/attribution/webhooks/{webhook_id}",
902
+ ...options
903
+ });
904
+ };
905
+ var testWebhookSubscription = (options) => {
906
+ return (options.client ?? client).post({
907
+ security: [
908
+ {
909
+ scheme: "bearer",
910
+ type: "http"
911
+ }
912
+ ],
913
+ url: "/campaigns/{campaign_id}/attribution/webhooks/{webhook_id}/test",
914
+ ...options
915
+ });
916
+ };
917
+ var regenerateWebhookSecret = (options) => {
918
+ return (options.client ?? client).post({
919
+ security: [
920
+ {
921
+ scheme: "bearer",
922
+ type: "http"
923
+ }
924
+ ],
925
+ url: "/campaigns/{campaign_id}/attribution/webhooks/{webhook_id}/regenerate_secret",
926
+ ...options
927
+ });
928
+ };
929
+ var reactivateWebhookSubscription = (options) => {
930
+ return (options.client ?? client).post({
931
+ security: [
932
+ {
933
+ scheme: "bearer",
934
+ type: "http"
935
+ }
936
+ ],
937
+ url: "/campaigns/{campaign_id}/attribution/webhooks/{webhook_id}/reactivate",
938
+ ...options
939
+ });
940
+ };
941
+ var getAttributionMe = (options) => {
942
+ return (options?.client ?? client).get({
943
+ security: [
944
+ {
945
+ scheme: "bearer",
946
+ type: "http"
947
+ }
948
+ ],
949
+ url: "/attribution/me",
950
+ ...options
951
+ });
952
+ };
953
+ var listAttributionCampaigns = (options) => {
954
+ return (options?.client ?? client).get({
955
+ security: [
956
+ {
957
+ scheme: "bearer",
958
+ type: "http"
959
+ }
960
+ ],
961
+ url: "/attribution/campaigns",
962
+ ...options
963
+ });
964
+ };
965
+ var registerAsPartner = (options) => {
966
+ return (options.client ?? client).post({
967
+ security: [
968
+ {
969
+ scheme: "bearer",
970
+ type: "http"
971
+ }
972
+ ],
973
+ url: "/attribution/partners/register",
974
+ ...options,
975
+ headers: {
976
+ "Content-Type": "application/json",
977
+ ...options?.headers
978
+ }
979
+ });
980
+ };
981
+ var listPartnerInvites = (options) => {
982
+ return (options?.client ?? client).get({
983
+ security: [
984
+ {
985
+ scheme: "bearer",
986
+ type: "http"
987
+ }
988
+ ],
989
+ url: "/attribution/invites",
990
+ ...options
991
+ });
992
+ };
993
+ var createPartnerInvite = (options) => {
994
+ return (options.client ?? client).post({
995
+ security: [
996
+ {
997
+ scheme: "bearer",
998
+ type: "http"
999
+ }
1000
+ ],
1001
+ url: "/attribution/invites",
1002
+ ...options,
1003
+ headers: {
1004
+ "Content-Type": "application/json",
1005
+ ...options?.headers
1006
+ }
1007
+ });
1008
+ };
1009
+ var revokePartnerInvite = (options) => {
1010
+ return (options.client ?? client).delete({
1011
+ security: [
1012
+ {
1013
+ scheme: "bearer",
1014
+ type: "http"
1015
+ }
1016
+ ],
1017
+ url: "/attribution/invites/{token}",
1018
+ ...options
1019
+ });
1020
+ };
1021
+
1022
+ // src/client.ts
1023
+ var DEFAULT_API_BASE_URL = "https://api.wefunder.com/api/v2";
1024
+ var DEFAULT_API_VERSION = "2025-01-15";
1025
+ function modeForToken(token) {
1026
+ if (token.startsWith("at_live_")) return "live";
1027
+ if (token.startsWith("at_test_")) return "test";
1028
+ return "unknown";
1029
+ }
1030
+ var Wefunder = class _Wefunder {
1031
+ mode;
1032
+ raw;
1033
+ #client;
1034
+ #tokens;
1035
+ constructor(opts) {
1036
+ const tokenSet = opts.tokens ?? (opts.accessToken ? { accessToken: opts.accessToken } : void 0);
1037
+ if (!tokenSet) {
1038
+ throw new Error("Wefunder: provide `accessToken` or `tokens`.");
1039
+ }
1040
+ this.mode = modeForToken(tokenSet.accessToken);
1041
+ const reMint = opts.clientCredentials && opts.clientId && opts.clientSecret ? () => clientCredentialsGrant({
1042
+ clientId: opts.clientId,
1043
+ clientSecret: opts.clientSecret,
1044
+ scopes: opts.clientCredentials.scopes,
1045
+ oauthBaseUrl: opts.oauthBaseUrl,
1046
+ tokenBaseUrl: opts.tokenBaseUrl,
1047
+ fetch: opts.fetch,
1048
+ now: opts.now
1049
+ }) : void 0;
1050
+ this.#tokens = new TokenManager({
1051
+ tokens: tokenSet,
1052
+ clientId: opts.clientId,
1053
+ clientSecret: opts.clientSecret,
1054
+ reMint,
1055
+ oauthBaseUrl: opts.oauthBaseUrl,
1056
+ tokenBaseUrl: opts.tokenBaseUrl,
1057
+ onTokenRefresh: opts.onTokenRefresh,
1058
+ store: opts.store,
1059
+ fetch: opts.fetch,
1060
+ now: opts.now
1061
+ });
1062
+ const wrappedFetch = createFetch({
1063
+ tokenManager: this.#tokens,
1064
+ fetch: opts.fetch,
1065
+ now: opts.now,
1066
+ sleep: opts.sleep,
1067
+ random: opts.random,
1068
+ retry: opts.retry
1069
+ });
1070
+ this.#client = (0, import_client_fetch2.createClient)({
1071
+ baseUrl: opts.baseUrl ?? DEFAULT_API_BASE_URL,
1072
+ headers: { "Wefunder-Version": opts.apiVersion ?? DEFAULT_API_VERSION },
1073
+ auth: () => this.#tokens.getAccessToken(),
1074
+ fetch: wrappedFetch
1075
+ });
1076
+ this.raw = this.#buildRaw();
1077
+ }
1078
+ /** Server-to-server: exchange client credentials for a token, then build a client. */
1079
+ static async fromClientCredentials(opts) {
1080
+ const tokens = await clientCredentialsGrant({
1081
+ clientId: opts.clientId,
1082
+ clientSecret: opts.clientSecret,
1083
+ scopes: opts.scopes,
1084
+ oauthBaseUrl: opts.oauthBaseUrl,
1085
+ tokenBaseUrl: opts.tokenBaseUrl,
1086
+ fetch: opts.fetch,
1087
+ now: opts.now
1088
+ });
1089
+ return new _Wefunder({
1090
+ tokens,
1091
+ clientId: opts.clientId,
1092
+ clientSecret: opts.clientSecret,
1093
+ clientCredentials: { scopes: opts.scopes },
1094
+ // enables auto-re-mint on expiry/401
1095
+ oauthBaseUrl: opts.oauthBaseUrl,
1096
+ tokenBaseUrl: opts.tokenBaseUrl,
1097
+ apiVersion: opts.apiVersion,
1098
+ baseUrl: opts.baseUrl,
1099
+ fetch: opts.fetch,
1100
+ now: opts.now
1101
+ });
1102
+ }
1103
+ /** The live token set (e.g. to persist after construction). */
1104
+ get tokens() {
1105
+ return this.#tokens.current;
1106
+ }
1107
+ // ---- unwrap: turn the {data,error,response} result into data-or-throw ----
1108
+ async #unwrap(p) {
1109
+ const { data, error, response } = await p;
1110
+ if (response && response.ok && error === void 0) return data;
1111
+ const status = response?.status ?? 0;
1112
+ const env = error ?? {};
1113
+ throw new WefunderError({
1114
+ status,
1115
+ type: env.error?.type ?? "api_error",
1116
+ message: env.error?.message ?? response?.statusText ?? "Request failed",
1117
+ // X-Wf-Request-Id header is primary (present even on non-JSON edge errors).
1118
+ requestId: requestIdFrom(response, env.error?.request_id ?? env.request_id),
1119
+ details: env.error?.details,
1120
+ remediation: env.error?.remediation
1121
+ });
1122
+ }
1123
+ // Single-resource ops return a `{ data: Entity }` envelope; strip it for ergonomics.
1124
+ async #unwrapData(p) {
1125
+ const env = await this.#unwrap(p);
1126
+ return env.data;
1127
+ }
1128
+ #buildRaw() {
1129
+ const raw = {};
1130
+ for (const [name, fn] of Object.entries(sdk_gen_exports)) {
1131
+ raw[name] = (options) => fn({ ...options, client: this.#client });
1132
+ }
1133
+ return raw;
1134
+ }
1135
+ /**
1136
+ * Unwrap any generated op result (incl. `wf.raw.*`) the way the ergonomic
1137
+ * namespaces do: returns the response body on success, throws a typed
1138
+ * `WefunderError` (with `request_id`) on failure. Lets `raw` callers keep the
1139
+ * SDK's error handling. (Stress-test finding C.)
1140
+ */
1141
+ unwrap(p) {
1142
+ return this.#unwrap(p);
1143
+ }
1144
+ // Generic page helper: forwards the endpoint's full query (cursor + documented
1145
+ // params like `sort`), not just the cursor. (Stress-test finding B.)
1146
+ #page(fn) {
1147
+ return (query) => this.#unwrap(fn({ client: this.#client, query }));
1148
+ }
1149
+ // ---- resource namespaces (common GA paths) ----
1150
+ users = {
1151
+ me: () => this.#unwrapData(getCurrentUser({ client: this.#client }))
1152
+ };
1153
+ offerings = {
1154
+ list: this.#page(listOfferings),
1155
+ all: (query) => paginate((cursor) => this.offerings.list({ ...query, cursor })),
1156
+ collect: (query) => collect((cursor) => this.offerings.list({ ...query, cursor })),
1157
+ get: (externalId) => this.#unwrapData(
1158
+ getOffering({ client: this.#client, path: { external_id: externalId } })
1159
+ )
1160
+ };
1161
+ investments = {
1162
+ list: this.#page(listInvestments),
1163
+ all: () => paginate((cursor) => this.investments.list({ cursor })),
1164
+ collect: () => collect((cursor) => this.investments.list({ cursor }))
1165
+ };
1166
+ campaigns = {
1167
+ list: this.#page(listCampaigns),
1168
+ all: () => paginate((cursor) => this.campaigns.list({ cursor })),
1169
+ collect: () => collect((cursor) => this.campaigns.list({ cursor }))
1170
+ };
1171
+ syndicates = {
1172
+ list: this.#page(listSyndicates),
1173
+ all: () => paginate((cursor) => this.syndicates.list({ cursor })),
1174
+ get: (id) => this.#unwrapData(getSyndicate({ client: this.#client, path: { id } }))
1175
+ };
1176
+ intents = {
1177
+ list: this.#page(listIntents),
1178
+ all: () => paginate((cursor) => this.intents.list({ cursor })),
1179
+ get: (id) => this.#unwrapData(getIntent({ client: this.#client, path: { id } }))
1180
+ };
1181
+ attribution = {
1182
+ me: () => this.#unwrapData(getAttributionMe({ client: this.#client }))
1183
+ };
1184
+ };
1185
+
1186
+ // src/webhooks.ts
1187
+ var import_node_crypto2 = require("crypto");
1188
+ var SIGNATURE_HEADER = "x-wefunder-signature";
1189
+ var TIMESTAMP_HEADER = "x-wefunder-timestamp";
1190
+ var EVENT_HEADER = "x-wefunder-event";
1191
+ var DELIVERY_ID_HEADER = "x-wefunder-delivery-id";
1192
+ function computeSignature(secret, timestamp, payload) {
1193
+ const mac = (0, import_node_crypto2.createHmac)("sha256", secret).update(`${timestamp}.${payload}`).digest("hex");
1194
+ return `sha256=${mac}`;
1195
+ }
1196
+ function constantTimeEqual(a, b) {
1197
+ const ab = Buffer.from(a);
1198
+ const bb = Buffer.from(b);
1199
+ if (ab.length !== bb.length) return false;
1200
+ return (0, import_node_crypto2.timingSafeEqual)(ab, bb);
1201
+ }
1202
+ function verifyWebhook(opts) {
1203
+ const tolerance = opts.toleranceSeconds ?? 300;
1204
+ const now = (opts.now ?? Date.now)();
1205
+ const ts = Number(opts.timestamp);
1206
+ if (!Number.isFinite(ts)) return false;
1207
+ if (tolerance > 0 && Math.abs(now / 1e3 - ts) > tolerance) return false;
1208
+ const expected = computeSignature(opts.secret, opts.timestamp, opts.payload);
1209
+ return constantTimeEqual(opts.signature, expected);
1210
+ }
1211
+ function constructEvent(payload, headers, secret, opts) {
1212
+ const get = (name) => {
1213
+ if (headers instanceof Headers) return headers.get(name) ?? void 0;
1214
+ const v = headers[name] ?? headers[name.toLowerCase()];
1215
+ return Array.isArray(v) ? v[0] : v;
1216
+ };
1217
+ const signature = get(SIGNATURE_HEADER);
1218
+ const timestamp = get(TIMESTAMP_HEADER);
1219
+ if (!signature || !timestamp) {
1220
+ throw new Error("Missing X-Wefunder-Signature or X-Wefunder-Timestamp header");
1221
+ }
1222
+ const ok = verifyWebhook({
1223
+ payload,
1224
+ signature,
1225
+ timestamp,
1226
+ secret,
1227
+ toleranceSeconds: opts?.toleranceSeconds,
1228
+ now: opts?.now
1229
+ });
1230
+ if (!ok) throw new Error("Webhook signature verification failed");
1231
+ return {
1232
+ event: get(EVENT_HEADER) ?? "",
1233
+ deliveryId: get(DELIVERY_ID_HEADER) ?? "",
1234
+ timestamp: Number(timestamp),
1235
+ data: JSON.parse(payload)
1236
+ };
1237
+ }
1238
+ // Annotate the CommonJS export names for ESM import in node:
1239
+ 0 && (module.exports = {
1240
+ DEFAULT_API_BASE_URL,
1241
+ DEFAULT_API_VERSION,
1242
+ DEFAULT_AUTHORIZE_BASE_URL,
1243
+ DEFAULT_OAUTH_BASE_URL,
1244
+ DEFAULT_TOKEN_BASE_URL,
1245
+ DELIVERY_ID_HEADER,
1246
+ EVENT_HEADER,
1247
+ REQUEST_ID_HEADER,
1248
+ SIGNATURE_HEADER,
1249
+ TIMESTAMP_HEADER,
1250
+ Wefunder,
1251
+ WefunderAuthError,
1252
+ WefunderError,
1253
+ clientCredentialsGrant,
1254
+ collect,
1255
+ constructEvent,
1256
+ createAuthorizationUrl,
1257
+ exchangeCode,
1258
+ generatePkce,
1259
+ modeForToken,
1260
+ paginate,
1261
+ refreshToken,
1262
+ verifyWebhook
1263
+ });
1264
+ //# sourceMappingURL=index.cjs.map