dupr-js-client 0.1.3 → 1.0.1

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 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.DUPR_BASE_URL ?? "https://uat.mydupr.com/api",
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
- DUPR_BASE_URL=https://uat.mydupr.com/api
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.DUPR_BASE_URL ?? "https://uat.mydupr.com/api",
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 {
@@ -299,6 +322,13 @@ interface AuthCodeTokenResponse extends TokenResponse {
299
322
  token_type?: string;
300
323
  scope?: string;
301
324
  }
325
+ /** Response from `client.auth.refreshSsoToken()`. Both tokens are always present — DUPR rotates refresh tokens on every use. */
326
+ interface SsoTokenResponse {
327
+ accessToken: string;
328
+ refreshToken: string;
329
+ /** Seconds until the access token expires, if provided by DUPR. */
330
+ expiresIn?: number;
331
+ }
302
332
  interface AuthorizationUrlParams {
303
333
  /** Your OAuth redirect URI, must match what is registered with DUPR. */
304
334
  redirectUri: string;
@@ -329,6 +359,20 @@ declare class AuthModule {
329
359
  code: string;
330
360
  redirectUri: string;
331
361
  }): Promise<AuthCodeTokenResponse>;
362
+ /**
363
+ * Returns the DUPR SSO iframe URL. Embed this in an `<iframe allow="payment">` to
364
+ * display the DUPR login widget. Requires `ssoBaseUrl` in `DuprClientOptions`.
365
+ */
366
+ getSsoIframeUrl(): string;
367
+ /**
368
+ * Refresh a DUPR SSO user token obtained from the iframe login `postMessage` event.
369
+ * Uses a separate refresh endpoint on `ssoRefreshBaseUrl` (distinct from the Partner API).
370
+ * Requires `ssoRefreshBaseUrl` in `DuprClientOptions`.
371
+ *
372
+ * DUPR rotates refresh tokens on every use — always store both `accessToken` and
373
+ * `refreshToken` from the response.
374
+ */
375
+ refreshSsoToken(refreshToken: string): Promise<SsoTokenResponse>;
332
376
  /**
333
377
  * Obtain a new access token using a refresh token from a previous Authorization Code flow.
334
378
  * Uses `POST /auth/{version}/token` with `grant_type=refresh_token`.
@@ -513,4 +557,4 @@ declare class ServerError extends DuprApiError {
513
557
  constructor(message: string, statusCode: number, details?: unknown, duprRequestId?: string);
514
558
  }
515
559
 
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 ExternalMatchPlayer, 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 MatchFormat, type MatchResponse, type MatchSource, MatchesModule, NotFoundError, PlayerRatingModule, type PlayerRatingSubscribeRequest, PlayersModule, RateLimitError, type RatingCoach, type RatingType, type RequestInfo, type ResolvedConfig, type ResolvedRetryOptions, type ResponseInfo, type RetryOptions, ServerError, type SubscriptionItemRequest, type TargetUserRequest, type TokenResponse, type UpdateEventRequestV1, type UpdateEventResponseV1, type UpdateProvisionalRatingRequest, type UserInfo, type UserWebhookRequest, UsersModule, ValidationError, type WebhookSchema, type WebhookTopic, WebhooksModule };
560
+ export { type ApiStatus, type ApiWrapper, type AttributionRequest, type AuthCodeTokenResponse, type AuthMode, AuthModule, AuthenticationError, type AuthorizationUrlParams, type ClientHookRequest, type ClubMembership, type ClubMembershipResponse, ClubsModule, type CreateEventRequestV1, type CreateEventResponseV1, type CreateProvisionalRatingRequest, type DeleteEventRequestV1, type DeleteEventResponseV1, type DeleteProvisionalRatingRequest, DuprApiError, DuprClient, type DuprClientOptions, EventsModule, type ExtendedUserInfo, type ExternalAgeRangeFilter, type ExternalBatchUserDetailRequest, type ExternalClubMatchSearchRequest, type ExternalClubMemberRequest, type ExternalDeleteMatchRequest, type ExternalFilterLocation, type ExternalInviteRequest, type ExternalMatchPlayer, 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 MatchFormat, type MatchResponse, type MatchSource, 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
@@ -15,6 +15,9 @@ function resolveConfig(opts) {
15
15
  };
16
16
  if (opts.onRequest) cfg.onRequest = opts.onRequest;
17
17
  if (opts.onResponse) cfg.onResponse = opts.onResponse;
18
+ if (opts.ssoBaseUrl) cfg.ssoBaseUrl = opts.ssoBaseUrl;
19
+ if (opts.ssoRefreshBaseUrl) cfg.ssoRefreshBaseUrl = opts.ssoRefreshBaseUrl;
20
+ if (opts.authorizationUrl) cfg.authorizationUrl = opts.authorizationUrl;
18
21
  return cfg;
19
22
  }
20
23
 
@@ -269,13 +272,12 @@ var AuthModule = class {
269
272
  * The `authorizationUrl` config option must be set (see above note).
270
273
  */
271
274
  getAuthorizationUrl(params) {
272
- const authUrl = this.config.authorizationUrl;
273
- if (!authUrl) {
275
+ if (!this.config.authorizationUrl) {
274
276
  throw new Error(
275
277
  "authorizationUrl is not configured. Pass it in DuprClientOptions to use the Authorization Code flow."
276
278
  );
277
279
  }
278
- const url = new URL(authUrl);
280
+ const url = new URL(this.config.authorizationUrl);
279
281
  const clientId = this.config.auth.type === "clientCredentials" ? this.config.auth.clientKey : "";
280
282
  url.searchParams.set("response_type", "code");
281
283
  url.searchParams.set("client_id", clientId);
@@ -320,6 +322,95 @@ var AuthModule = class {
320
322
  }
321
323
  return res.json();
322
324
  }
325
+ // ── SSO Iframe Flow ───────────────────────────────────────────────────────
326
+ //
327
+ // DUPR's documented SSO approach for user-facing login uses an embedded iframe
328
+ // rather than a standard OAuth2 redirect. The iframe emits a window.postMessage
329
+ // event upon successful login.
330
+ //
331
+ // Typical flow:
332
+ // 1. client.auth.getSsoIframeUrl() → embed in <iframe allow="payment">
333
+ // 2. User logs in inside the iframe
334
+ // 3. Listen for window.postMessage → { userToken, refreshToken, id, duprId, stats }
335
+ // 4. Store userToken + refreshToken server-side; record tokenExpiresAt
336
+ // (7 days UAT / 30 days prod — not returned in the event, apply based on env)
337
+ // 5. When userToken nears expiry: client.auth.refreshSsoToken(refreshToken)
338
+ // DUPR rotates refresh tokens — store both returned tokens.
339
+ //
340
+ // UAT iframe host: https://uat.dupr.gg
341
+ // Prod iframe host: https://dashboard.dupr.com
342
+ // Always validate window.postMessage origin against the expected host.
343
+ /**
344
+ * Returns the DUPR SSO iframe URL. Embed this in an `<iframe allow="payment">` to
345
+ * display the DUPR login widget. Requires `ssoBaseUrl` in `DuprClientOptions`.
346
+ */
347
+ getSsoIframeUrl() {
348
+ if (!this.config.ssoBaseUrl) {
349
+ throw new Error(
350
+ "ssoBaseUrl is not configured. Pass it in DuprClientOptions to use the SSO iframe flow."
351
+ );
352
+ }
353
+ if (this.config.auth.type !== "clientCredentials") {
354
+ throw new AuthenticationError(
355
+ "getSsoIframeUrl() requires clientCredentials auth mode",
356
+ 401
357
+ );
358
+ }
359
+ const encoded = Buffer.from(this.config.auth.clientKey).toString("base64");
360
+ return `${this.config.ssoBaseUrl}/login-external-app/${encoded}`;
361
+ }
362
+ /**
363
+ * Refresh a DUPR SSO user token obtained from the iframe login `postMessage` event.
364
+ * Uses a separate refresh endpoint on `ssoRefreshBaseUrl` (distinct from the Partner API).
365
+ * Requires `ssoRefreshBaseUrl` in `DuprClientOptions`.
366
+ *
367
+ * DUPR rotates refresh tokens on every use — always store both `accessToken` and
368
+ * `refreshToken` from the response.
369
+ */
370
+ async refreshSsoToken(refreshToken) {
371
+ if (!this.config.ssoRefreshBaseUrl) {
372
+ throw new Error(
373
+ "ssoRefreshBaseUrl is not configured. Pass it in DuprClientOptions to use SSO token refresh."
374
+ );
375
+ }
376
+ const res = await this.config.customFetch(
377
+ `${this.config.ssoRefreshBaseUrl}/api/auth/refreshAccessToken`,
378
+ {
379
+ method: "POST",
380
+ headers: {
381
+ "Content-Type": "application/json",
382
+ "User-Agent": this.config.userAgent
383
+ },
384
+ body: JSON.stringify({ refreshToken }),
385
+ signal: AbortSignal.timeout(this.config.timeoutMs)
386
+ }
387
+ );
388
+ if (!res.ok) {
389
+ const errBody = await res.json().catch(() => void 0);
390
+ throw new AuthenticationError(
391
+ errBody?.["message"] ?? `SSO token refresh failed: ${res.status}`,
392
+ res.status,
393
+ errBody
394
+ );
395
+ }
396
+ const data = await res.json();
397
+ const accessToken = data["accessToken"] ?? data["userToken"];
398
+ const newRefreshToken = data["refreshToken"];
399
+ if (!accessToken) {
400
+ throw new AuthenticationError("SSO token refresh response missing accessToken", 502);
401
+ }
402
+ if (!newRefreshToken) {
403
+ throw new AuthenticationError(
404
+ "SSO token refresh response missing refreshToken \u2014 DUPR token rotation failed",
405
+ 502
406
+ );
407
+ }
408
+ return {
409
+ accessToken,
410
+ refreshToken: newRefreshToken,
411
+ ...data["expiresIn"] !== void 0 && { expiresIn: data["expiresIn"] }
412
+ };
413
+ }
323
414
  /**
324
415
  * Obtain a new access token using a refresh token from a previous Authorization Code flow.
325
416
  * Uses `POST /auth/{version}/token` with `grant_type=refresh_token`.
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\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nfunction retryDelayMs(attempt: number, baseDelayMs: number, maxDelayMs: number): number {\r\n // Exponential backoff with ±20% jitter to avoid thundering herd\r\n const exp = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);\r\n return exp * (0.8 + Math.random() * 0.4);\r\n}\r\n\r\nfunction isRetryable(err: unknown): boolean {\r\n if (err instanceof RateLimitError) return true;\r\n if (err instanceof ServerError) return true;\r\n // Network-level failures (fetch throws a TypeError on connection refused etc.)\r\n if (err instanceof TypeError) return true;\r\n return false;\r\n}\r\n\r\nexport class HttpClient {\r\n private token: string | null = null;\r\n private tokenExpiresAt = 0;\r\n\r\n constructor(private readonly config: ResolvedConfig) {}\r\n\r\n private async getBearerToken(): Promise<string> {\r\n if (this.config.overrideBearerToken) {\r\n return this.config.overrideBearerToken;\r\n }\r\n if (this.config.auth.type === \"staticBearer\") {\r\n return this.config.auth.bearerToken;\r\n }\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"No auth configured — set auth in DuprClientOptions or call setBearerToken()\", 401);\r\n }\r\n\r\n if (this.token && Date.now() < this.tokenExpiresAt) {\r\n return this.token;\r\n }\r\n\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const encoded = Buffer.from(`${clientKey}:${clientSecret}`).toString(\"base64\");\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n\r\n const start = Date.now();\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"x-authorization\": encoded,\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n this.config.onResponse?.({ status: res.status, url, durationMs: Date.now() - start });\r\n\r\n if (!res.ok) throw await buildError(res);\r\n\r\n const body = await res.json() as { token?: string; accessToken?: string; expiresIn?: number };\r\n this.token = body.token ?? body.accessToken ?? null;\r\n if (!this.token) throw new AuthenticationError(\"Token response contained no token\", 401);\r\n\r\n const ttlSec = body.expiresIn ?? 3600;\r\n this.tokenExpiresAt = Date.now() + (ttlSec - 60) * 1000;\r\n return this.token;\r\n }\r\n\r\n async get<T>(path: string, init?: RequestInit): Promise<T> {\r\n return this.request<T>(\"GET\", path, init);\r\n }\r\n\r\n async post<T>(path: string, body?: unknown, init?: RequestInit): Promise<T> {\r\n const extra: RequestInit = { headers: { \"Content-Type\": \"application/json\", ...(init?.headers ?? {}) } };\r\n if (body !== undefined) extra.body = JSON.stringify(body);\r\n return this.request<T>(\"POST\", path, { ...init, ...extra });\r\n }\r\n\r\n async delete<T>(path: string, body?: unknown, init?: RequestInit): Promise<T> {\r\n const extra: RequestInit = { headers: { \"Content-Type\": \"application/json\", ...(init?.headers ?? {}) } };\r\n if (body !== undefined) extra.body = JSON.stringify(body);\r\n return this.request<T>(\"DELETE\", path, { ...init, ...extra });\r\n }\r\n\r\n async request<T>(method: string, path: string, init?: RequestInit): Promise<T> {\r\n const retryCfg = this.config.retry;\r\n const maxAttempts = retryCfg === false ? 1 : retryCfg.maxRetries + 1;\r\n\r\n let lastErr: unknown;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n return await this.rawRequest<T>(method, path, init);\r\n } catch (err) {\r\n lastErr = err;\r\n\r\n if (attempt >= maxAttempts - 1) break;\r\n if (!isRetryable(err)) break;\r\n if (retryCfg === false) break;\r\n\r\n let delay: number;\r\n if (err instanceof RateLimitError) {\r\n // Honor Retry-After header (value in seconds)\r\n const retryAfterSec =\r\n err.details !== null &&\r\n typeof err.details === \"object\" &&\r\n \"retryAfterSeconds\" in (err.details as object)\r\n ? Number((err.details as { retryAfterSeconds: unknown }).retryAfterSeconds)\r\n : NaN;\r\n delay = Number.isFinite(retryAfterSec) && retryAfterSec > 0\r\n ? retryAfterSec * 1000\r\n : retryDelayMs(attempt, retryCfg.baseDelayMs, retryCfg.maxDelayMs);\r\n } else {\r\n delay = retryDelayMs(attempt, retryCfg.baseDelayMs, retryCfg.maxDelayMs);\r\n }\r\n\r\n await sleep(delay);\r\n }\r\n }\r\n\r\n throw lastErr;\r\n }\r\n\r\n private async rawRequest<T>(method: string, path: string, init?: RequestInit): Promise<T> {\r\n const token = await this.getBearerToken();\r\n const url = `${this.config.baseUrl}${path}`;\r\n\r\n const headers: Record<string, string> = {\r\n Authorization: `Bearer ${token}`,\r\n \"User-Agent\": this.config.userAgent,\r\n ...(init?.headers as Record<string, string> | undefined ?? {}),\r\n };\r\n\r\n this.config.onRequest?.({ method, url, headers });\r\n\r\n const start = Date.now();\r\n const res = await this.config.customFetch(url, {\r\n method,\r\n ...init,\r\n headers,\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n this.config.onResponse?.({ status: res.status, url, durationMs: Date.now() - start });\r\n\r\n if (!res.ok) {\r\n const err = await buildError(res);\r\n // Attach Retry-After from the response header so the retry loop can read it\r\n if (err instanceof RateLimitError) {\r\n const retryAfter = res.headers.get(\"Retry-After\");\r\n if (retryAfter) {\r\n (err as RateLimitError & { details: unknown }).details =\r\n typeof err.details === \"object\" && err.details !== null\r\n ? { ...err.details as object, retryAfterSeconds: Number(retryAfter) }\r\n : { retryAfterSeconds: Number(retryAfter) };\r\n }\r\n }\r\n throw err;\r\n }\r\n\r\n // Some endpoints return 204 No Content\r\n if (res.status === 204 || res.headers.get(\"content-length\") === \"0\") {\r\n return undefined as T;\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n }\r\n}\r\n","import { HttpClient } from \"./http.js\";\r\nimport { ResolvedConfig } from \"./config.js\";\r\nimport { AuthenticationError } from \"./errors.js\";\r\nimport { TokenResponse } from \"./types.js\";\r\n\r\nexport interface AuthCodeTokenResponse extends TokenResponse {\r\n refresh_token?: string;\r\n token_type?: string;\r\n scope?: string;\r\n}\r\n\r\n/** Response from `client.auth.refreshSsoToken()`. Both tokens are always present — DUPR rotates refresh tokens on every use. */\r\nexport interface SsoTokenResponse {\r\n accessToken: string;\r\n refreshToken: string;\r\n /** Seconds until the access token expires, if provided by DUPR. */\r\n expiresIn?: number;\r\n}\r\n\r\nexport interface AuthorizationUrlParams {\r\n /** Your OAuth redirect URI, must match what is registered with DUPR. */\r\n redirectUri: string;\r\n /** OAuth scopes to request (e.g. [\"user.read\"]). Defaults to empty. */\r\n scopes?: string[];\r\n /** Opaque value passed through the flow to prevent CSRF. Recommended. */\r\n state?: string;\r\n}\r\n\r\nexport class AuthModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly config: ResolvedConfig,\r\n ) {}\r\n\r\n /**\r\n * Explicitly request a new access token using client credentials.\r\n * Normally you don't need to call this — the HTTP client handles token refresh automatically.\r\n */\r\n async getToken(): Promise<TokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"getToken() requires clientCredentials auth mode\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const encoded = Buffer.from(`${clientKey}:${clientSecret}`).toString(\"base64\");\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"x-authorization\": encoded,\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const body = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (body?.[\"message\"] as string | undefined) ?? `Auth failed: ${res.status}`,\r\n res.status,\r\n body,\r\n );\r\n }\r\n\r\n return res.json() as Promise<TokenResponse>;\r\n }\r\n\r\n // ── Authorization Code Flow ───────────────────────────────────────────────\r\n //\r\n // Use this flow to let end-users authorise your app to act on their behalf\r\n // (e.g. the \"Connect DUPR\" button). The user is redirected to DUPR's login\r\n // page, then back to your redirectUri with an authorization code.\r\n //\r\n // NOTE: This requires a DUPR OAuth application with an authorization endpoint\r\n // separate from the Partner API client credentials. Confirm the exact\r\n // authorization URL with DUPR support.\r\n //\r\n // Typical flow:\r\n // 1. client.auth.getAuthorizationUrl({ redirectUri, state }) → redirect user\r\n // 2. User approves → DUPR calls back to redirectUri?code=xxx&state=yyy\r\n // 3. client.auth.exchangeCode({ code, redirectUri }) → tokens\r\n // 4. Store access_token + refresh_token; call client.setBearerToken(access_token)\r\n // 5. When access_token expires: client.auth.refreshToken(refresh_token)\r\n\r\n /**\r\n * Build the DUPR authorization URL to redirect the user to for login.\r\n * The `authorizationUrl` config option must be set (see above note).\r\n */\r\n getAuthorizationUrl(params: AuthorizationUrlParams): string {\r\n if (!this.config.authorizationUrl) {\r\n throw new Error(\r\n \"authorizationUrl is not configured. Pass it in DuprClientOptions to use the Authorization Code flow.\",\r\n );\r\n }\r\n const url = new URL(this.config.authorizationUrl);\r\n const clientId = this.config.auth.type === \"clientCredentials\" ? this.config.auth.clientKey : \"\";\r\n url.searchParams.set(\"response_type\", \"code\");\r\n url.searchParams.set(\"client_id\", clientId);\r\n url.searchParams.set(\"redirect_uri\", params.redirectUri);\r\n if (params.scopes?.length) url.searchParams.set(\"scope\", params.scopes.join(\" \"));\r\n if (params.state) url.searchParams.set(\"state\", params.state);\r\n return url.toString();\r\n }\r\n\r\n /**\r\n * Exchange an authorization code (from the OAuth callback) for access + refresh tokens.\r\n * Uses `POST /auth/{version}/token` with `grant_type=authorization_code`.\r\n */\r\n async exchangeCode(params: {\r\n code: string;\r\n redirectUri: string;\r\n }): Promise<AuthCodeTokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"exchangeCode() requires clientCredentials auth configured with clientKey/clientSecret\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n const body = new URLSearchParams({\r\n grant_type: \"authorization_code\",\r\n code: params.code,\r\n redirect_uri: params.redirectUri,\r\n client_id: clientKey,\r\n client_secret: clientSecret,\r\n });\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: body.toString(),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `Code exchange failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n return res.json() as Promise<AuthCodeTokenResponse>;\r\n }\r\n\r\n // ── SSO Iframe Flow ───────────────────────────────────────────────────────\r\n //\r\n // DUPR's documented SSO approach for user-facing login uses an embedded iframe\r\n // rather than a standard OAuth2 redirect. The iframe emits a window.postMessage\r\n // event upon successful login.\r\n //\r\n // Typical flow:\r\n // 1. client.auth.getSsoIframeUrl() → embed in <iframe allow=\"payment\">\r\n // 2. User logs in inside the iframe\r\n // 3. Listen for window.postMessage → { userToken, refreshToken, id, duprId, stats }\r\n // 4. Store userToken + refreshToken server-side; record tokenExpiresAt\r\n // (7 days UAT / 30 days prod — not returned in the event, apply based on env)\r\n // 5. When userToken nears expiry: client.auth.refreshSsoToken(refreshToken)\r\n // DUPR rotates refresh tokens — store both returned tokens.\r\n //\r\n // UAT iframe host: https://uat.dupr.gg\r\n // Prod iframe host: https://dashboard.dupr.com\r\n // Always validate window.postMessage origin against the expected host.\r\n\r\n /**\r\n * Returns the DUPR SSO iframe URL. Embed this in an `<iframe allow=\"payment\">` to\r\n * display the DUPR login widget. Requires `ssoBaseUrl` in `DuprClientOptions`.\r\n */\r\n getSsoIframeUrl(): string {\r\n if (!this.config.ssoBaseUrl) {\r\n throw new Error(\r\n \"ssoBaseUrl is not configured. Pass it in DuprClientOptions to use the SSO iframe flow.\",\r\n );\r\n }\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\r\n \"getSsoIframeUrl() requires clientCredentials auth mode\",\r\n 401,\r\n );\r\n }\r\n const encoded = Buffer.from(this.config.auth.clientKey).toString(\"base64\");\r\n return `${this.config.ssoBaseUrl}/login-external-app/${encoded}`;\r\n }\r\n\r\n /**\r\n * Refresh a DUPR SSO user token obtained from the iframe login `postMessage` event.\r\n * Uses a separate refresh endpoint on `ssoRefreshBaseUrl` (distinct from the Partner API).\r\n * Requires `ssoRefreshBaseUrl` in `DuprClientOptions`.\r\n *\r\n * DUPR rotates refresh tokens on every use — always store both `accessToken` and\r\n * `refreshToken` from the response.\r\n */\r\n async refreshSsoToken(refreshToken: string): Promise<SsoTokenResponse> {\r\n if (!this.config.ssoRefreshBaseUrl) {\r\n throw new Error(\r\n \"ssoRefreshBaseUrl is not configured. Pass it in DuprClientOptions to use SSO token refresh.\",\r\n );\r\n }\r\n const res = await this.config.customFetch(\r\n `${this.config.ssoRefreshBaseUrl}/api/auth/refreshAccessToken`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: JSON.stringify({ refreshToken }),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n },\r\n );\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `SSO token refresh failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n const data = await res.json() as Record<string, unknown>;\r\n const accessToken = (data[\"accessToken\"] ?? data[\"userToken\"]) as string | undefined;\r\n const newRefreshToken = data[\"refreshToken\"] as string | undefined;\r\n\r\n if (!accessToken) {\r\n throw new AuthenticationError(\"SSO token refresh response missing accessToken\", 502);\r\n }\r\n if (!newRefreshToken) {\r\n throw new AuthenticationError(\r\n \"SSO token refresh response missing refreshToken — DUPR token rotation failed\",\r\n 502,\r\n );\r\n }\r\n\r\n return {\r\n accessToken,\r\n refreshToken: newRefreshToken,\r\n ...(data[\"expiresIn\"] !== undefined && { expiresIn: data[\"expiresIn\"] as number }),\r\n };\r\n }\r\n\r\n /**\r\n * Obtain a new access token using a refresh token from a previous Authorization Code flow.\r\n * Uses `POST /auth/{version}/token` with `grant_type=refresh_token`.\r\n */\r\n async refreshToken(refreshToken: string): Promise<AuthCodeTokenResponse> {\r\n if (this.config.auth.type !== \"clientCredentials\") {\r\n throw new AuthenticationError(\"refreshToken() requires clientCredentials auth configured\", 401);\r\n }\r\n const { clientKey, clientSecret } = this.config.auth;\r\n const url = `${this.config.baseUrl}/auth/${this.config.version}/token`;\r\n const body = new URLSearchParams({\r\n grant_type: \"refresh_token\",\r\n refresh_token: refreshToken,\r\n client_id: clientKey,\r\n client_secret: clientSecret,\r\n });\r\n\r\n const res = await this.config.customFetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n \"User-Agent\": this.config.userAgent,\r\n },\r\n body: body.toString(),\r\n signal: AbortSignal.timeout(this.config.timeoutMs),\r\n });\r\n\r\n if (!res.ok) {\r\n const errBody = await res.json().catch(() => undefined) as Record<string, unknown> | undefined;\r\n throw new AuthenticationError(\r\n (errBody?.[\"message\"] as string | undefined) ?? `Token refresh failed: ${res.status}`,\r\n res.status,\r\n errBody,\r\n );\r\n }\r\n\r\n return res.json() as Promise<AuthCodeTokenResponse>;\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ClubMembershipResponse,\r\n CreateProvisionalRatingRequest,\r\n DeleteProvisionalRatingRequest,\r\n ExtendedUserInfo,\r\n ExternalBatchUserDetailRequest,\r\n ExternalInviteRequest,\r\n ExternalSearchRequest,\r\n GetProvisionalRatingRequest,\r\n GrantExternalSubscriptionRequest,\r\n UpdateProvisionalRatingRequest,\r\n UserInfo,\r\n} from \"../types.js\";\r\n\r\nexport class UsersModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** GET /user/{version}/{id} — basic player profile */\r\n getUser(duprId: string): Promise<ApiWrapper<UserInfo>> {\r\n return this.http.get(`/user/${this.cfg.version}/${duprId}`);\r\n }\r\n\r\n /** GET /user/{version}/{id}/details — extended profile (requires USER_EMAIL::VIEW permission) */\r\n getExtendedUser(duprId: string): Promise<ApiWrapper<ExtendedUserInfo>> {\r\n return this.http.get(`/user/${this.cfg.version}/${duprId}/details`);\r\n }\r\n\r\n /** GET /user/{version}/{id}/clubs — club memberships for a player */\r\n getClubMemberships(duprId: string): Promise<ClubMembershipResponse> {\r\n return this.http.get(`/user/${this.cfg.version}/${duprId}/clubs`);\r\n }\r\n\r\n /** POST /user/{version}/search — full-text player search with optional filters */\r\n search(req: ExternalSearchRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/user/${this.cfg.version}/search`, req);\r\n }\r\n\r\n /** POST /user/{version}/batch — fetch multiple players by DUPR ID in one request */\r\n getBatch(req: ExternalBatchUserDetailRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/user/${this.cfg.version}/batch`, req);\r\n }\r\n\r\n /** POST /user/{version}/invite — pre-generate a DUPR ID and send an invite email */\r\n invite(req: ExternalInviteRequest): Promise<ApiWrapper<{ duprId: string }>> {\r\n return this.http.post(`/user/${this.cfg.version}/invite`, req);\r\n }\r\n\r\n /** POST /user/{version}/subscription/grants — grant a subscription to a user */\r\n grantSubscription(req: GrantExternalSubscriptionRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/subscription/grants`, req);\r\n }\r\n\r\n // ── Provisional ratings ──────────────────────────────────────\r\n\r\n /** POST /user/{version}/provisional_rating — get provisional ratings for a player */\r\n getProvisionalRating(req: GetProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating`, req);\r\n }\r\n\r\n /** POST /user/{version}/provisional_rating/create */\r\n createProvisionalRating(req: CreateProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating/create`, req);\r\n }\r\n\r\n /** POST /user/{version}/provisional_rating/update */\r\n updateProvisionalRating(req: UpdateProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/provisional_rating/update`, req);\r\n }\r\n\r\n /** DELETE /user/{version}/provisional_rating/delete */\r\n deleteProvisionalRating(req: DeleteProvisionalRatingRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/user/${this.cfg.version}/provisional_rating/delete`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper } from \"../types.js\";\r\n\r\nexport interface GetDuprIdByEmailRequest {\r\n email: string;\r\n}\r\n\r\nexport interface DuprIdByEmailResponse {\r\n duprId?: string;\r\n}\r\n\r\nexport class PlayersModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /{version}/player/duprid-by-email — resolve a DUPR ID from an email address */\r\n getDuprIdByEmail(req: GetDuprIdByEmailRequest): Promise<ApiWrapper<DuprIdByEmailResponse>> {\r\n return this.http.post(`/${this.cfg.version}/player/duprid-by-email`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper, PlayerRatingSubscribeRequest } from \"../types.js\";\r\n\r\nexport interface PlayerRatingHistoryRequest {\r\n duprId: string;\r\n offset?: number;\r\n limit?: number;\r\n}\r\n\r\nexport interface PlayerRatingHistoryEntry {\r\n date?: string;\r\n singlesRating?: number;\r\n doublesRating?: number;\r\n}\r\n\r\nexport class PlayerRatingModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /history — get rating history for a player */\r\n getHistory(req: PlayerRatingHistoryRequest): Promise<ApiWrapper<PlayerRatingHistoryEntry[]>> {\r\n return this.http.post(`/history`, req);\r\n }\r\n\r\n /** GET /{version}/subscribe/rating-changes — list currently subscribed DUPR IDs */\r\n getSubscriptions(): Promise<ApiWrapper<{ duprIds: string[] }>> {\r\n return this.http.get(`/${this.cfg.version}/subscribe/rating-changes`);\r\n }\r\n\r\n /** POST /{version}/subscribe/rating-changes — subscribe to rating-change events for a list of players */\r\n subscribe(req: PlayerRatingSubscribeRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/${this.cfg.version}/subscribe/rating-changes`, req);\r\n }\r\n\r\n /** DELETE /{version}/subscribe/rating-changes — unsubscribe from rating-change events */\r\n unsubscribe(req: PlayerRatingSubscribeRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/${this.cfg.version}/subscribe/rating-changes`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ExternalDeleteMatchRequest,\r\n ExternalMatchRequest,\r\n ExternalMatchSearchRequest,\r\n ExternalUpdateMatchRequest,\r\n MatchResponse,\r\n} from \"../types.js\";\r\n\r\nexport interface AnnotateMatchRequest {\r\n matchId: string;\r\n annotation: Record<string, unknown>;\r\n}\r\n\r\nexport class MatchesModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** GET /match/{version}/{id} — view a single match */\r\n get(matchId: string): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.get(`/match/${this.cfg.version}/${matchId}`);\r\n }\r\n\r\n /** POST /match/{version}/create — submit a new match result */\r\n create(match: ExternalMatchRequest): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.post(`/match/${this.cfg.version}/create`, match);\r\n }\r\n\r\n /** POST /match/{version}/batch — submit multiple match results in one call */\r\n createBulk(matches: ExternalMatchRequest[]): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/match/${this.cfg.version}/batch`, matches);\r\n }\r\n\r\n /** POST /match/{version}/update — update an existing match */\r\n update(req: ExternalUpdateMatchRequest): Promise<ApiWrapper<MatchResponse>> {\r\n return this.http.post(`/match/${this.cfg.version}/update`, req);\r\n }\r\n\r\n /** DELETE /match/{version}/delete — delete a match */\r\n delete(req: ExternalDeleteMatchRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/match/${this.cfg.version}/delete`, req);\r\n }\r\n\r\n /** POST /match/{version}/annotate — attach vendor-specific metadata to a match */\r\n annotate(req: AnnotateMatchRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/match/${this.cfg.version}/annotate`, req);\r\n }\r\n\r\n /** DELETE /match/{version}/annotate/{matchId} — remove a match annotation */\r\n deleteAnnotation(matchId: string): Promise<ApiWrapper> {\r\n return this.http.delete(`/match/${this.cfg.version}/annotate/${matchId}`);\r\n }\r\n\r\n /** POST /match/history/search — search a player's match history */\r\n searchHistory(req: ExternalMatchSearchRequest): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/match/history/search`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n ExternalClubMemberRequest,\r\n ExternalClubMatchSearchRequest,\r\n MatchResponse,\r\n UserInfo,\r\n} from \"../types.js\";\r\n\r\nexport class ClubsModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /club/{version}/members — get ratings for all members of a club */\r\n membersRating(req: ExternalClubMemberRequest): Promise<ApiWrapper<UserInfo[]>> {\r\n return this.http.post(`/club/${this.cfg.version}/members`, req);\r\n }\r\n\r\n /** POST /club/{version}/match/search — search matches associated with a club */\r\n searchMatches(req: ExternalClubMatchSearchRequest): Promise<ApiWrapper<MatchResponse[]>> {\r\n return this.http.post(`/club/${this.cfg.version}/match/search`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport {\r\n ApiWrapper,\r\n CreateEventRequestV1,\r\n CreateEventResponseV1,\r\n DeleteEventRequestV1,\r\n DeleteEventResponseV1,\r\n GetEventRequestV1,\r\n GetEventResponseV1,\r\n UpdateEventRequestV1,\r\n UpdateEventResponseV1,\r\n} from \"../types.js\";\r\n\r\nexport class EventsModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /events/{version}/create */\r\n create(req: CreateEventRequestV1): Promise<ApiWrapper<CreateEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/create`, req);\r\n }\r\n\r\n /** GET /events/{version}/get */\r\n get(req: GetEventRequestV1): Promise<ApiWrapper<GetEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/get`, req);\r\n }\r\n\r\n /** POST /events/{version}/update */\r\n update(req: UpdateEventRequestV1): Promise<ApiWrapper<UpdateEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/update`, req);\r\n }\r\n\r\n /** POST /events/{version}/delete */\r\n delete(req: DeleteEventRequestV1): Promise<ApiWrapper<DeleteEventResponseV1>> {\r\n return this.http.post(`/events/${this.cfg.version}/delete`, req);\r\n }\r\n}\r\n","import { HttpClient } from \"../http.js\";\r\nimport { ResolvedConfig } from \"../config.js\";\r\nimport { ApiWrapper, ClientHookRequest, UserWebhookRequest, WebhookSchema } from \"../types.js\";\r\n\r\nexport class WebhooksModule {\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly cfg: ResolvedConfig,\r\n ) {}\r\n\r\n /** POST /{version}/webhook — register a webhook endpoint */\r\n register(req: ClientHookRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/${this.cfg.version}/webhook`, req);\r\n }\r\n\r\n /** GET /{version}/topic — list all available webhook topics */\r\n getTopics(): Promise<ApiWrapper<string[]>> {\r\n return this.http.get(`/${this.cfg.version}/topic`);\r\n }\r\n\r\n /** GET /{version}/webhook/schema — list available webhook schemas */\r\n listSchemas(): Promise<ApiWrapper<WebhookSchema[]>> {\r\n return this.http.get(`/${this.cfg.version}/webhook/schema`);\r\n }\r\n\r\n /** GET /{version}/webhook/schema/{topic} — get the JSON schema for a specific topic */\r\n getSchema(topic: string): Promise<ApiWrapper<WebhookSchema>> {\r\n return this.http.get(`/${this.cfg.version}/webhook/schema/${topic}`);\r\n }\r\n\r\n /** POST /user/{version}/subscribe/webhook-event — subscribe specific users to a webhook topic */\r\n subscribeUsers(req: UserWebhookRequest): Promise<ApiWrapper> {\r\n return this.http.post(`/user/${this.cfg.version}/subscribe/webhook-event`, req);\r\n }\r\n\r\n /** DELETE /user/{version}/subscribe/webhook-event — unsubscribe specific users from a webhook topic */\r\n unsubscribeUsers(req: UserWebhookRequest): Promise<ApiWrapper> {\r\n return this.http.delete(`/user/${this.cfg.version}/subscribe/webhook-event`, req);\r\n }\r\n}\r\n","import { DuprClientOptions, ResolvedConfig, resolveConfig } from \"./config.js\";\r\nimport { HttpClient } from \"./http.js\";\r\nimport { AuthModule } from \"./auth.js\";\r\nimport { UsersModule } from \"./resources/users.js\";\r\nimport { PlayersModule } from \"./resources/players.js\";\r\nimport { PlayerRatingModule } from \"./resources/playerRating.js\";\r\nimport { MatchesModule } from \"./resources/matches.js\";\r\nimport { ClubsModule } from \"./resources/clubs.js\";\r\nimport { EventsModule } from \"./resources/events.js\";\r\nimport { WebhooksModule } from \"./resources/webhooks.js\";\r\n\r\nexport class DuprClient {\r\n readonly config: ResolvedConfig;\r\n readonly auth: AuthModule;\r\n readonly users: UsersModule;\r\n readonly players: PlayersModule;\r\n readonly playerRating: PlayerRatingModule;\r\n readonly matches: MatchesModule;\r\n readonly clubs: ClubsModule;\r\n readonly events: EventsModule;\r\n readonly webhooks: WebhooksModule;\r\n\r\n constructor(opts: DuprClientOptions = {}) {\r\n this.config = resolveConfig(opts);\r\n const http = new HttpClient(this.config);\r\n this.auth = new AuthModule(http, this.config);\r\n this.users = new UsersModule(http, this.config);\r\n this.players = new PlayersModule(http, this.config);\r\n this.playerRating = new PlayerRatingModule(http, this.config);\r\n this.matches = new MatchesModule(http, this.config);\r\n this.clubs = new ClubsModule(http, this.config);\r\n this.events = new EventsModule(http, this.config);\r\n this.webhooks = new WebhooksModule(http, this.config);\r\n }\r\n\r\n /** Override the bearer token at runtime — useful when your backend handles auth separately. */\r\n setBearerToken(token: string): void {\r\n this.config.overrideBearerToken = token;\r\n }\r\n\r\n /** Clear the runtime bearer token override and fall back to configured auth. */\r\n clearBearerToken(): void {\r\n delete this.config.overrideBearerToken;\r\n }\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dupr-js-client",
3
- "version": "0.1.3",
3
+ "version": "1.0.1",
4
4
  "description": "A comprehensive TypeScript/JavaScript client for the DUPR (Dynamic Universal Pickleball Rating) API.",
5
5
  "license": "MIT",
6
6
  "author": "Sunny Tambi",