dupr-js-client 1.0.1 → 2.2.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.d.ts +80 -20
- package/dist/index.js +30 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -101,20 +101,29 @@ declare class HttpClient {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
type MatchFormat = "SINGLES" | "DOUBLES";
|
|
104
|
-
type MatchSource = "PARTNER" | "CLUB";
|
|
104
|
+
type MatchSource = "DUPR" | "LEAGUE" | "PARTNER" | "CLUB";
|
|
105
|
+
type MatchType = "RALLY" | "SIDEOUT";
|
|
106
|
+
type MatchCompletionType = "FORFEIT" | "WITHDRAWAL" | "RETIREMENT" | "COMPLETED" | "UNKNOWN";
|
|
107
|
+
type MatchPlayType = "RECREATIONAL" | "TOURNAMENT" | "LEAGUE" | "INFORMATIONAL" | "UNKNOWN";
|
|
105
108
|
type Gender = "MALE" | "FEMALE";
|
|
106
109
|
type RatingType = "SINGLES" | "DOUBLES";
|
|
107
110
|
type WebhookTopic = "RATING";
|
|
108
|
-
type ApiStatus = "SUCCESS" | "FAILURE";
|
|
111
|
+
type ApiStatus = "SUCCESS" | "FAILURE" | "REDIRECT" | "PARTIAL";
|
|
109
112
|
interface ApiWrapper<T = unknown> {
|
|
110
113
|
status: ApiStatus;
|
|
111
114
|
message?: string;
|
|
112
115
|
result?: T;
|
|
113
116
|
}
|
|
114
117
|
interface TokenResponse {
|
|
118
|
+
/** Flat format (some DUPR environments return the token directly at the top level). */
|
|
115
119
|
token?: string;
|
|
116
120
|
accessToken?: string;
|
|
117
121
|
expiresIn?: number;
|
|
122
|
+
/** Wrapped format — the Partner API auth endpoint returns { status, result: { token, expiry } }. */
|
|
123
|
+
result?: {
|
|
124
|
+
token?: string;
|
|
125
|
+
expiry?: string;
|
|
126
|
+
};
|
|
118
127
|
}
|
|
119
128
|
interface UserInfo {
|
|
120
129
|
duprId: string;
|
|
@@ -193,30 +202,70 @@ interface UpdateProvisionalRatingRequest {
|
|
|
193
202
|
interface DeleteProvisionalRatingRequest {
|
|
194
203
|
duprId: string;
|
|
195
204
|
}
|
|
196
|
-
interface ExternalMatchPlayer {
|
|
197
|
-
duprId: string;
|
|
198
|
-
}
|
|
199
205
|
interface ExternalMatchTeam {
|
|
200
|
-
/**
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
|
|
206
|
+
/** DUPR ID of player 1. Required for both SINGLES and DOUBLES. */
|
|
207
|
+
player1: string;
|
|
208
|
+
/** DUPR ID of player 2. Required for DOUBLES; omit for SINGLES. */
|
|
209
|
+
player2?: string;
|
|
210
|
+
game1: number;
|
|
211
|
+
game2?: number;
|
|
212
|
+
game3?: number;
|
|
213
|
+
game4?: number;
|
|
214
|
+
game5?: number;
|
|
204
215
|
}
|
|
205
216
|
interface ExternalMatchRequest {
|
|
206
|
-
/**
|
|
217
|
+
/** Universally unique identifier for this match — must never be reused. */
|
|
207
218
|
identifier: string;
|
|
208
|
-
/** yyyy-MM-dd */
|
|
219
|
+
/** yyyy-MM-dd (ISO 8601 date). */
|
|
209
220
|
matchDate: string;
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
221
|
+
/** Match format: SINGLES or DOUBLES. Required. */
|
|
222
|
+
format: MatchFormat;
|
|
223
|
+
teamA: ExternalMatchTeam;
|
|
224
|
+
teamB: ExternalMatchTeam;
|
|
225
|
+
/** Event name in which this match was played. Required. */
|
|
226
|
+
event: string;
|
|
227
|
+
/** RALLY or SIDEOUT scoring format. */
|
|
228
|
+
matchType?: MatchType;
|
|
229
|
+
/** Source of the match. */
|
|
230
|
+
matchSource?: MatchSource;
|
|
231
|
+
/** Display-only location string. */
|
|
232
|
+
location?: string;
|
|
233
|
+
/** Display-only bracket name. */
|
|
234
|
+
bracket?: string;
|
|
235
|
+
/** DUPR Club unique identifier. Required when matchSource is CLUB. */
|
|
236
|
+
clubId?: string | number;
|
|
237
|
+
/** Optional key-value metadata. */
|
|
238
|
+
extras?: Record<string, string>;
|
|
239
|
+
matchCompletionType?: MatchCompletionType;
|
|
240
|
+
matchPlayType?: MatchPlayType;
|
|
215
241
|
}
|
|
216
242
|
interface ExternalUpdateMatchRequest {
|
|
217
|
-
|
|
243
|
+
/** DUPR internal match ID returned in the create response. Required. */
|
|
244
|
+
matchId: number;
|
|
245
|
+
/** Universally unique identifier for this match. */
|
|
246
|
+
identifier?: string;
|
|
247
|
+
/** yyyy-MM-dd (ISO 8601 date). */
|
|
218
248
|
matchDate?: string;
|
|
219
|
-
|
|
249
|
+
/** Match format: SINGLES or DOUBLES. */
|
|
250
|
+
format?: MatchFormat;
|
|
251
|
+
teamA?: ExternalMatchTeam;
|
|
252
|
+
teamB?: ExternalMatchTeam;
|
|
253
|
+
/** Event name in which this match was played. */
|
|
254
|
+
event?: string;
|
|
255
|
+
/** RALLY or SIDEOUT scoring format. */
|
|
256
|
+
matchType?: MatchType;
|
|
257
|
+
/** Source of the match. */
|
|
258
|
+
matchSource?: MatchSource;
|
|
259
|
+
/** Display-only location string. */
|
|
260
|
+
location?: string;
|
|
261
|
+
/** Display-only bracket name. */
|
|
262
|
+
bracket?: string;
|
|
263
|
+
/** DUPR Club unique identifier. */
|
|
264
|
+
clubId?: string | number;
|
|
265
|
+
/** Optional key-value metadata. */
|
|
266
|
+
extras?: Record<string, string>;
|
|
267
|
+
matchCompletionType?: MatchCompletionType;
|
|
268
|
+
matchPlayType?: MatchPlayType;
|
|
220
269
|
}
|
|
221
270
|
interface ExternalDeleteMatchRequest {
|
|
222
271
|
matchCode: string;
|
|
@@ -269,7 +318,7 @@ interface CreateEventRequestV1 {
|
|
|
269
318
|
startDate: string;
|
|
270
319
|
endDate: string;
|
|
271
320
|
location?: string;
|
|
272
|
-
clubId?: number;
|
|
321
|
+
clubId?: string | number;
|
|
273
322
|
}
|
|
274
323
|
interface UpdateEventRequestV1 {
|
|
275
324
|
eventId: string;
|
|
@@ -336,6 +385,8 @@ interface AuthorizationUrlParams {
|
|
|
336
385
|
scopes?: string[];
|
|
337
386
|
/** Opaque value passed through the flow to prevent CSRF. Recommended. */
|
|
338
387
|
state?: string;
|
|
388
|
+
/** PKCE code_challenge (S256). Generate the pair with `client.auth.generatePkce()`. */
|
|
389
|
+
codeChallenge?: string;
|
|
339
390
|
}
|
|
340
391
|
declare class AuthModule {
|
|
341
392
|
private readonly http;
|
|
@@ -346,9 +397,16 @@ declare class AuthModule {
|
|
|
346
397
|
* Normally you don't need to call this — the HTTP client handles token refresh automatically.
|
|
347
398
|
*/
|
|
348
399
|
getToken(): Promise<TokenResponse>;
|
|
400
|
+
/** Generate a PKCE `code_verifier` + `code_challenge` pair (S256 method).
|
|
401
|
+
* Pass `codeChallenge` to `getAuthorizationUrl()` and `codeVerifier` to `exchangeCode()`. */
|
|
402
|
+
generatePkce(): {
|
|
403
|
+
codeVerifier: string;
|
|
404
|
+
codeChallenge: string;
|
|
405
|
+
};
|
|
349
406
|
/**
|
|
350
407
|
* Build the DUPR authorization URL to redirect the user to for login.
|
|
351
408
|
* The `authorizationUrl` config option must be set (see above note).
|
|
409
|
+
* Pass `codeChallenge` (from `generatePkce()`) to enable PKCE.
|
|
352
410
|
*/
|
|
353
411
|
getAuthorizationUrl(params: AuthorizationUrlParams): string;
|
|
354
412
|
/**
|
|
@@ -358,6 +416,8 @@ declare class AuthModule {
|
|
|
358
416
|
exchangeCode(params: {
|
|
359
417
|
code: string;
|
|
360
418
|
redirectUri: string;
|
|
419
|
+
/** PKCE code_verifier. Required if `codeChallenge` was passed to `getAuthorizationUrl()`. */
|
|
420
|
+
codeVerifier?: string;
|
|
361
421
|
}): Promise<AuthCodeTokenResponse>;
|
|
362
422
|
/**
|
|
363
423
|
* Returns the DUPR SSO iframe URL. Embed this in an `<iframe allow="payment">` to
|
|
@@ -557,4 +617,4 @@ declare class ServerError extends DuprApiError {
|
|
|
557
617
|
constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string);
|
|
558
618
|
}
|
|
559
619
|
|
|
560
|
-
export { type ApiStatus, type ApiWrapper, type AttributionRequest, type AuthCodeTokenResponse, type AuthMode, AuthModule, AuthenticationError, type AuthorizationUrlParams, type ClientHookRequest, type ClubMembership, type ClubMembershipResponse, ClubsModule, type CreateEventRequestV1, type CreateEventResponseV1, type CreateProvisionalRatingRequest, type DeleteEventRequestV1, type DeleteEventResponseV1, type DeleteProvisionalRatingRequest, DuprApiError, DuprClient, type DuprClientOptions, EventsModule, type ExtendedUserInfo, type ExternalAgeRangeFilter, type ExternalBatchUserDetailRequest, type ExternalClubMatchSearchRequest, type ExternalClubMemberRequest, type ExternalDeleteMatchRequest, type ExternalFilterLocation, type ExternalInviteRequest, type
|
|
620
|
+
export { type ApiStatus, type ApiWrapper, type AttributionRequest, type AuthCodeTokenResponse, type AuthMode, AuthModule, AuthenticationError, type AuthorizationUrlParams, type ClientHookRequest, type ClubMembership, type ClubMembershipResponse, ClubsModule, type CreateEventRequestV1, type CreateEventResponseV1, type CreateProvisionalRatingRequest, type DeleteEventRequestV1, type DeleteEventResponseV1, type DeleteProvisionalRatingRequest, DuprApiError, DuprClient, type DuprClientOptions, EventsModule, type ExtendedUserInfo, type ExternalAgeRangeFilter, type ExternalBatchUserDetailRequest, type ExternalClubMatchSearchRequest, type ExternalClubMemberRequest, type ExternalDeleteMatchRequest, type ExternalFilterLocation, type ExternalInviteRequest, type ExternalMatchRequest, type ExternalMatchSearchRequest, type ExternalMatchTeam, type ExternalRatingFilter, type ExternalSearchFilter, type ExternalSearchRequest, type ExternalUpdateMatchRequest, type Gender, type GetEventRequestV1, type GetEventResponseV1, type GetProvisionalRatingRequest, type GrantExternalSubscriptionRequest, type MatchCompletionType, type MatchFormat, type MatchPlayType, type MatchResponse, type MatchSource, type MatchType, MatchesModule, NotFoundError, PlayerRatingModule, type PlayerRatingSubscribeRequest, PlayersModule, RateLimitError, type RatingCoach, type RatingType, type RequestInfo, type ResolvedConfig, type ResolvedRetryOptions, type ResponseInfo, type RetryOptions, ServerError, type SsoTokenResponse, type SubscriptionItemRequest, type TargetUserRequest, type TokenResponse, type UpdateEventRequestV1, type UpdateEventResponseV1, type UpdateProvisionalRatingRequest, type UserInfo, type UserWebhookRequest, UsersModule, ValidationError, type WebhookSchema, type WebhookTopic, WebhooksModule };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { randomBytes, createHash } from 'crypto';
|
|
2
|
+
|
|
1
3
|
// src/config.ts
|
|
2
4
|
function resolveConfig(opts) {
|
|
3
5
|
const cfg = {
|
|
@@ -139,10 +141,14 @@ var HttpClient = class {
|
|
|
139
141
|
this.config.onResponse?.({ status: res.status, url, durationMs: Date.now() - start });
|
|
140
142
|
if (!res.ok) throw await buildError(res);
|
|
141
143
|
const body = await res.json();
|
|
142
|
-
this.token = body.token ?? body.accessToken ?? null;
|
|
144
|
+
this.token = body.result?.token ?? body.token ?? body.accessToken ?? null;
|
|
143
145
|
if (!this.token) throw new AuthenticationError("Token response contained no token", 401);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
if (body.result?.expiry) {
|
|
147
|
+
this.tokenExpiresAt = new Date(body.result.expiry).getTime() - 6e4;
|
|
148
|
+
} else {
|
|
149
|
+
const ttlSec = body.expiresIn ?? 3600;
|
|
150
|
+
this.tokenExpiresAt = Date.now() + (ttlSec - 60) * 1e3;
|
|
151
|
+
}
|
|
146
152
|
return this.token;
|
|
147
153
|
}
|
|
148
154
|
async get(path, init) {
|
|
@@ -190,7 +196,8 @@ var HttpClient = class {
|
|
|
190
196
|
"User-Agent": this.config.userAgent,
|
|
191
197
|
...init?.headers ?? {}
|
|
192
198
|
};
|
|
193
|
-
|
|
199
|
+
const { Authorization: _redacted, ...hookHeaders } = headers;
|
|
200
|
+
this.config.onRequest?.({ method, url, headers: hookHeaders });
|
|
194
201
|
const start = Date.now();
|
|
195
202
|
const res = await this.config.customFetch(url, {
|
|
196
203
|
method,
|
|
@@ -215,8 +222,6 @@ var HttpClient = class {
|
|
|
215
222
|
return res.json();
|
|
216
223
|
}
|
|
217
224
|
};
|
|
218
|
-
|
|
219
|
-
// src/auth.ts
|
|
220
225
|
var AuthModule = class {
|
|
221
226
|
constructor(http, config) {
|
|
222
227
|
this.http = http;
|
|
@@ -267,9 +272,17 @@ var AuthModule = class {
|
|
|
267
272
|
// 3. client.auth.exchangeCode({ code, redirectUri }) → tokens
|
|
268
273
|
// 4. Store access_token + refresh_token; call client.setBearerToken(access_token)
|
|
269
274
|
// 5. When access_token expires: client.auth.refreshToken(refresh_token)
|
|
275
|
+
/** Generate a PKCE `code_verifier` + `code_challenge` pair (S256 method).
|
|
276
|
+
* Pass `codeChallenge` to `getAuthorizationUrl()` and `codeVerifier` to `exchangeCode()`. */
|
|
277
|
+
generatePkce() {
|
|
278
|
+
const codeVerifier = randomBytes(32).toString("base64url");
|
|
279
|
+
const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
|
|
280
|
+
return { codeVerifier, codeChallenge };
|
|
281
|
+
}
|
|
270
282
|
/**
|
|
271
283
|
* Build the DUPR authorization URL to redirect the user to for login.
|
|
272
284
|
* The `authorizationUrl` config option must be set (see above note).
|
|
285
|
+
* Pass `codeChallenge` (from `generatePkce()`) to enable PKCE.
|
|
273
286
|
*/
|
|
274
287
|
getAuthorizationUrl(params) {
|
|
275
288
|
if (!this.config.authorizationUrl) {
|
|
@@ -284,6 +297,10 @@ var AuthModule = class {
|
|
|
284
297
|
url.searchParams.set("redirect_uri", params.redirectUri);
|
|
285
298
|
if (params.scopes?.length) url.searchParams.set("scope", params.scopes.join(" "));
|
|
286
299
|
if (params.state) url.searchParams.set("state", params.state);
|
|
300
|
+
if (params.codeChallenge) {
|
|
301
|
+
url.searchParams.set("code_challenge", params.codeChallenge);
|
|
302
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
303
|
+
}
|
|
287
304
|
return url.toString();
|
|
288
305
|
}
|
|
289
306
|
/**
|
|
@@ -303,6 +320,7 @@ var AuthModule = class {
|
|
|
303
320
|
client_id: clientKey,
|
|
304
321
|
client_secret: clientSecret
|
|
305
322
|
});
|
|
323
|
+
if (params.codeVerifier) body.set("code_verifier", params.codeVerifier);
|
|
306
324
|
const res = await this.config.customFetch(url, {
|
|
307
325
|
method: "POST",
|
|
308
326
|
headers: {
|
|
@@ -456,15 +474,15 @@ var UsersModule = class {
|
|
|
456
474
|
}
|
|
457
475
|
/** GET /user/{version}/{id} — basic player profile */
|
|
458
476
|
getUser(duprId) {
|
|
459
|
-
return this.http.get(`/user/${this.cfg.version}/${duprId}`);
|
|
477
|
+
return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}`);
|
|
460
478
|
}
|
|
461
479
|
/** GET /user/{version}/{id}/details — extended profile (requires USER_EMAIL::VIEW permission) */
|
|
462
480
|
getExtendedUser(duprId) {
|
|
463
|
-
return this.http.get(`/user/${this.cfg.version}/${duprId}/details`);
|
|
481
|
+
return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}/details`);
|
|
464
482
|
}
|
|
465
483
|
/** GET /user/{version}/{id}/clubs — club memberships for a player */
|
|
466
484
|
getClubMemberships(duprId) {
|
|
467
|
-
return this.http.get(`/user/${this.cfg.version}/${duprId}/clubs`);
|
|
485
|
+
return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}/clubs`);
|
|
468
486
|
}
|
|
469
487
|
/** POST /user/{version}/search — full-text player search with optional filters */
|
|
470
488
|
search(req) {
|
|
@@ -545,7 +563,7 @@ var MatchesModule = class {
|
|
|
545
563
|
}
|
|
546
564
|
/** GET /match/{version}/{id} — view a single match */
|
|
547
565
|
get(matchId) {
|
|
548
|
-
return this.http.get(`/match/${this.cfg.version}/${matchId}`);
|
|
566
|
+
return this.http.get(`/match/${this.cfg.version}/${encodeURIComponent(matchId)}`);
|
|
549
567
|
}
|
|
550
568
|
/** POST /match/{version}/create — submit a new match result */
|
|
551
569
|
create(match) {
|
|
@@ -569,7 +587,7 @@ var MatchesModule = class {
|
|
|
569
587
|
}
|
|
570
588
|
/** DELETE /match/{version}/annotate/{matchId} — remove a match annotation */
|
|
571
589
|
deleteAnnotation(matchId) {
|
|
572
|
-
return this.http.delete(`/match/${this.cfg.version}/annotate/${matchId}`);
|
|
590
|
+
return this.http.delete(`/match/${this.cfg.version}/annotate/${encodeURIComponent(matchId)}`);
|
|
573
591
|
}
|
|
574
592
|
/** POST /match/history/search — search a player's match history */
|
|
575
593
|
searchHistory(req) {
|
|
@@ -637,7 +655,7 @@ var WebhooksModule = class {
|
|
|
637
655
|
}
|
|
638
656
|
/** GET /{version}/webhook/schema/{topic} — get the JSON schema for a specific topic */
|
|
639
657
|
getSchema(topic) {
|
|
640
|
-
return this.http.get(`/${this.cfg.version}/webhook/schema/${topic}`);
|
|
658
|
+
return this.http.get(`/${this.cfg.version}/webhook/schema/${encodeURIComponent(topic)}`);
|
|
641
659
|
}
|
|
642
660
|
/** POST /user/{version}/subscribe/webhook-event — subscribe specific users to a webhook topic */
|
|
643
661
|
subscribeUsers(req) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/errors.ts","../src/http.ts","../src/auth.ts","../src/resources/users.ts","../src/resources/players.ts","../src/resources/playerRating.ts","../src/resources/matches.ts","../src/resources/clubs.ts","../src/resources/events.ts","../src/resources/webhooks.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export type AuthMode =\r\n | { type: \"clientCredentials\"; clientKey: string; clientSecret: string }\r\n | { type: \"staticBearer\"; bearerToken: string }\r\n | { type: \"none\" };\r\n\r\nexport interface RequestInfo {\r\n method: string;\r\n url: string;\r\n headers: Record<string, string>;\r\n}\r\n\r\nexport interface ResponseInfo {\r\n status: number;\r\n url: string;\r\n durationMs: number;\r\n}\r\n\r\nexport interface RetryOptions {\r\n /** Max number of retry attempts after the initial failure. @default 3 */\r\n maxRetries?: number;\r\n /** Base delay in ms before the first retry. Doubles on each attempt. @default 1_000 */\r\n baseDelayMs?: number;\r\n /** Max delay cap in ms (prevents infinite backoff). @default 30_000 */\r\n maxDelayMs?: number;\r\n}\r\n\r\nexport interface DuprClientOptions {\r\n /** @default \"https://uat.mydupr.com/api\" */\r\n baseUrl?: string;\r\n /** API version prefix used in all paths. @default \"v1.0\" */\r\n version?: string;\r\n /** Request timeout in milliseconds. @default 30_000 */\r\n timeoutMs?: number;\r\n auth?: AuthMode;\r\n /** Custom User-Agent header. */\r\n userAgent?: string;\r\n /** Inject a custom fetch implementation (useful for testing or polyfilling). */\r\n customFetch?: typeof fetch;\r\n /** Called before every request. Useful for logging or tracing. */\r\n onRequest?: (info: RequestInfo) => void;\r\n /** Called after every response (including errors). */\r\n onResponse?: (info: ResponseInfo) => void;\r\n /** Retry behaviour for transient errors (5xx, network failures, 429). Pass `false` to disable. */\r\n retry?: RetryOptions | false;\r\n /**\r\n * Base URL for the DUPR SSO iframe login widget.\r\n * UAT: \"https://uat.dupr.gg\"\r\n * Prod: \"https://dashboard.dupr.com\"\r\n * Required to call `client.auth.getSsoIframeUrl()`.\r\n */\r\n ssoBaseUrl?: string;\r\n /**\r\n * Base URL for refreshing DUPR SSO user tokens — a separate host from the Partner API.\r\n * UAT: \"https://api.uat.dupr.gg\"\r\n * Prod: \"https://api.dupr.gg\"\r\n * Required to call `client.auth.refreshSsoToken()`.\r\n */\r\n ssoRefreshBaseUrl?: string;\r\n /**\r\n * Authorization endpoint URL for the OAuth 2.0 authorization code flow.\r\n * Confirm the exact value with DUPR support before use.\r\n * Required to call `client.auth.getAuthorizationUrl()`.\r\n */\r\n authorizationUrl?: string;\r\n}\r\n\r\nexport interface ResolvedRetryOptions {\r\n maxRetries: number;\r\n baseDelayMs: number;\r\n maxDelayMs: number;\r\n}\r\n\r\nexport interface ResolvedConfig {\r\n baseUrl: string;\r\n version: string;\r\n timeoutMs: number;\r\n auth: AuthMode;\r\n userAgent: string;\r\n customFetch: typeof fetch;\r\n retry: ResolvedRetryOptions | false;\r\n onRequest?: (info: RequestInfo) => void;\r\n onResponse?: (info: ResponseInfo) => void;\r\n /** Runtime override for the bearer token — set via `client.setBearerToken()`. */\r\n overrideBearerToken?: string;\r\n ssoBaseUrl?: string;\r\n ssoRefreshBaseUrl?: string;\r\n authorizationUrl?: string;\r\n}\r\n\r\nexport function resolveConfig(opts: DuprClientOptions): ResolvedConfig {\r\n const cfg: ResolvedConfig = {\r\n baseUrl: opts.baseUrl ?? \"https://uat.mydupr.com/api\",\r\n version: opts.version ?? \"v1.0\",\r\n timeoutMs: opts.timeoutMs ?? 30_000,\r\n auth: opts.auth ?? { type: \"none\" },\r\n userAgent: opts.userAgent ?? \"dupr-js-client/0.1.0\",\r\n customFetch: opts.customFetch ?? globalThis.fetch.bind(globalThis),\r\n retry:\r\n opts.retry === false\r\n ? false\r\n : {\r\n maxRetries: opts.retry?.maxRetries ?? 3,\r\n baseDelayMs: opts.retry?.baseDelayMs ?? 1_000,\r\n maxDelayMs: opts.retry?.maxDelayMs ?? 30_000,\r\n },\r\n };\r\n if (opts.onRequest) cfg.onRequest = opts.onRequest;\r\n if (opts.onResponse) cfg.onResponse = opts.onResponse;\r\n if (opts.ssoBaseUrl) cfg.ssoBaseUrl = opts.ssoBaseUrl;\r\n if (opts.ssoRefreshBaseUrl) cfg.ssoRefreshBaseUrl = opts.ssoRefreshBaseUrl;\r\n if (opts.authorizationUrl) cfg.authorizationUrl = opts.authorizationUrl;\r\n return cfg;\r\n}\r\n","export class DuprApiError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly statusCode: number,\r\n public readonly details?: unknown,\r\n public readonly duprRequestId?: string,\r\n ) {\r\n super(message);\r\n this.name = \"DuprApiError\";\r\n // Maintain proper prototype chain in transpiled environments\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class AuthenticationError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"AuthenticationError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class ValidationError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"ValidationError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class NotFoundError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"NotFoundError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class RateLimitError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"RateLimitError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class ServerError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"ServerError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport async function buildError(res: Response): Promise<DuprApiError> {\r\n let body: unknown;\r\n const requestId = res.headers.get(\"x-request-id\") ?? res.headers.get(\"x-dupr-request-id\") ?? undefined;\r\n\r\n try {\r\n body = await res.json();\r\n } catch {\r\n // non-JSON body — leave body undefined\r\n }\r\n\r\n const msg =\r\n (typeof body === \"object\" && body !== null && \"message\" in body && typeof (body as Record<string, unknown>)[\"message\"] === \"string\"\r\n ? (body as Record<string, unknown>)[\"message\"] as string\r\n : null) ??\r\n `DUPR API error ${res.status}`;\r\n\r\n switch (true) {\r\n case res.status === 401 || res.status === 403:\r\n return new AuthenticationError(msg, res.status, body, requestId);\r\n case res.status === 404:\r\n return new NotFoundError(msg, res.status, body, requestId);\r\n case res.status === 400:\r\n return new ValidationError(msg, res.status, body, requestId);\r\n case res.status === 429:\r\n return new RateLimitError(msg, res.status, body, requestId);\r\n case res.status >= 500:\r\n return new ServerError(msg, res.status, body, requestId);\r\n default:\r\n return new DuprApiError(msg, res.status, body, requestId);\r\n }\r\n}\r\n","import { ResolvedConfig } from \"./config.js\";\r\nimport { AuthenticationError, buildError, RateLimitError, ServerError } from \"./errors.js\";\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nfunction retryDelayMs(attempt: number, baseDelayMs: number, maxDelayMs: number): number {\r\n // Exponential backoff with ±20% jitter to avoid thundering herd\r\n const exp = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);\r\n return exp * (0.8 + Math.random() * 0.4);\r\n}\r\n\r\nfunction isRetryable(err: unknown): boolean {\r\n if (err instanceof RateLimitError) return true;\r\n if (err instanceof ServerError) return true;\r\n // Network-level failures (fetch throws a TypeError on connection refused etc.)\r\n if (err instanceof TypeError) return true;\r\n return false;\r\n}\r\n\r\nexport class HttpClient {\r\n private token: string | null = null;\r\n private tokenExpiresAt = 0;\r\n\r\n constructor(private readonly config: ResolvedConfig) {}\r\n\r\n private async getBearerToken(): Promise<string> {\r\n if (this.config.overrideBearerToken) {\r\n return this.config.overrideBearerToken;\r\n }\r\n if (this.config.auth.type === \"staticBearer\") {\r\n return this.config.auth.bearerToken;\r\n }\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"No auth configured — set auth in DuprClientOptions or call setBearerToken()\", 401);\r\n }\r\n\r\n if (this.token && Date.now() < this.tokenExpiresAt) {\r\n return this.token;\r\n }\r\n\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const encoded = Buffer.from(`${clientKey}:${clientSecret}`).toString(\"base64\");\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n\r\n const start = Date.now();\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"x-authorization\": encoded,\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n this.config.onResponse?.({ status: res.status, url, durationMs: Date.now() - start });\r\n\r\n if (!res.ok) throw await buildError(res);\r\n\r\n const body = await res.json() as { token?: string; accessToken?: string; expiresIn?: number };\r\n this.token = body.token ?? body.accessToken ?? null;\r\n if (!this.token) throw new AuthenticationError(\"Token response contained no token\", 401);\r\n\r\n const ttlSec = body.expiresIn ?? 3600;\r\n this.tokenExpiresAt = Date.now() + (ttlSec - 60) * 1000;\r\n return this.token;\r\n }\r\n\r\n async get<T>(path: string, init?: RequestInit): Promise<T> {\r\n return this.request<T>(\"GET\", path, init);\r\n }\r\n\r\n async post<T>(path: string, body?: unknown, init?: RequestInit): Promise<T> {\r\n const extra: RequestInit = { headers: { \"Content-Type\": \"application/json\", ...(init?.headers ?? {}) } };\r\n if (body !== undefined) extra.body = JSON.stringify(body);\r\n return this.request<T>(\"POST\", path, { ...init, ...extra });\r\n }\r\n\r\n async delete<T>(path: string, body?: unknown, init?: RequestInit): Promise<T> {\r\n const extra: RequestInit = { headers: { \"Content-Type\": \"application/json\", ...(init?.headers ?? {}) } };\r\n if (body !== undefined) extra.body = JSON.stringify(body);\r\n return this.request<T>(\"DELETE\", path, { ...init, ...extra });\r\n }\r\n\r\n async request<T>(method: string, path: string, init?: RequestInit): Promise<T> {\r\n const retryCfg = this.config.retry;\r\n const maxAttempts = retryCfg === false ? 1 : retryCfg.maxRetries + 1;\r\n\r\n let lastErr: unknown;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n return await this.rawRequest<T>(method, path, init);\r\n } catch (err) {\r\n lastErr = err;\r\n\r\n if (attempt >= maxAttempts - 1) break;\r\n if (!isRetryable(err)) break;\r\n if (retryCfg === false) break;\r\n\r\n let delay: number;\r\n if (err instanceof RateLimitError) {\r\n // Honor Retry-After header (value in seconds)\r\n const retryAfterSec =\r\n err.details !== null &&\r\n typeof err.details === \"object\" &&\r\n \"retryAfterSeconds\" in (err.details as object)\r\n ? Number((err.details as { retryAfterSeconds: unknown }).retryAfterSeconds)\r\n : NaN;\r\n delay = Number.isFinite(retryAfterSec) && retryAfterSec > 0\r\n ? retryAfterSec * 1000\r\n : retryDelayMs(attempt, retryCfg.baseDelayMs, retryCfg.maxDelayMs);\r\n } else {\r\n delay = retryDelayMs(attempt, retryCfg.baseDelayMs, retryCfg.maxDelayMs);\r\n }\r\n\r\n await sleep(delay);\r\n }\r\n }\r\n\r\n throw lastErr;\r\n }\r\n\r\n private async rawRequest<T>(method: string, path: string, init?: RequestInit): Promise<T> {\r\n const token = await this.getBearerToken();\r\n const url = `${this.config.baseUrl}${path}`;\r\n\r\n const headers: Record<string, string> = {\r\n Authorization: `Bearer ${token}`,\r\n \"User-Agent\": this.config.userAgent,\r\n ...(init?.headers as Record<string, string> | undefined ?? {}),\r\n };\r\n\r\n this.config.onRequest?.({ method, url, headers });\r\n\r\n const start = Date.now();\r\n const res = await this.config.customFetch(url, {\r\n method,\r\n ...init,\r\n headers,\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n this.config.onResponse?.({ status: res.status, url, durationMs: Date.now() - start });\r\n\r\n if (!res.ok) {\r\n const err = await buildError(res);\r\n // Attach Retry-After from the response header so the retry loop can read it\r\n if (err instanceof RateLimitError) {\r\n const retryAfter = res.headers.get(\"Retry-After\");\r\n if (retryAfter) {\r\n (err as RateLimitError & { details: unknown }).details =\r\n typeof err.details === \"object\" && err.details !== null\r\n ? { ...err.details as object, retryAfterSeconds: Number(retryAfter) }\r\n : { retryAfterSeconds: Number(retryAfter) };\r\n }\r\n }\r\n throw err;\r\n }\r\n\r\n // Some endpoints return 204 No Content\r\n if (res.status === 204 || res.headers.get(\"content-length\") === \"0\") {\r\n return undefined as T;\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n }\r\n}\r\n","import { HttpClient } from \"./http.js\";\r\nimport { ResolvedConfig } from \"./config.js\";\r\nimport { AuthenticationError } from \"./errors.js\";\r\nimport { TokenResponse } from \"./types.js\";\r\n\r\nexport interface AuthCodeTokenResponse extends TokenResponse {\r\n refresh_token?: string;\r\n token_type?: string;\r\n scope?: string;\r\n}\r\n\r\n/** Response from `client.auth.refreshSsoToken()`. Both tokens are always present — DUPR rotates refresh tokens on every use. */\r\nexport interface SsoTokenResponse {\r\n accessToken: string;\r\n refreshToken: string;\r\n /** Seconds until the access token expires, if provided by DUPR. */\r\n expiresIn?: number;\r\n}\r\n\r\nexport interface AuthorizationUrlParams {\r\n /** Your OAuth redirect URI, must match what is registered with DUPR. */\r\n redirectUri: string;\r\n /** OAuth scopes to request (e.g. [\"user.read\"]). Defaults to empty. */\r\n scopes?: string[];\r\n /** Opaque value passed through the flow to prevent CSRF. Recommended. */\r\n state?: string;\r\n}\r\n\r\nexport class AuthModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly config: ResolvedConfig,\r\n ) {}\r\n\r\n /**\r\n * Explicitly request a new access token using client credentials.\r\n * Normally you don't need to call this — the HTTP client handles token refresh automatically.\r\n */\r\n async getToken(): Promise<TokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"getToken() requires clientCredentials auth mode\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const encoded = Buffer.from(`${clientKey}:${clientSecret}`).toString(\"base64\");\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"x-authorization\": encoded,\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const body = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (body?.[\"message\"] as string | undefined) ?? `Auth failed: ${res.status}`,\r\n res.status,\r\n body,\r\n );\r\n }\r\n\r\n return res.json() as Promise<TokenResponse>;\r\n }\r\n\r\n // ── Authorization Code Flow ───────────────────────────────────────────────\r\n //\r\n // Use this flow to let end-users authorise your app to act on their behalf\r\n // (e.g. the \"Connect DUPR\" button). The user is redirected to DUPR's login\r\n // page, then back to your redirectUri with an authorization code.\r\n //\r\n // NOTE: This requires a DUPR OAuth application with an authorization endpoint\r\n // separate from the Partner API client credentials. Confirm the exact\r\n // authorization URL with DUPR support.\r\n //\r\n // Typical flow:\r\n // 1. client.auth.getAuthorizationUrl({ redirectUri, state }) → redirect user\r\n // 2. User approves → DUPR calls back to redirectUri?code=xxx&state=yyy\r\n // 3. client.auth.exchangeCode({ code, redirectUri }) → tokens\r\n // 4. Store access_token + refresh_token; call client.setBearerToken(access_token)\r\n // 5. When access_token expires: client.auth.refreshToken(refresh_token)\r\n\r\n /**\r\n * Build the DUPR authorization URL to redirect the user to for login.\r\n * The `authorizationUrl` config option must be set (see above note).\r\n */\r\n getAuthorizationUrl(params: AuthorizationUrlParams): string {\r\n if (!this.config.authorizationUrl) {\r\n throw new Error(\r\n \"authorizationUrl is not configured. Pass it in DuprClientOptions to use the Authorization Code flow.\",\r\n );\r\n }\r\n const url = new URL(this.config.authorizationUrl);\r\n const clientId = this.config.auth.type === \"clientCredentials\" ? this.config.auth.clientKey : \"\";\r\n url.searchParams.set(\"response_type\", \"code\");\r\n url.searchParams.set(\"client_id\", clientId);\r\n url.searchParams.set(\"redirect_uri\", params.redirectUri);\r\n if (params.scopes?.length) url.searchParams.set(\"scope\", params.scopes.join(\" \"));\r\n if (params.state) url.searchParams.set(\"state\", params.state);\r\n return url.toString();\r\n }\r\n\r\n /**\r\n * Exchange an authorization code (from the OAuth callback) for access + refresh tokens.\r\n * Uses `POST /auth/{version}/token` with `grant_type=authorization_code`.\r\n */\r\n async exchangeCode(params: {\r\n code: string;\r\n redirectUri: string;\r\n }): Promise<AuthCodeTokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"exchangeCode() requires clientCredentials auth configured with clientKey/clientSecret\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n const body = new URLSearchParams({\r\n grant_type: \"authorization_code\",\r\n code: params.code,\r\n redirect_uri: params.redirectUri,\r\n client_id: clientKey,\r\n client_secret: clientSecret,\r\n });\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: body.toString(),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `Code exchange failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n return res.json() as Promise<AuthCodeTokenResponse>;\r\n }\r\n\r\n // ── SSO Iframe Flow ───────────────────────────────────────────────────────\r\n //\r\n // DUPR's documented SSO approach for user-facing login uses an embedded iframe\r\n // rather than a standard OAuth2 redirect. The iframe emits a window.postMessage\r\n // event upon successful login.\r\n //\r\n // Typical flow:\r\n // 1. client.auth.getSsoIframeUrl() → embed in <iframe allow=\"payment\">\r\n // 2. User logs in inside the iframe\r\n // 3. Listen for window.postMessage → { userToken, refreshToken, id, duprId, stats }\r\n // 4. Store userToken + refreshToken server-side; record tokenExpiresAt\r\n // (7 days UAT / 30 days prod — not returned in the event, apply based on env)\r\n // 5. When userToken nears expiry: client.auth.refreshSsoToken(refreshToken)\r\n // DUPR rotates refresh tokens — store both returned tokens.\r\n //\r\n // UAT iframe host: https://uat.dupr.gg\r\n // Prod iframe host: https://dashboard.dupr.com\r\n // Always validate window.postMessage origin against the expected host.\r\n\r\n /**\r\n * Returns the DUPR SSO iframe URL. Embed this in an `<iframe allow=\"payment\">` to\r\n * display the DUPR login widget. Requires `ssoBaseUrl` in `DuprClientOptions`.\r\n */\r\n getSsoIframeUrl(): string {\r\n if (!this.config.ssoBaseUrl) {\r\n throw new Error(\r\n \"ssoBaseUrl is not configured. Pass it in DuprClientOptions to use the SSO iframe flow.\",\r\n );\r\n }\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\r\n \"getSsoIframeUrl() requires clientCredentials auth mode\",\r\n 401,\r\n );\r\n }\r\n const encoded = Buffer.from(this.config.auth.clientKey).toString(\"base64\");\r\n return `${this.config.ssoBaseUrl}/login-external-app/${encoded}`;\r\n }\r\n\r\n /**\r\n * Refresh a DUPR SSO user token obtained from the iframe login `postMessage` event.\r\n * Uses a separate refresh endpoint on `ssoRefreshBaseUrl` (distinct from the Partner API).\r\n * Requires `ssoRefreshBaseUrl` in `DuprClientOptions`.\r\n *\r\n * DUPR rotates refresh tokens on every use — always store both `accessToken` and\r\n * `refreshToken` from the response.\r\n */\r\n async refreshSsoToken(refreshToken: string): Promise<SsoTokenResponse> {\r\n if (!this.config.ssoRefreshBaseUrl) {\r\n throw new Error(\r\n \"ssoRefreshBaseUrl is not configured. Pass it in DuprClientOptions to use SSO token refresh.\",\r\n );\r\n }\r\n const res = await this.config.customFetch(\r\n `${this.config.ssoRefreshBaseUrl}/api/auth/refreshAccessToken`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: JSON.stringify({ refreshToken }),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n },\r\n );\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `SSO token refresh failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n const data = await res.json() as Record<string, unknown>;\r\n const accessToken = (data[\"accessToken\"] ?? data[\"userToken\"]) as string | undefined;\r\n const newRefreshToken = data[\"refreshToken\"] as string | undefined;\r\n\r\n if (!accessToken) {\r\n throw new AuthenticationError(\"SSO token refresh response missing accessToken\", 502);\r\n }\r\n if (!newRefreshToken) {\r\n throw new AuthenticationError(\r\n \"SSO token refresh response missing refreshToken — DUPR token rotation failed\",\r\n 502,\r\n );\r\n }\r\n\r\n return {\r\n accessToken,\r\n refreshToken: newRefreshToken,\r\n ...(data[\"expiresIn\"] !== undefined && { expiresIn: data[\"expiresIn\"] as number }),\r\n };\r\n }\r\n\r\n /**\r\n * Obtain a new access token using a refresh token from a previous Authorization Code flow.\r\n * Uses `POST /auth/{version}/token` with `grant_type=refresh_token`.\r\n */\r\n async refreshToken(refreshToken: string): Promise<AuthCodeTokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"refreshToken() requires clientCredentials auth configured\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n const body = new URLSearchParams({\r\n grant_type: \"refresh_token\",\r\n refresh_token: refreshToken,\r\n client_id: clientKey,\r\n client_secret: clientSecret,\r\n });\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: body.toString(),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `Token refresh failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n return res.json() as Promise<AuthCodeTokenResponse>;\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ClubMembershipResponse,\r\n CreateProvisionalRatingRequest,\r\n DeleteProvisionalRatingRequest,\r\n ExtendedUserInfo,\r\n ExternalBatchUserDetailRequest,\r\n ExternalInviteRequest,\r\n ExternalSearchRequest,\r\n GetProvisionalRatingRequest,\r\n GrantExternalSubscriptionRequest,\r\n UpdateProvisionalRatingRequest,\r\n UserInfo,\r\n} from \"../types.js\";\r\n\r\nexport class UsersModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** GET /user/{version}/{id} — basic player profile */\r\n getUser(duprId: string): Promise<ApiWrapper<UserInfo>> {\r\n return this.http.get(`/user/${this.cfg.version}/${duprId}`);\r\n }\r\n\r\n /** GET /user/{version}/{id}/details — extended profile (requires USER_EMAIL::VIEW permission) */\r\n getExtendedUser(duprId: string): Promise<ApiWrapper<ExtendedUserInfo>> {\r\n return this.http.get(`/user/${this.cfg.version}/${duprId}/details`);\r\n }\r\n\r\n /** GET /user/{version}/{id}/clubs — club memberships for a player */\r\n getClubMemberships(duprId: string): Promise<ClubMembershipResponse> {\r\n return this.http.get(`/user/${this.cfg.version}/${duprId}/clubs`);\r\n }\r\n\r\n /** POST /user/{version}/search — full-text player search with optional filters */\r\n search(req: ExternalSearchRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/user/${this.cfg.version}/search`, req);\r\n }\r\n\r\n /** POST /user/{version}/batch — fetch multiple players by DUPR ID in one request */\r\n getBatch(req: ExternalBatchUserDetailRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/user/${this.cfg.version}/batch`, req);\r\n }\r\n\r\n /** POST /user/{version}/invite — pre-generate a DUPR ID and send an invite email */\r\n invite(req: ExternalInviteRequest): Promise<ApiWrapper<{ duprId: string }>> {\r\n return this.http.post(`/user/${this.cfg.version}/invite`, req);\r\n }\r\n\r\n /** POST /user/{version}/subscription/grants — grant a subscription to a user */\r\n grantSubscription(req: GrantExternalSubscriptionRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/subscription/grants`, req);\r\n }\r\n\r\n // ── Provisional ratings ──────────────────────────────────────\r\n\r\n /** POST /user/{version}/provisional_rating — get provisional ratings for a player */\r\n getProvisionalRating(req: GetProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating`, req);\r\n }\r\n\r\n /** POST /user/{version}/provisional_rating/create */\r\n createProvisionalRating(req: CreateProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating/create`, req);\r\n }\r\n\r\n /** POST /user/{version}/provisional_rating/update */\r\n updateProvisionalRating(req: UpdateProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating/update`, req);\r\n }\r\n\r\n /** DELETE /user/{version}/provisional_rating/delete */\r\n deleteProvisionalRating(req: DeleteProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/user/${this.cfg.version}/provisional_rating/delete`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper } from \"../types.js\";\r\n\r\nexport interface GetDuprIdByEmailRequest {\r\n email: string;\r\n}\r\n\r\nexport interface DuprIdByEmailResponse {\r\n duprId?: string;\r\n}\r\n\r\nexport class PlayersModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /{version}/player/duprid-by-email — resolve a DUPR ID from an email address */\r\n getDuprIdByEmail(req: GetDuprIdByEmailRequest): Promise<ApiWrapper<DuprIdByEmailResponse>> {\r\n return this.http.post(`/${this.cfg.version}/player/duprid-by-email`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper, PlayerRatingSubscribeRequest } from \"../types.js\";\r\n\r\nexport interface PlayerRatingHistoryRequest {\r\n duprId: string;\r\n offset?: number;\r\n limit?: number;\r\n}\r\n\r\nexport interface PlayerRatingHistoryEntry {\r\n date?: string;\r\n singlesRating?: number;\r\n doublesRating?: number;\r\n}\r\n\r\nexport class PlayerRatingModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /history — get rating history for a player */\r\n getHistory(req: PlayerRatingHistoryRequest): Promise<ApiWrapper<PlayerRatingHistoryEntry[]>> {\r\n return this.http.post(`/history`, req);\r\n }\r\n\r\n /** GET /{version}/subscribe/rating-changes — list currently subscribed DUPR IDs */\r\n getSubscriptions(): Promise<ApiWrapper<{ duprIds: string[] }>> {\r\n return this.http.get(`/${this.cfg.version}/subscribe/rating-changes`);\r\n }\r\n\r\n /** POST /{version}/subscribe/rating-changes — subscribe to rating-change events for a list of players */\r\n subscribe(req: PlayerRatingSubscribeRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/${this.cfg.version}/subscribe/rating-changes`, req);\r\n }\r\n\r\n /** DELETE /{version}/subscribe/rating-changes — unsubscribe from rating-change events */\r\n unsubscribe(req: PlayerRatingSubscribeRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/${this.cfg.version}/subscribe/rating-changes`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ExternalDeleteMatchRequest,\r\n ExternalMatchRequest,\r\n ExternalMatchSearchRequest,\r\n ExternalUpdateMatchRequest,\r\n MatchResponse,\r\n} from \"../types.js\";\r\n\r\nexport interface AnnotateMatchRequest {\r\n matchId: string;\r\n annotation: Record<string, unknown>;\r\n}\r\n\r\nexport class MatchesModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** GET /match/{version}/{id} — view a single match */\r\n get(matchId: string): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.get(`/match/${this.cfg.version}/${matchId}`);\r\n }\r\n\r\n /** POST /match/{version}/create — submit a new match result */\r\n create(match: ExternalMatchRequest): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.post(`/match/${this.cfg.version}/create`, match);\r\n }\r\n\r\n /** POST /match/{version}/batch — submit multiple match results in one call */\r\n createBulk(matches: ExternalMatchRequest[]): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/match/${this.cfg.version}/batch`, matches);\r\n }\r\n\r\n /** POST /match/{version}/update — update an existing match */\r\n update(req: ExternalUpdateMatchRequest): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.post(`/match/${this.cfg.version}/update`, req);\r\n }\r\n\r\n /** DELETE /match/{version}/delete — delete a match */\r\n delete(req: ExternalDeleteMatchRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/match/${this.cfg.version}/delete`, req);\r\n }\r\n\r\n /** POST /match/{version}/annotate — attach vendor-specific metadata to a match */\r\n annotate(req: AnnotateMatchRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/match/${this.cfg.version}/annotate`, req);\r\n }\r\n\r\n /** DELETE /match/{version}/annotate/{matchId} — remove a match annotation */\r\n deleteAnnotation(matchId: string): Promise<ApiWrapper> {\r\n return this.http.delete(`/match/${this.cfg.version}/annotate/${matchId}`);\r\n }\r\n\r\n /** POST /match/history/search — search a player's match history */\r\n searchHistory(req: ExternalMatchSearchRequest): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/match/history/search`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ExternalClubMemberRequest,\r\n ExternalClubMatchSearchRequest,\r\n MatchResponse,\r\n UserInfo,\r\n} from \"../types.js\";\r\n\r\nexport class ClubsModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /club/{version}/members — get ratings for all members of a club */\r\n membersRating(req: ExternalClubMemberRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/club/${this.cfg.version}/members`, req);\r\n }\r\n\r\n /** POST /club/{version}/match/search — search matches associated with a club */\r\n searchMatches(req: ExternalClubMatchSearchRequest): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/club/${this.cfg.version}/match/search`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n CreateEventRequestV1,\r\n CreateEventResponseV1,\r\n DeleteEventRequestV1,\r\n DeleteEventResponseV1,\r\n GetEventRequestV1,\r\n GetEventResponseV1,\r\n UpdateEventRequestV1,\r\n UpdateEventResponseV1,\r\n} from \"../types.js\";\r\n\r\nexport class EventsModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /events/{version}/create */\r\n create(req: CreateEventRequestV1): Promise<ApiWrapper<CreateEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/create`, req);\r\n }\r\n\r\n /** GET /events/{version}/get */\r\n get(req: GetEventRequestV1): Promise<ApiWrapper<GetEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/get`, req);\r\n }\r\n\r\n /** POST /events/{version}/update */\r\n update(req: UpdateEventRequestV1): Promise<ApiWrapper<UpdateEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/update`, req);\r\n }\r\n\r\n /** POST /events/{version}/delete */\r\n delete(req: DeleteEventRequestV1): Promise<ApiWrapper<DeleteEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/delete`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper, ClientHookRequest, UserWebhookRequest, WebhookSchema } from \"../types.js\";\r\n\r\nexport class WebhooksModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /{version}/webhook — register a webhook endpoint */\r\n register(req: ClientHookRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/${this.cfg.version}/webhook`, req);\r\n }\r\n\r\n /** GET /{version}/topic — list all available webhook topics */\r\n getTopics(): Promise<ApiWrapper<string[]>> {\r\n return this.http.get(`/${this.cfg.version}/topic`);\r\n }\r\n\r\n /** GET /{version}/webhook/schema — list available webhook schemas */\r\n listSchemas(): Promise<ApiWrapper<WebhookSchema[]>> {\r\n return this.http.get(`/${this.cfg.version}/webhook/schema`);\r\n }\r\n\r\n /** GET /{version}/webhook/schema/{topic} — get the JSON schema for a specific topic */\r\n getSchema(topic: string): Promise<ApiWrapper<WebhookSchema>> {\r\n return this.http.get(`/${this.cfg.version}/webhook/schema/${topic}`);\r\n }\r\n\r\n /** POST /user/{version}/subscribe/webhook-event — subscribe specific users to a webhook topic */\r\n subscribeUsers(req: UserWebhookRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/subscribe/webhook-event`, req);\r\n }\r\n\r\n /** DELETE /user/{version}/subscribe/webhook-event — unsubscribe specific users from a webhook topic */\r\n unsubscribeUsers(req: UserWebhookRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/user/${this.cfg.version}/subscribe/webhook-event`, req);\r\n }\r\n}\r\n","import { DuprClientOptions, ResolvedConfig, resolveConfig } from \"./config.js\";\r\nimport { HttpClient } from \"./http.js\";\r\nimport { AuthModule } from \"./auth.js\";\r\nimport { UsersModule } from \"./resources/users.js\";\r\nimport { PlayersModule } from \"./resources/players.js\";\r\nimport { PlayerRatingModule } from \"./resources/playerRating.js\";\r\nimport { MatchesModule } from \"./resources/matches.js\";\r\nimport { ClubsModule } from \"./resources/clubs.js\";\r\nimport { EventsModule } from \"./resources/events.js\";\r\nimport { WebhooksModule } from \"./resources/webhooks.js\";\r\n\r\nexport class DuprClient {\r\n readonly config: ResolvedConfig;\r\n readonly auth: AuthModule;\r\n readonly users: UsersModule;\r\n readonly players: PlayersModule;\r\n readonly playerRating: PlayerRatingModule;\r\n readonly matches: MatchesModule;\r\n readonly clubs: ClubsModule;\r\n readonly events: EventsModule;\r\n readonly webhooks: WebhooksModule;\r\n\r\n constructor(opts: DuprClientOptions = {}) {\r\n this.config = resolveConfig(opts);\r\n const http = new HttpClient(this.config);\r\n this.auth = new AuthModule(http, this.config);\r\n this.users = new UsersModule(http, this.config);\r\n this.players = new PlayersModule(http, this.config);\r\n this.playerRating = new PlayerRatingModule(http, this.config);\r\n this.matches = new MatchesModule(http, this.config);\r\n this.clubs = new ClubsModule(http, this.config);\r\n this.events = new EventsModule(http, this.config);\r\n this.webhooks = new WebhooksModule(http, this.config);\r\n }\r\n\r\n /** Override the bearer token at runtime — useful when your backend handles auth separately. */\r\n setBearerToken(token: string): void {\r\n this.config.overrideBearerToken = token;\r\n }\r\n\r\n /** Clear the runtime bearer token override and fall back to configured auth. */\r\n clearBearerToken(): void {\r\n delete this.config.overrideBearerToken;\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/errors.ts","../src/http.ts","../src/auth.ts","../src/resources/users.ts","../src/resources/players.ts","../src/resources/playerRating.ts","../src/resources/matches.ts","../src/resources/clubs.ts","../src/resources/events.ts","../src/resources/webhooks.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export type AuthMode =\r\n | { type: \"clientCredentials\"; clientKey: string; clientSecret: string }\r\n | { type: \"staticBearer\"; bearerToken: string }\r\n | { type: \"none\" };\r\n\r\nexport interface RequestInfo {\r\n method: string;\r\n url: string;\r\n headers: Record<string, string>;\r\n}\r\n\r\nexport interface ResponseInfo {\r\n status: number;\r\n url: string;\r\n durationMs: number;\r\n}\r\n\r\nexport interface RetryOptions {\r\n /** Max number of retry attempts after the initial failure. @default 3 */\r\n maxRetries?: number;\r\n /** Base delay in ms before the first retry. Doubles on each attempt. @default 1_000 */\r\n baseDelayMs?: number;\r\n /** Max delay cap in ms (prevents infinite backoff). @default 30_000 */\r\n maxDelayMs?: number;\r\n}\r\n\r\nexport interface DuprClientOptions {\r\n /** @default \"https://uat.mydupr.com/api\" */\r\n baseUrl?: string;\r\n /** API version prefix used in all paths. @default \"v1.0\" */\r\n version?: string;\r\n /** Request timeout in milliseconds. @default 30_000 */\r\n timeoutMs?: number;\r\n auth?: AuthMode;\r\n /** Custom User-Agent header. */\r\n userAgent?: string;\r\n /** Inject a custom fetch implementation (useful for testing or polyfilling). */\r\n customFetch?: typeof fetch;\r\n /** Called before every request. Useful for logging or tracing. */\r\n onRequest?: (info: RequestInfo) => void;\r\n /** Called after every response (including errors). */\r\n onResponse?: (info: ResponseInfo) => void;\r\n /** Retry behaviour for transient errors (5xx, network failures, 429). Pass `false` to disable. */\r\n retry?: RetryOptions | false;\r\n /**\r\n * Base URL for the DUPR SSO iframe login widget.\r\n * UAT: \"https://uat.dupr.gg\"\r\n * Prod: \"https://dashboard.dupr.com\"\r\n * Required to call `client.auth.getSsoIframeUrl()`.\r\n */\r\n ssoBaseUrl?: string;\r\n /**\r\n * Base URL for refreshing DUPR SSO user tokens — a separate host from the Partner API.\r\n * UAT: \"https://api.uat.dupr.gg\"\r\n * Prod: \"https://api.dupr.gg\"\r\n * Required to call `client.auth.refreshSsoToken()`.\r\n */\r\n ssoRefreshBaseUrl?: string;\r\n /**\r\n * Authorization endpoint URL for the OAuth 2.0 authorization code flow.\r\n * Confirm the exact value with DUPR support before use.\r\n * Required to call `client.auth.getAuthorizationUrl()`.\r\n */\r\n authorizationUrl?: string;\r\n}\r\n\r\nexport interface ResolvedRetryOptions {\r\n maxRetries: number;\r\n baseDelayMs: number;\r\n maxDelayMs: number;\r\n}\r\n\r\nexport interface ResolvedConfig {\r\n baseUrl: string;\r\n version: string;\r\n timeoutMs: number;\r\n auth: AuthMode;\r\n userAgent: string;\r\n customFetch: typeof fetch;\r\n retry: ResolvedRetryOptions | false;\r\n onRequest?: (info: RequestInfo) => void;\r\n onResponse?: (info: ResponseInfo) => void;\r\n /** Runtime override for the bearer token — set via `client.setBearerToken()`. */\r\n overrideBearerToken?: string;\r\n ssoBaseUrl?: string;\r\n ssoRefreshBaseUrl?: string;\r\n authorizationUrl?: string;\r\n}\r\n\r\nexport function resolveConfig(opts: DuprClientOptions): ResolvedConfig {\r\n const cfg: ResolvedConfig = {\r\n baseUrl: opts.baseUrl ?? \"https://uat.mydupr.com/api\",\r\n version: opts.version ?? \"v1.0\",\r\n timeoutMs: opts.timeoutMs ?? 30_000,\r\n auth: opts.auth ?? { type: \"none\" },\r\n userAgent: opts.userAgent ?? \"dupr-js-client/0.1.0\",\r\n customFetch: opts.customFetch ?? globalThis.fetch.bind(globalThis),\r\n retry:\r\n opts.retry === false\r\n ? false\r\n : {\r\n maxRetries: opts.retry?.maxRetries ?? 3,\r\n baseDelayMs: opts.retry?.baseDelayMs ?? 1_000,\r\n maxDelayMs: opts.retry?.maxDelayMs ?? 30_000,\r\n },\r\n };\r\n if (opts.onRequest) cfg.onRequest = opts.onRequest;\r\n if (opts.onResponse) cfg.onResponse = opts.onResponse;\r\n if (opts.ssoBaseUrl) cfg.ssoBaseUrl = opts.ssoBaseUrl;\r\n if (opts.ssoRefreshBaseUrl) cfg.ssoRefreshBaseUrl = opts.ssoRefreshBaseUrl;\r\n if (opts.authorizationUrl) cfg.authorizationUrl = opts.authorizationUrl;\r\n return cfg;\r\n}\r\n","export class DuprApiError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly statusCode: number,\r\n public readonly details?: unknown,\r\n public readonly duprRequestId?: string,\r\n ) {\r\n super(message);\r\n this.name = \"DuprApiError\";\r\n // Maintain proper prototype chain in transpiled environments\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class AuthenticationError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"AuthenticationError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class ValidationError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"ValidationError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class NotFoundError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"NotFoundError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class RateLimitError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"RateLimitError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class ServerError extends DuprApiError {\r\n constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string) {\r\n super(message, statusCode, details, duprRequestId);\r\n this.name = \"ServerError\";\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport async function buildError(res: Response): Promise<DuprApiError> {\r\n let body: unknown;\r\n const requestId = res.headers.get(\"x-request-id\") ?? res.headers.get(\"x-dupr-request-id\") ?? undefined;\r\n\r\n try {\r\n body = await res.json();\r\n } catch {\r\n // non-JSON body — leave body undefined\r\n }\r\n\r\n const msg =\r\n (typeof body === \"object\" && body !== null && \"message\" in body && typeof (body as Record<string, unknown>)[\"message\"] === \"string\"\r\n ? (body as Record<string, unknown>)[\"message\"] as string\r\n : null) ??\r\n `DUPR API error ${res.status}`;\r\n\r\n switch (true) {\r\n case res.status === 401 || res.status === 403:\r\n return new AuthenticationError(msg, res.status, body, requestId);\r\n case res.status === 404:\r\n return new NotFoundError(msg, res.status, body, requestId);\r\n case res.status === 400:\r\n return new ValidationError(msg, res.status, body, requestId);\r\n case res.status === 429:\r\n return new RateLimitError(msg, res.status, body, requestId);\r\n case res.status >= 500:\r\n return new ServerError(msg, res.status, body, requestId);\r\n default:\r\n return new DuprApiError(msg, res.status, body, requestId);\r\n }\r\n}\r\n","import { ResolvedConfig } from \"./config.js\";\r\nimport { AuthenticationError, buildError, RateLimitError, ServerError } from \"./errors.js\";\r\nimport type { TokenResponse } from \"./types.js\";\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nfunction retryDelayMs(attempt: number, baseDelayMs: number, maxDelayMs: number): number {\r\n // Exponential backoff with ±20% jitter to avoid thundering herd\r\n const exp = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);\r\n return exp * (0.8 + Math.random() * 0.4);\r\n}\r\n\r\nfunction isRetryable(err: unknown): boolean {\r\n if (err instanceof RateLimitError) return true;\r\n if (err instanceof ServerError) return true;\r\n // Network-level failures (fetch throws a TypeError on connection refused etc.)\r\n if (err instanceof TypeError) return true;\r\n return false;\r\n}\r\n\r\nexport class HttpClient {\r\n private token: string | null = null;\r\n private tokenExpiresAt = 0;\r\n\r\n constructor(private readonly config: ResolvedConfig) {}\r\n\r\n private async getBearerToken(): Promise<string> {\r\n if (this.config.overrideBearerToken) {\r\n return this.config.overrideBearerToken;\r\n }\r\n if (this.config.auth.type === \"staticBearer\") {\r\n return this.config.auth.bearerToken;\r\n }\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"No auth configured — set auth in DuprClientOptions or call setBearerToken()\", 401);\r\n }\r\n\r\n if (this.token && Date.now() < this.tokenExpiresAt) {\r\n return this.token;\r\n }\r\n\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const encoded = Buffer.from(`${clientKey}:${clientSecret}`).toString(\"base64\");\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n\r\n const start = Date.now();\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"x-authorization\": encoded,\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n this.config.onResponse?.({ status: res.status, url, durationMs: Date.now() - start });\r\n\r\n if (!res.ok) throw await buildError(res);\r\n\r\n const body = await res.json() as TokenResponse;\r\n // The Partner API wraps the token in result: { token, expiry }.\r\n // Older/alternate environments return it at the top level — handle both.\r\n this.token = body.result?.token ?? body.token ?? body.accessToken ?? null;\r\n if (!this.token) throw new AuthenticationError(\"Token response contained no token\", 401);\r\n\r\n if (body.result?.expiry) {\r\n // expiry is an ISO datetime string; subtract 60s buffer\r\n this.tokenExpiresAt = new Date(body.result.expiry).getTime() - 60_000;\r\n } else {\r\n const ttlSec = body.expiresIn ?? 3600;\r\n this.tokenExpiresAt = Date.now() + (ttlSec - 60) * 1000;\r\n }\r\n return this.token;\r\n }\r\n\r\n async get<T>(path: string, init?: RequestInit): Promise<T> {\r\n return this.request<T>(\"GET\", path, init);\r\n }\r\n\r\n async post<T>(path: string, body?: unknown, init?: RequestInit): Promise<T> {\r\n const extra: RequestInit = { headers: { \"Content-Type\": \"application/json\", ...(init?.headers ?? {}) } };\r\n if (body !== undefined) extra.body = JSON.stringify(body);\r\n return this.request<T>(\"POST\", path, { ...init, ...extra });\r\n }\r\n\r\n async delete<T>(path: string, body?: unknown, init?: RequestInit): Promise<T> {\r\n const extra: RequestInit = { headers: { \"Content-Type\": \"application/json\", ...(init?.headers ?? {}) } };\r\n if (body !== undefined) extra.body = JSON.stringify(body);\r\n return this.request<T>(\"DELETE\", path, { ...init, ...extra });\r\n }\r\n\r\n async request<T>(method: string, path: string, init?: RequestInit): Promise<T> {\r\n const retryCfg = this.config.retry;\r\n const maxAttempts = retryCfg === false ? 1 : retryCfg.maxRetries + 1;\r\n\r\n let lastErr: unknown;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n return await this.rawRequest<T>(method, path, init);\r\n } catch (err) {\r\n lastErr = err;\r\n\r\n if (attempt >= maxAttempts - 1) break;\r\n if (!isRetryable(err)) break;\r\n if (retryCfg === false) break;\r\n\r\n let delay: number;\r\n if (err instanceof RateLimitError) {\r\n // Honor Retry-After header (value in seconds)\r\n const retryAfterSec =\r\n err.details !== null &&\r\n typeof err.details === \"object\" &&\r\n \"retryAfterSeconds\" in (err.details as object)\r\n ? Number((err.details as { retryAfterSeconds: unknown }).retryAfterSeconds)\r\n : NaN;\r\n delay = Number.isFinite(retryAfterSec) && retryAfterSec > 0\r\n ? retryAfterSec * 1000\r\n : retryDelayMs(attempt, retryCfg.baseDelayMs, retryCfg.maxDelayMs);\r\n } else {\r\n delay = retryDelayMs(attempt, retryCfg.baseDelayMs, retryCfg.maxDelayMs);\r\n }\r\n\r\n await sleep(delay);\r\n }\r\n }\r\n\r\n throw lastErr;\r\n }\r\n\r\n private async rawRequest<T>(method: string, path: string, init?: RequestInit): Promise<T> {\r\n const token = await this.getBearerToken();\r\n const url = `${this.config.baseUrl}${path}`;\r\n\r\n const headers: Record<string, string> = {\r\n Authorization: `Bearer ${token}`,\r\n \"User-Agent\": this.config.userAgent,\r\n ...(init?.headers as Record<string, string> | undefined ?? {}),\r\n };\r\n\r\n const { Authorization: _redacted, ...hookHeaders } = headers;\r\n this.config.onRequest?.({ method, url, headers: hookHeaders });\r\n\r\n const start = Date.now();\r\n const res = await this.config.customFetch(url, {\r\n method,\r\n ...init,\r\n headers,\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n this.config.onResponse?.({ status: res.status, url, durationMs: Date.now() - start });\r\n\r\n if (!res.ok) {\r\n const err = await buildError(res);\r\n // Attach Retry-After from the response header so the retry loop can read it\r\n if (err instanceof RateLimitError) {\r\n const retryAfter = res.headers.get(\"Retry-After\");\r\n if (retryAfter) {\r\n (err as RateLimitError & { details: unknown }).details =\r\n typeof err.details === \"object\" && err.details !== null\r\n ? { ...err.details as object, retryAfterSeconds: Number(retryAfter) }\r\n : { retryAfterSeconds: Number(retryAfter) };\r\n }\r\n }\r\n throw err;\r\n }\r\n\r\n // Some endpoints return 204 No Content\r\n if (res.status === 204 || res.headers.get(\"content-length\") === \"0\") {\r\n return undefined as T;\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n }\r\n}\r\n","import { createHash, randomBytes } from \"crypto\";\r\nimport { HttpClient } from \"./http.js\";\r\nimport { ResolvedConfig } from \"./config.js\";\r\nimport { AuthenticationError } from \"./errors.js\";\r\nimport { TokenResponse } from \"./types.js\";\r\n\r\nexport interface AuthCodeTokenResponse extends TokenResponse {\r\n refresh_token?: string;\r\n token_type?: string;\r\n scope?: string;\r\n}\r\n\r\n/** Response from `client.auth.refreshSsoToken()`. Both tokens are always present — DUPR rotates refresh tokens on every use. */\r\nexport interface SsoTokenResponse {\r\n accessToken: string;\r\n refreshToken: string;\r\n /** Seconds until the access token expires, if provided by DUPR. */\r\n expiresIn?: number;\r\n}\r\n\r\nexport interface AuthorizationUrlParams {\r\n /** Your OAuth redirect URI, must match what is registered with DUPR. */\r\n redirectUri: string;\r\n /** OAuth scopes to request (e.g. [\"user.read\"]). Defaults to empty. */\r\n scopes?: string[];\r\n /** Opaque value passed through the flow to prevent CSRF. Recommended. */\r\n state?: string;\r\n /** PKCE code_challenge (S256). Generate the pair with `client.auth.generatePkce()`. */\r\n codeChallenge?: string;\r\n}\r\n\r\nexport class AuthModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly config: ResolvedConfig,\r\n ) {}\r\n\r\n /**\r\n * Explicitly request a new access token using client credentials.\r\n * Normally you don't need to call this — the HTTP client handles token refresh automatically.\r\n */\r\n async getToken(): Promise<TokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"getToken() requires clientCredentials auth mode\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const encoded = Buffer.from(`${clientKey}:${clientSecret}`).toString(\"base64\");\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"x-authorization\": encoded,\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const body = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (body?.[\"message\"] as string | undefined) ?? `Auth failed: ${res.status}`,\r\n res.status,\r\n body,\r\n );\r\n }\r\n\r\n return res.json() as Promise<TokenResponse>;\r\n }\r\n\r\n // ── Authorization Code Flow ───────────────────────────────────────────────\r\n //\r\n // Use this flow to let end-users authorise your app to act on their behalf\r\n // (e.g. the \"Connect DUPR\" button). The user is redirected to DUPR's login\r\n // page, then back to your redirectUri with an authorization code.\r\n //\r\n // NOTE: This requires a DUPR OAuth application with an authorization endpoint\r\n // separate from the Partner API client credentials. Confirm the exact\r\n // authorization URL with DUPR support.\r\n //\r\n // Typical flow:\r\n // 1. client.auth.getAuthorizationUrl({ redirectUri, state }) → redirect user\r\n // 2. User approves → DUPR calls back to redirectUri?code=xxx&state=yyy\r\n // 3. client.auth.exchangeCode({ code, redirectUri }) → tokens\r\n // 4. Store access_token + refresh_token; call client.setBearerToken(access_token)\r\n // 5. When access_token expires: client.auth.refreshToken(refresh_token)\r\n\r\n /** Generate a PKCE `code_verifier` + `code_challenge` pair (S256 method).\r\n * Pass `codeChallenge` to `getAuthorizationUrl()` and `codeVerifier` to `exchangeCode()`. */\r\n generatePkce(): { codeVerifier: string; codeChallenge: string } {\r\n const codeVerifier = randomBytes(32).toString(\"base64url\");\r\n const codeChallenge = createHash(\"sha256\").update(codeVerifier).digest(\"base64url\");\r\n return { codeVerifier, codeChallenge };\r\n }\r\n\r\n /**\r\n * Build the DUPR authorization URL to redirect the user to for login.\r\n * The `authorizationUrl` config option must be set (see above note).\r\n * Pass `codeChallenge` (from `generatePkce()`) to enable PKCE.\r\n */\r\n getAuthorizationUrl(params: AuthorizationUrlParams): string {\r\n if (!this.config.authorizationUrl) {\r\n throw new Error(\r\n \"authorizationUrl is not configured. Pass it in DuprClientOptions to use the Authorization Code flow.\",\r\n );\r\n }\r\n const url = new URL(this.config.authorizationUrl);\r\n const clientId = this.config.auth.type === \"clientCredentials\" ? this.config.auth.clientKey : \"\";\r\n url.searchParams.set(\"response_type\", \"code\");\r\n url.searchParams.set(\"client_id\", clientId);\r\n url.searchParams.set(\"redirect_uri\", params.redirectUri);\r\n if (params.scopes?.length) url.searchParams.set(\"scope\", params.scopes.join(\" \"));\r\n if (params.state) url.searchParams.set(\"state\", params.state);\r\n if (params.codeChallenge) {\r\n url.searchParams.set(\"code_challenge\", params.codeChallenge);\r\n url.searchParams.set(\"code_challenge_method\", \"S256\");\r\n }\r\n return url.toString();\r\n }\r\n\r\n /**\r\n * Exchange an authorization code (from the OAuth callback) for access + refresh tokens.\r\n * Uses `POST /auth/{version}/token` with `grant_type=authorization_code`.\r\n */\r\n async exchangeCode(params: {\r\n code: string;\r\n redirectUri: string;\r\n /** PKCE code_verifier. Required if `codeChallenge` was passed to `getAuthorizationUrl()`. */\r\n codeVerifier?: string;\r\n }): Promise<AuthCodeTokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"exchangeCode() requires clientCredentials auth configured with clientKey/clientSecret\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n const body = new URLSearchParams({\r\n grant_type: \"authorization_code\",\r\n code: params.code,\r\n redirect_uri: params.redirectUri,\r\n client_id: clientKey,\r\n client_secret: clientSecret,\r\n });\r\n if (params.codeVerifier) body.set(\"code_verifier\", params.codeVerifier);\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: body.toString(),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `Code exchange failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n return res.json() as Promise<AuthCodeTokenResponse>;\r\n }\r\n\r\n // ── SSO Iframe Flow ───────────────────────────────────────────────────────\r\n //\r\n // DUPR's documented SSO approach for user-facing login uses an embedded iframe\r\n // rather than a standard OAuth2 redirect. The iframe emits a window.postMessage\r\n // event upon successful login.\r\n //\r\n // Typical flow:\r\n // 1. client.auth.getSsoIframeUrl() → embed in <iframe allow=\"payment\">\r\n // 2. User logs in inside the iframe\r\n // 3. Listen for window.postMessage → { userToken, refreshToken, id, duprId, stats }\r\n // 4. Store userToken + refreshToken server-side; record tokenExpiresAt\r\n // (7 days UAT / 30 days prod — not returned in the event, apply based on env)\r\n // 5. When userToken nears expiry: client.auth.refreshSsoToken(refreshToken)\r\n // DUPR rotates refresh tokens — store both returned tokens.\r\n //\r\n // UAT iframe host: https://uat.dupr.gg\r\n // Prod iframe host: https://dashboard.dupr.com\r\n // Always validate window.postMessage origin against the expected host.\r\n\r\n /**\r\n * Returns the DUPR SSO iframe URL. Embed this in an `<iframe allow=\"payment\">` to\r\n * display the DUPR login widget. Requires `ssoBaseUrl` in `DuprClientOptions`.\r\n */\r\n getSsoIframeUrl(): string {\r\n if (!this.config.ssoBaseUrl) {\r\n throw new Error(\r\n \"ssoBaseUrl is not configured. Pass it in DuprClientOptions to use the SSO iframe flow.\",\r\n );\r\n }\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\r\n \"getSsoIframeUrl() requires clientCredentials auth mode\",\r\n 401,\r\n );\r\n }\r\n const encoded = Buffer.from(this.config.auth.clientKey).toString(\"base64\");\r\n return `${this.config.ssoBaseUrl}/login-external-app/${encoded}`;\r\n }\r\n\r\n /**\r\n * Refresh a DUPR SSO user token obtained from the iframe login `postMessage` event.\r\n * Uses a separate refresh endpoint on `ssoRefreshBaseUrl` (distinct from the Partner API).\r\n * Requires `ssoRefreshBaseUrl` in `DuprClientOptions`.\r\n *\r\n * DUPR rotates refresh tokens on every use — always store both `accessToken` and\r\n * `refreshToken` from the response.\r\n */\r\n async refreshSsoToken(refreshToken: string): Promise<SsoTokenResponse> {\r\n if (!this.config.ssoRefreshBaseUrl) {\r\n throw new Error(\r\n \"ssoRefreshBaseUrl is not configured. Pass it in DuprClientOptions to use SSO token refresh.\",\r\n );\r\n }\r\n const res = await this.config.customFetch(\r\n `${this.config.ssoRefreshBaseUrl}/api/auth/refreshAccessToken`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: JSON.stringify({ refreshToken }),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n },\r\n );\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `SSO token refresh failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n const data = await res.json() as Record<string, unknown>;\r\n const accessToken = (data[\"accessToken\"] ?? data[\"userToken\"]) as string | undefined;\r\n const newRefreshToken = data[\"refreshToken\"] as string | undefined;\r\n\r\n if (!accessToken) {\r\n throw new AuthenticationError(\"SSO token refresh response missing accessToken\", 502);\r\n }\r\n if (!newRefreshToken) {\r\n throw new AuthenticationError(\r\n \"SSO token refresh response missing refreshToken — DUPR token rotation failed\",\r\n 502,\r\n );\r\n }\r\n\r\n return {\r\n accessToken,\r\n refreshToken: newRefreshToken,\r\n ...(data[\"expiresIn\"] !== undefined && { expiresIn: data[\"expiresIn\"] as number }),\r\n };\r\n }\r\n\r\n /**\r\n * Obtain a new access token using a refresh token from a previous Authorization Code flow.\r\n * Uses `POST /auth/{version}/token` with `grant_type=refresh_token`.\r\n */\r\n async refreshToken(refreshToken: string): Promise<AuthCodeTokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"refreshToken() requires clientCredentials auth configured\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n const body = new URLSearchParams({\r\n grant_type: \"refresh_token\",\r\n refresh_token: refreshToken,\r\n client_id: clientKey,\r\n client_secret: clientSecret,\r\n });\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: body.toString(),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `Token refresh failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n return res.json() as Promise<AuthCodeTokenResponse>;\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ClubMembershipResponse,\r\n CreateProvisionalRatingRequest,\r\n DeleteProvisionalRatingRequest,\r\n ExtendedUserInfo,\r\n ExternalBatchUserDetailRequest,\r\n ExternalInviteRequest,\r\n ExternalSearchRequest,\r\n GetProvisionalRatingRequest,\r\n GrantExternalSubscriptionRequest,\r\n UpdateProvisionalRatingRequest,\r\n UserInfo,\r\n} from \"../types.js\";\r\n\r\nexport class UsersModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** GET /user/{version}/{id} — basic player profile */\r\n getUser(duprId: string): Promise<ApiWrapper<UserInfo>> {\r\n return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}`);\r\n }\r\n\r\n /** GET /user/{version}/{id}/details — extended profile (requires USER_EMAIL::VIEW permission) */\r\n getExtendedUser(duprId: string): Promise<ApiWrapper<ExtendedUserInfo>> {\r\n return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}/details`);\r\n }\r\n\r\n /** GET /user/{version}/{id}/clubs — club memberships for a player */\r\n getClubMemberships(duprId: string): Promise<ClubMembershipResponse> {\r\n return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}/clubs`);\r\n }\r\n\r\n /** POST /user/{version}/search — full-text player search with optional filters */\r\n search(req: ExternalSearchRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/user/${this.cfg.version}/search`, req);\r\n }\r\n\r\n /** POST /user/{version}/batch — fetch multiple players by DUPR ID in one request */\r\n getBatch(req: ExternalBatchUserDetailRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/user/${this.cfg.version}/batch`, req);\r\n }\r\n\r\n /** POST /user/{version}/invite — pre-generate a DUPR ID and send an invite email */\r\n invite(req: ExternalInviteRequest): Promise<ApiWrapper<{ duprId: string }>> {\r\n return this.http.post(`/user/${this.cfg.version}/invite`, req);\r\n }\r\n\r\n /** POST /user/{version}/subscription/grants — grant a subscription to a user */\r\n grantSubscription(req: GrantExternalSubscriptionRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/subscription/grants`, req);\r\n }\r\n\r\n // ── Provisional ratings ──────────────────────────────────────\r\n\r\n /** POST /user/{version}/provisional_rating — get provisional ratings for a player */\r\n getProvisionalRating(req: GetProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating`, req);\r\n }\r\n\r\n /** POST /user/{version}/provisional_rating/create */\r\n createProvisionalRating(req: CreateProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating/create`, req);\r\n }\r\n\r\n /** POST /user/{version}/provisional_rating/update */\r\n updateProvisionalRating(req: UpdateProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating/update`, req);\r\n }\r\n\r\n /** DELETE /user/{version}/provisional_rating/delete */\r\n deleteProvisionalRating(req: DeleteProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/user/${this.cfg.version}/provisional_rating/delete`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper } from \"../types.js\";\r\n\r\nexport interface GetDuprIdByEmailRequest {\r\n email: string;\r\n}\r\n\r\nexport interface DuprIdByEmailResponse {\r\n duprId?: string;\r\n}\r\n\r\nexport class PlayersModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /{version}/player/duprid-by-email — resolve a DUPR ID from an email address */\r\n getDuprIdByEmail(req: GetDuprIdByEmailRequest): Promise<ApiWrapper<DuprIdByEmailResponse>> {\r\n return this.http.post(`/${this.cfg.version}/player/duprid-by-email`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper, PlayerRatingSubscribeRequest } from \"../types.js\";\r\n\r\nexport interface PlayerRatingHistoryRequest {\r\n duprId: string;\r\n offset?: number;\r\n limit?: number;\r\n}\r\n\r\nexport interface PlayerRatingHistoryEntry {\r\n date?: string;\r\n singlesRating?: number;\r\n doublesRating?: number;\r\n}\r\n\r\nexport class PlayerRatingModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /history — get rating history for a player */\r\n getHistory(req: PlayerRatingHistoryRequest): Promise<ApiWrapper<PlayerRatingHistoryEntry[]>> {\r\n return this.http.post(`/history`, req);\r\n }\r\n\r\n /** GET /{version}/subscribe/rating-changes — list currently subscribed DUPR IDs */\r\n getSubscriptions(): Promise<ApiWrapper<{ duprIds: string[] }>> {\r\n return this.http.get(`/${this.cfg.version}/subscribe/rating-changes`);\r\n }\r\n\r\n /** POST /{version}/subscribe/rating-changes — subscribe to rating-change events for a list of players */\r\n subscribe(req: PlayerRatingSubscribeRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/${this.cfg.version}/subscribe/rating-changes`, req);\r\n }\r\n\r\n /** DELETE /{version}/subscribe/rating-changes — unsubscribe from rating-change events */\r\n unsubscribe(req: PlayerRatingSubscribeRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/${this.cfg.version}/subscribe/rating-changes`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ExternalDeleteMatchRequest,\r\n ExternalMatchRequest,\r\n ExternalMatchSearchRequest,\r\n ExternalUpdateMatchRequest,\r\n MatchResponse,\r\n} from \"../types.js\";\r\n\r\nexport interface AnnotateMatchRequest {\r\n matchId: string;\r\n annotation: Record<string, unknown>;\r\n}\r\n\r\nexport class MatchesModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** GET /match/{version}/{id} — view a single match */\r\n get(matchId: string): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.get(`/match/${this.cfg.version}/${encodeURIComponent(matchId)}`);\r\n }\r\n\r\n /** POST /match/{version}/create — submit a new match result */\r\n create(match: ExternalMatchRequest): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.post(`/match/${this.cfg.version}/create`, match);\r\n }\r\n\r\n /** POST /match/{version}/batch — submit multiple match results in one call */\r\n createBulk(matches: ExternalMatchRequest[]): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/match/${this.cfg.version}/batch`, matches);\r\n }\r\n\r\n /** POST /match/{version}/update — update an existing match */\r\n update(req: ExternalUpdateMatchRequest): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.post(`/match/${this.cfg.version}/update`, req);\r\n }\r\n\r\n /** DELETE /match/{version}/delete — delete a match */\r\n delete(req: ExternalDeleteMatchRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/match/${this.cfg.version}/delete`, req);\r\n }\r\n\r\n /** POST /match/{version}/annotate — attach vendor-specific metadata to a match */\r\n annotate(req: AnnotateMatchRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/match/${this.cfg.version}/annotate`, req);\r\n }\r\n\r\n /** DELETE /match/{version}/annotate/{matchId} — remove a match annotation */\r\n deleteAnnotation(matchId: string): Promise<ApiWrapper> {\r\n return this.http.delete(`/match/${this.cfg.version}/annotate/${encodeURIComponent(matchId)}`);\r\n }\r\n\r\n /** POST /match/history/search — search a player's match history */\r\n searchHistory(req: ExternalMatchSearchRequest): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/match/history/search`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ExternalClubMemberRequest,\r\n ExternalClubMatchSearchRequest,\r\n MatchResponse,\r\n UserInfo,\r\n} from \"../types.js\";\r\n\r\nexport class ClubsModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /club/{version}/members — get ratings for all members of a club */\r\n membersRating(req: ExternalClubMemberRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/club/${this.cfg.version}/members`, req);\r\n }\r\n\r\n /** POST /club/{version}/match/search — search matches associated with a club */\r\n searchMatches(req: ExternalClubMatchSearchRequest): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/club/${this.cfg.version}/match/search`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n CreateEventRequestV1,\r\n CreateEventResponseV1,\r\n DeleteEventRequestV1,\r\n DeleteEventResponseV1,\r\n GetEventRequestV1,\r\n GetEventResponseV1,\r\n UpdateEventRequestV1,\r\n UpdateEventResponseV1,\r\n} from \"../types.js\";\r\n\r\nexport class EventsModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /events/{version}/create */\r\n create(req: CreateEventRequestV1): Promise<ApiWrapper<CreateEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/create`, req);\r\n }\r\n\r\n /** GET /events/{version}/get */\r\n get(req: GetEventRequestV1): Promise<ApiWrapper<GetEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/get`, req);\r\n }\r\n\r\n /** POST /events/{version}/update */\r\n update(req: UpdateEventRequestV1): Promise<ApiWrapper<UpdateEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/update`, req);\r\n }\r\n\r\n /** POST /events/{version}/delete */\r\n delete(req: DeleteEventRequestV1): Promise<ApiWrapper<DeleteEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/delete`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper, ClientHookRequest, UserWebhookRequest, WebhookSchema } from \"../types.js\";\r\n\r\nexport class WebhooksModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /{version}/webhook — register a webhook endpoint */\r\n register(req: ClientHookRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/${this.cfg.version}/webhook`, req);\r\n }\r\n\r\n /** GET /{version}/topic — list all available webhook topics */\r\n getTopics(): Promise<ApiWrapper<string[]>> {\r\n return this.http.get(`/${this.cfg.version}/topic`);\r\n }\r\n\r\n /** GET /{version}/webhook/schema — list available webhook schemas */\r\n listSchemas(): Promise<ApiWrapper<WebhookSchema[]>> {\r\n return this.http.get(`/${this.cfg.version}/webhook/schema`);\r\n }\r\n\r\n /** GET /{version}/webhook/schema/{topic} — get the JSON schema for a specific topic */\r\n getSchema(topic: string): Promise<ApiWrapper<WebhookSchema>> {\r\n return this.http.get(`/${this.cfg.version}/webhook/schema/${encodeURIComponent(topic)}`);\r\n }\r\n\r\n /** POST /user/{version}/subscribe/webhook-event — subscribe specific users to a webhook topic */\r\n subscribeUsers(req: UserWebhookRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/subscribe/webhook-event`, req);\r\n }\r\n\r\n /** DELETE /user/{version}/subscribe/webhook-event — unsubscribe specific users from a webhook topic */\r\n unsubscribeUsers(req: UserWebhookRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/user/${this.cfg.version}/subscribe/webhook-event`, req);\r\n }\r\n}\r\n","import { DuprClientOptions, ResolvedConfig, resolveConfig } from \"./config.js\";\r\nimport { HttpClient } from \"./http.js\";\r\nimport { AuthModule } from \"./auth.js\";\r\nimport { UsersModule } from \"./resources/users.js\";\r\nimport { PlayersModule } from \"./resources/players.js\";\r\nimport { PlayerRatingModule } from \"./resources/playerRating.js\";\r\nimport { MatchesModule } from \"./resources/matches.js\";\r\nimport { ClubsModule } from \"./resources/clubs.js\";\r\nimport { EventsModule } from \"./resources/events.js\";\r\nimport { WebhooksModule } from \"./resources/webhooks.js\";\r\n\r\nexport class DuprClient {\r\n readonly config: ResolvedConfig;\r\n readonly auth: AuthModule;\r\n readonly users: UsersModule;\r\n readonly players: PlayersModule;\r\n readonly playerRating: PlayerRatingModule;\r\n readonly matches: MatchesModule;\r\n readonly clubs: ClubsModule;\r\n readonly events: EventsModule;\r\n readonly webhooks: WebhooksModule;\r\n\r\n constructor(opts: DuprClientOptions = {}) {\r\n this.config = resolveConfig(opts);\r\n const http = new HttpClient(this.config);\r\n this.auth = new AuthModule(http, this.config);\r\n this.users = new UsersModule(http, this.config);\r\n this.players = new PlayersModule(http, this.config);\r\n this.playerRating = new PlayerRatingModule(http, this.config);\r\n this.matches = new MatchesModule(http, this.config);\r\n this.clubs = new ClubsModule(http, this.config);\r\n this.events = new EventsModule(http, this.config);\r\n this.webhooks = new WebhooksModule(http, this.config);\r\n }\r\n\r\n /** Override the bearer token at runtime — useful when your backend handles auth separately. */\r\n setBearerToken(token: string): void {\r\n this.config.overrideBearerToken = token;\r\n }\r\n\r\n /** Clear the runtime bearer token override and fall back to configured auth. */\r\n clearBearerToken(): void {\r\n delete this.config.overrideBearerToken;\r\n }\r\n}\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dupr-js-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A comprehensive TypeScript/JavaScript client for the DUPR (Dynamic Universal Pickleball Rating) API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sunny Tambi",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"prepublishOnly": "npm run build && npm run typecheck"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
+
"@changesets/cli": "^2.31.0",
|
|
38
39
|
"@types/node": "^20.0.0",
|
|
39
40
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
40
41
|
"@typescript-eslint/parser": "^7.0.0",
|