dupr-js-client 0.1.3 → 2.0.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/README.md +3 -3
- package/dist/index.d.ts +122 -18
- package/dist/index.js +124 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -149,7 +149,7 @@ const client = new DuprClient(options);
|
|
|
149
149
|
import { DuprClient } from "dupr-js-client";
|
|
150
150
|
|
|
151
151
|
export const dupr = new DuprClient({
|
|
152
|
-
baseUrl: process.env.
|
|
152
|
+
baseUrl: process.env.DUPR_API_BASE_URL ?? "https://uat.mydupr.com/api",
|
|
153
153
|
auth: {
|
|
154
154
|
type: "clientCredentials",
|
|
155
155
|
clientKey: process.env.DUPR_CLIENT_KEY!,
|
|
@@ -160,7 +160,7 @@ export const dupr = new DuprClient({
|
|
|
160
160
|
|
|
161
161
|
```ini
|
|
162
162
|
# .env
|
|
163
|
-
|
|
163
|
+
DUPR_API_BASE_URL=https://uat.mydupr.com/api
|
|
164
164
|
DUPR_CLIENT_KEY=your_client_key
|
|
165
165
|
DUPR_CLIENT_SECRET=your_client_secret
|
|
166
166
|
```
|
|
@@ -794,7 +794,7 @@ it("retries once then succeeds", async () => {
|
|
|
794
794
|
import { DuprClient } from "dupr-js-client";
|
|
795
795
|
|
|
796
796
|
export const dupr = new DuprClient({
|
|
797
|
-
baseUrl: process.env.
|
|
797
|
+
baseUrl: process.env.DUPR_API_BASE_URL ?? "https://uat.mydupr.com/api",
|
|
798
798
|
auth: {
|
|
799
799
|
type: "clientCredentials",
|
|
800
800
|
clientKey: process.env.DUPR_CLIENT_KEY!,
|
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,26 @@ interface DuprClientOptions {
|
|
|
44
44
|
onResponse?: (info: ResponseInfo) => void;
|
|
45
45
|
/** Retry behaviour for transient errors (5xx, network failures, 429). Pass `false` to disable. */
|
|
46
46
|
retry?: RetryOptions | false;
|
|
47
|
+
/**
|
|
48
|
+
* Base URL for the DUPR SSO iframe login widget.
|
|
49
|
+
* UAT: "https://uat.dupr.gg"
|
|
50
|
+
* Prod: "https://dashboard.dupr.com"
|
|
51
|
+
* Required to call `client.auth.getSsoIframeUrl()`.
|
|
52
|
+
*/
|
|
53
|
+
ssoBaseUrl?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Base URL for refreshing DUPR SSO user tokens — a separate host from the Partner API.
|
|
56
|
+
* UAT: "https://api.uat.dupr.gg"
|
|
57
|
+
* Prod: "https://api.dupr.gg"
|
|
58
|
+
* Required to call `client.auth.refreshSsoToken()`.
|
|
59
|
+
*/
|
|
60
|
+
ssoRefreshBaseUrl?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Authorization endpoint URL for the OAuth 2.0 authorization code flow.
|
|
63
|
+
* Confirm the exact value with DUPR support before use.
|
|
64
|
+
* Required to call `client.auth.getAuthorizationUrl()`.
|
|
65
|
+
*/
|
|
66
|
+
authorizationUrl?: string;
|
|
47
67
|
}
|
|
48
68
|
interface ResolvedRetryOptions {
|
|
49
69
|
maxRetries: number;
|
|
@@ -62,6 +82,9 @@ interface ResolvedConfig {
|
|
|
62
82
|
onResponse?: (info: ResponseInfo) => void;
|
|
63
83
|
/** Runtime override for the bearer token — set via `client.setBearerToken()`. */
|
|
64
84
|
overrideBearerToken?: string;
|
|
85
|
+
ssoBaseUrl?: string;
|
|
86
|
+
ssoRefreshBaseUrl?: string;
|
|
87
|
+
authorizationUrl?: string;
|
|
65
88
|
}
|
|
66
89
|
|
|
67
90
|
declare class HttpClient {
|
|
@@ -78,20 +101,29 @@ declare class HttpClient {
|
|
|
78
101
|
}
|
|
79
102
|
|
|
80
103
|
type MatchFormat = "SINGLES" | "DOUBLES";
|
|
81
|
-
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";
|
|
82
108
|
type Gender = "MALE" | "FEMALE";
|
|
83
109
|
type RatingType = "SINGLES" | "DOUBLES";
|
|
84
110
|
type WebhookTopic = "RATING";
|
|
85
|
-
type ApiStatus = "SUCCESS" | "FAILURE";
|
|
111
|
+
type ApiStatus = "SUCCESS" | "FAILURE" | "REDIRECT" | "PARTIAL";
|
|
86
112
|
interface ApiWrapper<T = unknown> {
|
|
87
113
|
status: ApiStatus;
|
|
88
114
|
message?: string;
|
|
89
115
|
result?: T;
|
|
90
116
|
}
|
|
91
117
|
interface TokenResponse {
|
|
118
|
+
/** Flat format (some DUPR environments return the token directly at the top level). */
|
|
92
119
|
token?: string;
|
|
93
120
|
accessToken?: string;
|
|
94
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
|
+
};
|
|
95
127
|
}
|
|
96
128
|
interface UserInfo {
|
|
97
129
|
duprId: string;
|
|
@@ -170,30 +202,70 @@ interface UpdateProvisionalRatingRequest {
|
|
|
170
202
|
interface DeleteProvisionalRatingRequest {
|
|
171
203
|
duprId: string;
|
|
172
204
|
}
|
|
173
|
-
interface ExternalMatchPlayer {
|
|
174
|
-
duprId: string;
|
|
175
|
-
}
|
|
176
205
|
interface ExternalMatchTeam {
|
|
177
|
-
/**
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
|
|
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;
|
|
181
215
|
}
|
|
182
216
|
interface ExternalMatchRequest {
|
|
183
|
-
/**
|
|
217
|
+
/** Universally unique identifier for this match — must never be reused. */
|
|
184
218
|
identifier: string;
|
|
185
|
-
/** yyyy-MM-dd */
|
|
219
|
+
/** yyyy-MM-dd (ISO 8601 date). */
|
|
186
220
|
matchDate: string;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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. */
|
|
191
236
|
clubId?: number;
|
|
237
|
+
/** Optional key-value metadata. */
|
|
238
|
+
extras?: Record<string, string>;
|
|
239
|
+
matchCompletionType?: MatchCompletionType;
|
|
240
|
+
matchPlayType?: MatchPlayType;
|
|
192
241
|
}
|
|
193
242
|
interface ExternalUpdateMatchRequest {
|
|
194
|
-
|
|
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). */
|
|
195
248
|
matchDate?: string;
|
|
196
|
-
|
|
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?: number;
|
|
265
|
+
/** Optional key-value metadata. */
|
|
266
|
+
extras?: Record<string, string>;
|
|
267
|
+
matchCompletionType?: MatchCompletionType;
|
|
268
|
+
matchPlayType?: MatchPlayType;
|
|
197
269
|
}
|
|
198
270
|
interface ExternalDeleteMatchRequest {
|
|
199
271
|
matchCode: string;
|
|
@@ -299,6 +371,13 @@ interface AuthCodeTokenResponse extends TokenResponse {
|
|
|
299
371
|
token_type?: string;
|
|
300
372
|
scope?: string;
|
|
301
373
|
}
|
|
374
|
+
/** Response from `client.auth.refreshSsoToken()`. Both tokens are always present — DUPR rotates refresh tokens on every use. */
|
|
375
|
+
interface SsoTokenResponse {
|
|
376
|
+
accessToken: string;
|
|
377
|
+
refreshToken: string;
|
|
378
|
+
/** Seconds until the access token expires, if provided by DUPR. */
|
|
379
|
+
expiresIn?: number;
|
|
380
|
+
}
|
|
302
381
|
interface AuthorizationUrlParams {
|
|
303
382
|
/** Your OAuth redirect URI, must match what is registered with DUPR. */
|
|
304
383
|
redirectUri: string;
|
|
@@ -306,6 +385,8 @@ interface AuthorizationUrlParams {
|
|
|
306
385
|
scopes?: string[];
|
|
307
386
|
/** Opaque value passed through the flow to prevent CSRF. Recommended. */
|
|
308
387
|
state?: string;
|
|
388
|
+
/** PKCE code_challenge (S256). Generate the pair with `client.auth.generatePkce()`. */
|
|
389
|
+
codeChallenge?: string;
|
|
309
390
|
}
|
|
310
391
|
declare class AuthModule {
|
|
311
392
|
private readonly http;
|
|
@@ -316,9 +397,16 @@ declare class AuthModule {
|
|
|
316
397
|
* Normally you don't need to call this — the HTTP client handles token refresh automatically.
|
|
317
398
|
*/
|
|
318
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
|
+
};
|
|
319
406
|
/**
|
|
320
407
|
* Build the DUPR authorization URL to redirect the user to for login.
|
|
321
408
|
* The `authorizationUrl` config option must be set (see above note).
|
|
409
|
+
* Pass `codeChallenge` (from `generatePkce()`) to enable PKCE.
|
|
322
410
|
*/
|
|
323
411
|
getAuthorizationUrl(params: AuthorizationUrlParams): string;
|
|
324
412
|
/**
|
|
@@ -328,7 +416,23 @@ declare class AuthModule {
|
|
|
328
416
|
exchangeCode(params: {
|
|
329
417
|
code: string;
|
|
330
418
|
redirectUri: string;
|
|
419
|
+
/** PKCE code_verifier. Required if `codeChallenge` was passed to `getAuthorizationUrl()`. */
|
|
420
|
+
codeVerifier?: string;
|
|
331
421
|
}): Promise<AuthCodeTokenResponse>;
|
|
422
|
+
/**
|
|
423
|
+
* Returns the DUPR SSO iframe URL. Embed this in an `<iframe allow="payment">` to
|
|
424
|
+
* display the DUPR login widget. Requires `ssoBaseUrl` in `DuprClientOptions`.
|
|
425
|
+
*/
|
|
426
|
+
getSsoIframeUrl(): string;
|
|
427
|
+
/**
|
|
428
|
+
* Refresh a DUPR SSO user token obtained from the iframe login `postMessage` event.
|
|
429
|
+
* Uses a separate refresh endpoint on `ssoRefreshBaseUrl` (distinct from the Partner API).
|
|
430
|
+
* Requires `ssoRefreshBaseUrl` in `DuprClientOptions`.
|
|
431
|
+
*
|
|
432
|
+
* DUPR rotates refresh tokens on every use — always store both `accessToken` and
|
|
433
|
+
* `refreshToken` from the response.
|
|
434
|
+
*/
|
|
435
|
+
refreshSsoToken(refreshToken: string): Promise<SsoTokenResponse>;
|
|
332
436
|
/**
|
|
333
437
|
* Obtain a new access token using a refresh token from a previous Authorization Code flow.
|
|
334
438
|
* Uses `POST /auth/{version}/token` with `grant_type=refresh_token`.
|
|
@@ -513,4 +617,4 @@ declare class ServerError extends DuprApiError {
|
|
|
513
617
|
constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string);
|
|
514
618
|
}
|
|
515
619
|
|
|
516
|
-
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 = {
|
|
@@ -15,6 +17,9 @@ function resolveConfig(opts) {
|
|
|
15
17
|
};
|
|
16
18
|
if (opts.onRequest) cfg.onRequest = opts.onRequest;
|
|
17
19
|
if (opts.onResponse) cfg.onResponse = opts.onResponse;
|
|
20
|
+
if (opts.ssoBaseUrl) cfg.ssoBaseUrl = opts.ssoBaseUrl;
|
|
21
|
+
if (opts.ssoRefreshBaseUrl) cfg.ssoRefreshBaseUrl = opts.ssoRefreshBaseUrl;
|
|
22
|
+
if (opts.authorizationUrl) cfg.authorizationUrl = opts.authorizationUrl;
|
|
18
23
|
return cfg;
|
|
19
24
|
}
|
|
20
25
|
|
|
@@ -136,10 +141,14 @@ var HttpClient = class {
|
|
|
136
141
|
this.config.onResponse?.({ status: res.status, url, durationMs: Date.now() - start });
|
|
137
142
|
if (!res.ok) throw await buildError(res);
|
|
138
143
|
const body = await res.json();
|
|
139
|
-
this.token = body.token ?? body.accessToken ?? null;
|
|
144
|
+
this.token = body.result?.token ?? body.token ?? body.accessToken ?? null;
|
|
140
145
|
if (!this.token) throw new AuthenticationError("Token response contained no token", 401);
|
|
141
|
-
|
|
142
|
-
|
|
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
|
+
}
|
|
143
152
|
return this.token;
|
|
144
153
|
}
|
|
145
154
|
async get(path, init) {
|
|
@@ -187,7 +196,8 @@ var HttpClient = class {
|
|
|
187
196
|
"User-Agent": this.config.userAgent,
|
|
188
197
|
...init?.headers ?? {}
|
|
189
198
|
};
|
|
190
|
-
|
|
199
|
+
const { Authorization: _redacted, ...hookHeaders } = headers;
|
|
200
|
+
this.config.onRequest?.({ method, url, headers: hookHeaders });
|
|
191
201
|
const start = Date.now();
|
|
192
202
|
const res = await this.config.customFetch(url, {
|
|
193
203
|
method,
|
|
@@ -212,8 +222,6 @@ var HttpClient = class {
|
|
|
212
222
|
return res.json();
|
|
213
223
|
}
|
|
214
224
|
};
|
|
215
|
-
|
|
216
|
-
// src/auth.ts
|
|
217
225
|
var AuthModule = class {
|
|
218
226
|
constructor(http, config) {
|
|
219
227
|
this.http = http;
|
|
@@ -264,24 +272,35 @@ var AuthModule = class {
|
|
|
264
272
|
// 3. client.auth.exchangeCode({ code, redirectUri }) → tokens
|
|
265
273
|
// 4. Store access_token + refresh_token; call client.setBearerToken(access_token)
|
|
266
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
|
+
}
|
|
267
282
|
/**
|
|
268
283
|
* Build the DUPR authorization URL to redirect the user to for login.
|
|
269
284
|
* The `authorizationUrl` config option must be set (see above note).
|
|
285
|
+
* Pass `codeChallenge` (from `generatePkce()`) to enable PKCE.
|
|
270
286
|
*/
|
|
271
287
|
getAuthorizationUrl(params) {
|
|
272
|
-
|
|
273
|
-
if (!authUrl) {
|
|
288
|
+
if (!this.config.authorizationUrl) {
|
|
274
289
|
throw new Error(
|
|
275
290
|
"authorizationUrl is not configured. Pass it in DuprClientOptions to use the Authorization Code flow."
|
|
276
291
|
);
|
|
277
292
|
}
|
|
278
|
-
const url = new URL(
|
|
293
|
+
const url = new URL(this.config.authorizationUrl);
|
|
279
294
|
const clientId = this.config.auth.type === "clientCredentials" ? this.config.auth.clientKey : "";
|
|
280
295
|
url.searchParams.set("response_type", "code");
|
|
281
296
|
url.searchParams.set("client_id", clientId);
|
|
282
297
|
url.searchParams.set("redirect_uri", params.redirectUri);
|
|
283
298
|
if (params.scopes?.length) url.searchParams.set("scope", params.scopes.join(" "));
|
|
284
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
|
+
}
|
|
285
304
|
return url.toString();
|
|
286
305
|
}
|
|
287
306
|
/**
|
|
@@ -301,6 +320,7 @@ var AuthModule = class {
|
|
|
301
320
|
client_id: clientKey,
|
|
302
321
|
client_secret: clientSecret
|
|
303
322
|
});
|
|
323
|
+
if (params.codeVerifier) body.set("code_verifier", params.codeVerifier);
|
|
304
324
|
const res = await this.config.customFetch(url, {
|
|
305
325
|
method: "POST",
|
|
306
326
|
headers: {
|
|
@@ -320,6 +340,95 @@ var AuthModule = class {
|
|
|
320
340
|
}
|
|
321
341
|
return res.json();
|
|
322
342
|
}
|
|
343
|
+
// ── SSO Iframe Flow ───────────────────────────────────────────────────────
|
|
344
|
+
//
|
|
345
|
+
// DUPR's documented SSO approach for user-facing login uses an embedded iframe
|
|
346
|
+
// rather than a standard OAuth2 redirect. The iframe emits a window.postMessage
|
|
347
|
+
// event upon successful login.
|
|
348
|
+
//
|
|
349
|
+
// Typical flow:
|
|
350
|
+
// 1. client.auth.getSsoIframeUrl() → embed in <iframe allow="payment">
|
|
351
|
+
// 2. User logs in inside the iframe
|
|
352
|
+
// 3. Listen for window.postMessage → { userToken, refreshToken, id, duprId, stats }
|
|
353
|
+
// 4. Store userToken + refreshToken server-side; record tokenExpiresAt
|
|
354
|
+
// (7 days UAT / 30 days prod — not returned in the event, apply based on env)
|
|
355
|
+
// 5. When userToken nears expiry: client.auth.refreshSsoToken(refreshToken)
|
|
356
|
+
// DUPR rotates refresh tokens — store both returned tokens.
|
|
357
|
+
//
|
|
358
|
+
// UAT iframe host: https://uat.dupr.gg
|
|
359
|
+
// Prod iframe host: https://dashboard.dupr.com
|
|
360
|
+
// Always validate window.postMessage origin against the expected host.
|
|
361
|
+
/**
|
|
362
|
+
* Returns the DUPR SSO iframe URL. Embed this in an `<iframe allow="payment">` to
|
|
363
|
+
* display the DUPR login widget. Requires `ssoBaseUrl` in `DuprClientOptions`.
|
|
364
|
+
*/
|
|
365
|
+
getSsoIframeUrl() {
|
|
366
|
+
if (!this.config.ssoBaseUrl) {
|
|
367
|
+
throw new Error(
|
|
368
|
+
"ssoBaseUrl is not configured. Pass it in DuprClientOptions to use the SSO iframe flow."
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
if (this.config.auth.type !== "clientCredentials") {
|
|
372
|
+
throw new AuthenticationError(
|
|
373
|
+
"getSsoIframeUrl() requires clientCredentials auth mode",
|
|
374
|
+
401
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
const encoded = Buffer.from(this.config.auth.clientKey).toString("base64");
|
|
378
|
+
return `${this.config.ssoBaseUrl}/login-external-app/${encoded}`;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Refresh a DUPR SSO user token obtained from the iframe login `postMessage` event.
|
|
382
|
+
* Uses a separate refresh endpoint on `ssoRefreshBaseUrl` (distinct from the Partner API).
|
|
383
|
+
* Requires `ssoRefreshBaseUrl` in `DuprClientOptions`.
|
|
384
|
+
*
|
|
385
|
+
* DUPR rotates refresh tokens on every use — always store both `accessToken` and
|
|
386
|
+
* `refreshToken` from the response.
|
|
387
|
+
*/
|
|
388
|
+
async refreshSsoToken(refreshToken) {
|
|
389
|
+
if (!this.config.ssoRefreshBaseUrl) {
|
|
390
|
+
throw new Error(
|
|
391
|
+
"ssoRefreshBaseUrl is not configured. Pass it in DuprClientOptions to use SSO token refresh."
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
const res = await this.config.customFetch(
|
|
395
|
+
`${this.config.ssoRefreshBaseUrl}/api/auth/refreshAccessToken`,
|
|
396
|
+
{
|
|
397
|
+
method: "POST",
|
|
398
|
+
headers: {
|
|
399
|
+
"Content-Type": "application/json",
|
|
400
|
+
"User-Agent": this.config.userAgent
|
|
401
|
+
},
|
|
402
|
+
body: JSON.stringify({ refreshToken }),
|
|
403
|
+
signal: AbortSignal.timeout(this.config.timeoutMs)
|
|
404
|
+
}
|
|
405
|
+
);
|
|
406
|
+
if (!res.ok) {
|
|
407
|
+
const errBody = await res.json().catch(() => void 0);
|
|
408
|
+
throw new AuthenticationError(
|
|
409
|
+
errBody?.["message"] ?? `SSO token refresh failed: ${res.status}`,
|
|
410
|
+
res.status,
|
|
411
|
+
errBody
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
const data = await res.json();
|
|
415
|
+
const accessToken = data["accessToken"] ?? data["userToken"];
|
|
416
|
+
const newRefreshToken = data["refreshToken"];
|
|
417
|
+
if (!accessToken) {
|
|
418
|
+
throw new AuthenticationError("SSO token refresh response missing accessToken", 502);
|
|
419
|
+
}
|
|
420
|
+
if (!newRefreshToken) {
|
|
421
|
+
throw new AuthenticationError(
|
|
422
|
+
"SSO token refresh response missing refreshToken \u2014 DUPR token rotation failed",
|
|
423
|
+
502
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
accessToken,
|
|
428
|
+
refreshToken: newRefreshToken,
|
|
429
|
+
...data["expiresIn"] !== void 0 && { expiresIn: data["expiresIn"] }
|
|
430
|
+
};
|
|
431
|
+
}
|
|
323
432
|
/**
|
|
324
433
|
* Obtain a new access token using a refresh token from a previous Authorization Code flow.
|
|
325
434
|
* Uses `POST /auth/{version}/token` with `grant_type=refresh_token`.
|
|
@@ -365,15 +474,15 @@ var UsersModule = class {
|
|
|
365
474
|
}
|
|
366
475
|
/** GET /user/{version}/{id} — basic player profile */
|
|
367
476
|
getUser(duprId) {
|
|
368
|
-
return this.http.get(`/user/${this.cfg.version}/${duprId}`);
|
|
477
|
+
return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}`);
|
|
369
478
|
}
|
|
370
479
|
/** GET /user/{version}/{id}/details — extended profile (requires USER_EMAIL::VIEW permission) */
|
|
371
480
|
getExtendedUser(duprId) {
|
|
372
|
-
return this.http.get(`/user/${this.cfg.version}/${duprId}/details`);
|
|
481
|
+
return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}/details`);
|
|
373
482
|
}
|
|
374
483
|
/** GET /user/{version}/{id}/clubs — club memberships for a player */
|
|
375
484
|
getClubMemberships(duprId) {
|
|
376
|
-
return this.http.get(`/user/${this.cfg.version}/${duprId}/clubs`);
|
|
485
|
+
return this.http.get(`/user/${this.cfg.version}/${encodeURIComponent(duprId)}/clubs`);
|
|
377
486
|
}
|
|
378
487
|
/** POST /user/{version}/search — full-text player search with optional filters */
|
|
379
488
|
search(req) {
|
|
@@ -454,7 +563,7 @@ var MatchesModule = class {
|
|
|
454
563
|
}
|
|
455
564
|
/** GET /match/{version}/{id} — view a single match */
|
|
456
565
|
get(matchId) {
|
|
457
|
-
return this.http.get(`/match/${this.cfg.version}/${matchId}`);
|
|
566
|
+
return this.http.get(`/match/${this.cfg.version}/${encodeURIComponent(matchId)}`);
|
|
458
567
|
}
|
|
459
568
|
/** POST /match/{version}/create — submit a new match result */
|
|
460
569
|
create(match) {
|
|
@@ -478,7 +587,7 @@ var MatchesModule = class {
|
|
|
478
587
|
}
|
|
479
588
|
/** DELETE /match/{version}/annotate/{matchId} — remove a match annotation */
|
|
480
589
|
deleteAnnotation(matchId) {
|
|
481
|
-
return this.http.delete(`/match/${this.cfg.version}/annotate/${matchId}`);
|
|
590
|
+
return this.http.delete(`/match/${this.cfg.version}/annotate/${encodeURIComponent(matchId)}`);
|
|
482
591
|
}
|
|
483
592
|
/** POST /match/history/search — search a player's match history */
|
|
484
593
|
searchHistory(req) {
|
|
@@ -546,7 +655,7 @@ var WebhooksModule = class {
|
|
|
546
655
|
}
|
|
547
656
|
/** GET /{version}/webhook/schema/{topic} — get the JSON schema for a specific topic */
|
|
548
657
|
getSchema(topic) {
|
|
549
|
-
return this.http.get(`/${this.cfg.version}/webhook/schema/${topic}`);
|
|
658
|
+
return this.http.get(`/${this.cfg.version}/webhook/schema/${encodeURIComponent(topic)}`);
|
|
550
659
|
}
|
|
551
660
|
/** POST /user/{version}/subscribe/webhook-event — subscribe specific users to a webhook topic */
|
|
552
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\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}\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 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\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 const authUrl = (this.config as ResolvedConfig & { authorizationUrl?: string }).authorizationUrl;\r\n if (!authUrl) {\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(authUrl);\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 /**\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