@pulseid/client 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-BRQ2T53Z.js → chunk-GAMIRD7Y.js} +35 -2
- package/dist/chunk-GAMIRD7Y.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +1 -1
- package/dist/server.d.ts +12 -1
- package/dist/server.js +9 -2
- package/dist/server.js.map +1 -1
- package/package.json +18 -19
- package/dist/chunk-BRQ2T53Z.js.map +0 -1
|
@@ -308,6 +308,39 @@ var PulseIdClient = class {
|
|
|
308
308
|
});
|
|
309
309
|
}
|
|
310
310
|
// ===========================================================================
|
|
311
|
+
// EMAIL VERIFICATION
|
|
312
|
+
// ===========================================================================
|
|
313
|
+
/**
|
|
314
|
+
* Resend the email verification link.
|
|
315
|
+
*
|
|
316
|
+
* Requires the `email` scope. Will fail if email is already verified.
|
|
317
|
+
*
|
|
318
|
+
* @param accessToken - A valid access token with `email` scope
|
|
319
|
+
* @returns Success confirmation
|
|
320
|
+
* @throws {PulseIdError} If email is already verified or request fails
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* ```typescript
|
|
324
|
+
* try {
|
|
325
|
+
* await client.resendVerificationEmail(accessToken);
|
|
326
|
+
* console.log('Verification email sent!');
|
|
327
|
+
* } catch (error) {
|
|
328
|
+
* if (error.code === 'invalid_request') {
|
|
329
|
+
* console.log('Email already verified');
|
|
330
|
+
* }
|
|
331
|
+
* }
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
async resendVerificationEmail(accessToken) {
|
|
335
|
+
return this.http.post(
|
|
336
|
+
"/api/v1/me/resend-verification",
|
|
337
|
+
{},
|
|
338
|
+
{
|
|
339
|
+
Authorization: `Bearer ${accessToken}`
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
// ===========================================================================
|
|
311
344
|
// UTILITY METHODS
|
|
312
345
|
// ===========================================================================
|
|
313
346
|
/**
|
|
@@ -402,5 +435,5 @@ var PulseIdClient = class {
|
|
|
402
435
|
};
|
|
403
436
|
|
|
404
437
|
export { InsufficientScopeError, InvalidTokenError, NetworkError, NotFoundError, PulseIdClient, PulseIdError, TimeoutError };
|
|
405
|
-
//# sourceMappingURL=chunk-
|
|
406
|
-
//# sourceMappingURL=chunk-
|
|
438
|
+
//# sourceMappingURL=chunk-GAMIRD7Y.js.map
|
|
439
|
+
//# sourceMappingURL=chunk-GAMIRD7Y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/client.ts"],"names":[],"mappings":"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","file":"chunk-GAMIRD7Y.js","sourcesContent":["/**\n * PULSE ID SDK Errors\n *\n * Custom error classes for better error handling.\n */\n\nimport type { ApiErrorResponse, ErrorCode } from './types.js';\n\n/**\n * Base error class for PULSE ID SDK errors.\n */\nexport class PulseIdError extends Error {\n readonly code: ErrorCode;\n readonly statusCode: number;\n\n constructor(code: ErrorCode, message: string, statusCode = 400) {\n super(message);\n this.name = 'PulseIdError';\n this.code = code;\n this.statusCode = statusCode;\n\n // Maintains proper stack trace in V8 environments\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, PulseIdError);\n }\n }\n\n /**\n * Create an error from an API response.\n */\n static fromResponse(response: ApiErrorResponse, statusCode: number): PulseIdError {\n const code = mapErrorCode(response.error);\n\n switch (code) {\n case 'invalid_token':\n case 'expired_token':\n return new InvalidTokenError(response.error_description);\n case 'insufficient_scope':\n return new InsufficientScopeError(\n response.error_description,\n response.required_scope\n );\n case 'not_found':\n return new NotFoundError(response.error_description);\n default:\n return new PulseIdError(code, response.error_description, statusCode);\n }\n }\n}\n\n/**\n * Error thrown when the access token is invalid or expired.\n */\nexport class InvalidTokenError extends PulseIdError {\n constructor(message = 'Invalid or expired access token') {\n super('invalid_token', message, 401);\n this.name = 'InvalidTokenError';\n }\n}\n\n/**\n * Error thrown when the access token lacks required scopes.\n */\nexport class InsufficientScopeError extends PulseIdError {\n readonly requiredScope: string | undefined;\n\n constructor(message: string, requiredScope?: string) {\n super('insufficient_scope', message, 403);\n this.name = 'InsufficientScopeError';\n this.requiredScope = requiredScope;\n }\n}\n\n/**\n * Error thrown when a resource is not found.\n */\nexport class NotFoundError extends PulseIdError {\n constructor(message = 'Resource not found') {\n super('not_found', message, 404);\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Error thrown when a network request fails.\n */\nexport class NetworkError extends PulseIdError {\n readonly cause: Error | undefined;\n\n constructor(message: string, cause?: Error) {\n super('server_error', message, 0);\n this.name = 'NetworkError';\n this.cause = cause;\n }\n}\n\n/**\n * Error thrown when a request times out.\n */\nexport class TimeoutError extends PulseIdError {\n constructor(message = 'Request timed out') {\n super('server_error', message, 0);\n this.name = 'TimeoutError';\n }\n}\n\n/**\n * Map API error codes to SDK error codes.\n */\nfunction mapErrorCode(apiError: string): ErrorCode {\n switch (apiError) {\n case 'invalid_token':\n return 'invalid_token';\n case 'expired_token':\n return 'expired_token';\n case 'insufficient_scope':\n return 'insufficient_scope';\n case 'not_found':\n return 'not_found';\n case 'invalid_request':\n return 'invalid_request';\n default:\n return 'server_error';\n }\n}\n","/**\n * HTTP Client Utilities\n *\n * Internal utilities for making HTTP requests with proper error handling.\n */\n\nimport { NetworkError, PulseIdError, TimeoutError } from './errors.js';\nimport type { ApiErrorResponse, PulseIdConfig } from './types.js';\n\nconst DEFAULT_TIMEOUT = 30_000; // 30 seconds\n\ntype HttpMethod = 'GET' | 'POST' | 'PATCH' | 'DELETE';\n\ntype RequestOptions = {\n method: HttpMethod;\n headers?: Record<string, string>;\n body?: unknown;\n timeout?: number;\n};\n\n/**\n * Validate that a URL is a valid HTTPS URL.\n * Prevents SSRF and ensures secure communication.\n */\nfunction validateIssuerUrl(issuer: string): string {\n let url: URL;\n try {\n url = new URL(issuer);\n } catch {\n throw new Error(`Invalid issuer URL: ${issuer}`);\n }\n\n if (url.username || url.password) {\n throw new Error(`Issuer URL must not include credentials: ${issuer}`);\n }\n\n // Only allow HTTPS in production (allow HTTP for localhost in development)\n const isLocalhost =\n url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '::1';\n if (url.protocol !== 'https:' && !isLocalhost) {\n throw new Error(`Issuer URL must use HTTPS: ${issuer}`);\n }\n\n // Remove trailing slash for consistent URL building\n return url.origin + url.pathname.replace(/\\/$/, '');\n}\n\n/**\n * Create a configured HTTP client for the PULSE ID API.\n */\nexport function createHttpClient(config: PulseIdConfig) {\n const baseUrl = validateIssuerUrl(config.issuer);\n const fetchFn = config.fetch ?? globalThis.fetch;\n const timeout = config.timeout ?? DEFAULT_TIMEOUT;\n\n /**\n * Make an HTTP request to the PULSE ID API.\n */\n async function request<T>(path: string, options: RequestOptions): Promise<T> {\n const url = `${baseUrl}${path}`;\n const controller = new AbortController();\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, options.timeout ?? timeout);\n\n try {\n const response = await fetchFn(url, {\n method: options.method,\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n ...options.headers,\n },\n ...(options.body !== undefined && { body: JSON.stringify(options.body) }),\n signal: controller.signal,\n });\n\n // Clear the timeout\n clearTimeout(timeoutId);\n\n // Parse response body\n const contentType = response.headers.get('content-type');\n const isJson = contentType?.includes('application/json');\n\n if (!response.ok) {\n if (isJson) {\n const errorBody = (await response.json()) as ApiErrorResponse;\n throw PulseIdError.fromResponse(errorBody, response.status);\n }\n\n const errorText = await response.text();\n throw new PulseIdError(\n 'server_error',\n errorText || `HTTP ${response.status}`,\n response.status\n );\n }\n\n // Return parsed JSON or empty object for 204\n if (response.status === 204 || !isJson) {\n return {} as T;\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n // Re-throw SDK errors as-is\n if (error instanceof PulseIdError) {\n throw error;\n }\n\n // Handle abort (timeout)\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw new TimeoutError(`Request to ${path} timed out after ${timeout}ms`);\n }\n\n // Handle network errors\n if (error instanceof TypeError) {\n throw new NetworkError(`Network request to ${path} failed`, error);\n }\n\n // Unknown error\n throw new NetworkError(\n `Unknown error during request to ${path}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n return {\n /**\n * Make a GET request.\n */\n get<T>(path: string, headers?: Record<string, string>): Promise<T> {\n return request<T>(path, { method: 'GET', ...(headers && { headers }) });\n },\n\n /**\n * Make a POST request.\n */\n post<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return request<T>(path, { method: 'POST', body, ...(headers && { headers }) });\n },\n\n /**\n * Make a PATCH request.\n */\n patch<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return request<T>(path, { method: 'PATCH', body, ...(headers && { headers }) });\n },\n\n /**\n * Make a DELETE request.\n */\n delete<T>(path: string, headers?: Record<string, string>): Promise<T> {\n return request<T>(path, { method: 'DELETE', ...(headers && { headers }) });\n },\n\n /**\n * Make a form-encoded POST request (for OAuth token endpoints).\n */\n async postForm<T>(\n path: string,\n data: Record<string, string>,\n headers?: Record<string, string>\n ): Promise<T> {\n const url = `${baseUrl}${path}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetchFn(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n ...headers,\n },\n body: new URLSearchParams(data).toString(),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const contentType = response.headers.get('content-type');\n const isJson = contentType?.includes('application/json');\n\n if (!response.ok) {\n if (isJson) {\n const errorBody = (await response.json()) as ApiErrorResponse;\n throw PulseIdError.fromResponse(errorBody, response.status);\n }\n // Handle non-JSON error responses (e.g., HTML from proxy)\n const errorText = await response.text();\n throw new PulseIdError(\n 'server_error',\n errorText || `HTTP ${response.status}`,\n response.status\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof PulseIdError) throw error;\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw new TimeoutError();\n }\n throw new NetworkError(\n `Request to ${path} failed`,\n error instanceof Error ? error : undefined\n );\n }\n },\n };\n}\n\nexport type HttpClient = ReturnType<typeof createHttpClient>;\n","/**\n * PULSE ID Client\n *\n * Client-side SDK for interacting with the PULSE ID API.\n * Use this in browser environments where you have an access token.\n *\n * For server-side usage with refresh token management, use `PulseIdServer` from './server'.\n */\n\nimport { createHttpClient, type HttpClient } from './http.js';\nimport type { Profile, ProfileUpdate, PulseIdConfig, UserInfo } from './types.js';\n\n/**\n * PULSE ID API Client.\n *\n * @example\n * ```typescript\n * const client = new PulseIdClient({\n * issuer: 'https://id.pulserunning.at',\n * clientId: 'your-client-id',\n * });\n *\n * const profile = await client.getProfile(accessToken);\n * console.log(profile.displayName);\n * ```\n */\nexport class PulseIdClient {\n protected readonly http: HttpClient;\n protected readonly config: PulseIdConfig;\n\n constructor(config: PulseIdConfig) {\n this.config = config;\n this.http = createHttpClient(config);\n }\n\n // ===========================================================================\n // PROFILE\n // ===========================================================================\n\n /**\n * Get the authenticated user's profile.\n *\n * The fields returned depend on the scopes granted to the access token:\n * - `profile`: name, avatar, birthday, etc.\n * - `email`: email address and verification status\n * - `address`: address information\n * - `phone`: phone number\n *\n * @param accessToken - A valid access token\n * @returns The user's profile\n *\n * @example\n * ```typescript\n * const profile = await client.getProfile(accessToken);\n * console.log(`Hello, ${profile.displayName}!`);\n * ```\n */\n async getProfile(accessToken: string): Promise<Profile> {\n return this.http.get<Profile>('/api/v1/me', {\n Authorization: `Bearer ${accessToken}`,\n });\n }\n\n /**\n * Update the authenticated user's profile.\n *\n * Requires the `profile:write` scope.\n *\n * @param accessToken - A valid access token with `profile:write` scope\n * @param data - The profile fields to update\n * @returns The updated profile\n *\n * @example\n * ```typescript\n * const updated = await client.updateProfile(accessToken, {\n * displayName: 'Max Runner',\n * height: 180,\n * });\n * ```\n */\n async updateProfile(accessToken: string, data: ProfileUpdate): Promise<Profile> {\n return this.http.patch<Profile>('/api/v1/me', data, {\n Authorization: `Bearer ${accessToken}`,\n });\n }\n\n /**\n * Get the authenticated user's OIDC userinfo.\n *\n * Requires the `openid` scope. Additional fields depend on granted scopes.\n *\n * @param accessToken - A valid access token\n * @returns The user's OIDC userinfo\n *\n * @example\n * ```typescript\n * const info = await client.getUserInfo(accessToken);\n * console.log(info.sub);\n * ```\n */\n async getUserInfo(accessToken: string): Promise<UserInfo> {\n return this.http.get<UserInfo>('/userinfo', {\n Authorization: `Bearer ${accessToken}`,\n });\n }\n\n // ===========================================================================\n // EMAIL VERIFICATION\n // ===========================================================================\n\n /**\n * Resend the email verification link.\n *\n * Requires the `email` scope. Will fail if email is already verified.\n *\n * @param accessToken - A valid access token with `email` scope\n * @returns Success confirmation\n * @throws {PulseIdError} If email is already verified or request fails\n *\n * @example\n * ```typescript\n * try {\n * await client.resendVerificationEmail(accessToken);\n * console.log('Verification email sent!');\n * } catch (error) {\n * if (error.code === 'invalid_request') {\n * console.log('Email already verified');\n * }\n * }\n * ```\n */\n async resendVerificationEmail(accessToken: string): Promise<{ success: true; message: string }> {\n return this.http.post<{ success: true; message: string }>(\n '/api/v1/me/resend-verification',\n {},\n {\n Authorization: `Bearer ${accessToken}`,\n }\n );\n }\n\n // ===========================================================================\n // UTILITY METHODS\n // ===========================================================================\n\n /**\n * Get the configured issuer URL.\n */\n get issuer(): string {\n return this.config.issuer;\n }\n\n /**\n * Get the configured client ID.\n */\n get clientId(): string {\n return this.config.clientId;\n }\n\n /**\n * Build an authorization URL for the OAuth flow.\n *\n * @param options - Authorization options\n * @returns The authorization URL to redirect the user to\n *\n * @example\n * ```typescript\n * const authUrl = client.buildAuthorizationUrl({\n * redirectUri: 'https://myapp.com/callback',\n * scope: 'openid profile email',\n * state: 'random-state-string',\n * });\n * window.location.href = authUrl;\n * ```\n */\n buildAuthorizationUrl(options: {\n redirectUri: string;\n scope: string;\n state: string;\n nonce?: string;\n codeChallenge: string;\n codeChallengeMethod?: 'S256';\n prompt?: 'none' | 'login' | 'consent' | 'create';\n loginHint?: string;\n }): string {\n if (options.codeChallengeMethod && options.codeChallengeMethod !== 'S256') {\n throw new Error('code_challenge_method must be S256');\n }\n\n if (!options.state) {\n throw new Error('state is required for authorization requests');\n }\n\n if (!options.codeChallenge) {\n throw new Error('code_challenge is required for authorization requests');\n }\n\n const scopes = options.scope.split(' ').filter(Boolean);\n if (scopes.includes('openid') && !options.nonce) {\n throw new Error('nonce is required when requesting openid scope');\n }\n\n const url = new URL(`${this.config.issuer}/authorize`);\n\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('client_id', this.config.clientId);\n url.searchParams.set('redirect_uri', options.redirectUri);\n url.searchParams.set('scope', options.scope);\n\n url.searchParams.set('state', options.state);\n if (options.nonce) {\n url.searchParams.set('nonce', options.nonce);\n }\n url.searchParams.set('code_challenge', options.codeChallenge);\n url.searchParams.set('code_challenge_method', options.codeChallengeMethod ?? 'S256');\n if (options.prompt) {\n url.searchParams.set('prompt', options.prompt);\n }\n if (options.loginHint) {\n url.searchParams.set('login_hint', options.loginHint);\n }\n\n return url.toString();\n }\n\n /**\n * Build a logout URL for ending the session.\n *\n * @param options - Logout options\n * @returns The logout URL to redirect the user to\n *\n * @example\n * ```typescript\n * const logoutUrl = client.buildLogoutUrl({\n * idTokenHint: idToken,\n * postLogoutRedirectUri: 'https://myapp.com',\n * });\n * window.location.href = logoutUrl;\n * ```\n */\n buildLogoutUrl(options?: {\n idTokenHint?: string;\n postLogoutRedirectUri?: string;\n state?: string;\n }): string {\n const url = new URL(`${this.config.issuer}/logout`);\n\n if (options?.idTokenHint) {\n url.searchParams.set('id_token_hint', options.idTokenHint);\n }\n if (options?.postLogoutRedirectUri) {\n url.searchParams.set('post_logout_redirect_uri', options.postLogoutRedirectUri);\n }\n if (options?.state) {\n url.searchParams.set('state', options.state);\n }\n\n return url.toString();\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -294,6 +294,31 @@ declare class PulseIdClient {
|
|
|
294
294
|
* ```
|
|
295
295
|
*/
|
|
296
296
|
getUserInfo(accessToken: string): Promise<UserInfo>;
|
|
297
|
+
/**
|
|
298
|
+
* Resend the email verification link.
|
|
299
|
+
*
|
|
300
|
+
* Requires the `email` scope. Will fail if email is already verified.
|
|
301
|
+
*
|
|
302
|
+
* @param accessToken - A valid access token with `email` scope
|
|
303
|
+
* @returns Success confirmation
|
|
304
|
+
* @throws {PulseIdError} If email is already verified or request fails
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* ```typescript
|
|
308
|
+
* try {
|
|
309
|
+
* await client.resendVerificationEmail(accessToken);
|
|
310
|
+
* console.log('Verification email sent!');
|
|
311
|
+
* } catch (error) {
|
|
312
|
+
* if (error.code === 'invalid_request') {
|
|
313
|
+
* console.log('Email already verified');
|
|
314
|
+
* }
|
|
315
|
+
* }
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
resendVerificationEmail(accessToken: string): Promise<{
|
|
319
|
+
success: true;
|
|
320
|
+
message: string;
|
|
321
|
+
}>;
|
|
297
322
|
/**
|
|
298
323
|
* Get the configured issuer URL.
|
|
299
324
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { InsufficientScopeError, InvalidTokenError, NetworkError, NotFoundError, PulseIdClient, PulseIdError, TimeoutError } from './chunk-
|
|
1
|
+
export { InsufficientScopeError, InvalidTokenError, NetworkError, NotFoundError, PulseIdClient, PulseIdError, TimeoutError } from './chunk-GAMIRD7Y.js';
|
|
2
2
|
|
|
3
3
|
// src/types.ts
|
|
4
4
|
var SCOPES = {
|
package/dist/server.d.ts
CHANGED
|
@@ -23,9 +23,16 @@ interface ProfileResource {
|
|
|
23
23
|
interface UserInfoResource {
|
|
24
24
|
get(): Promise<UserInfo>;
|
|
25
25
|
}
|
|
26
|
+
interface EmailResource {
|
|
27
|
+
resendVerification(): Promise<{
|
|
28
|
+
success: true;
|
|
29
|
+
message: string;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
26
32
|
interface UserClient {
|
|
27
33
|
profile: ProfileResource;
|
|
28
34
|
userInfo: UserInfoResource;
|
|
35
|
+
email: EmailResource;
|
|
29
36
|
}
|
|
30
37
|
declare class PulseIdServer extends PulseIdClient {
|
|
31
38
|
private readonly clientSecret;
|
|
@@ -38,7 +45,11 @@ declare class PulseIdServer extends PulseIdClient {
|
|
|
38
45
|
getProfileWithRefresh(storage: TokenStorage, userId: string): Promise<Profile>;
|
|
39
46
|
updateProfileWithRefresh(storage: TokenStorage, userId: string, data: ProfileUpdate): Promise<Profile>;
|
|
40
47
|
getUserInfoWithRefresh(storage: TokenStorage, userId: string): Promise<UserInfo>;
|
|
48
|
+
resendVerificationWithRefresh(storage: TokenStorage, userId: string): Promise<{
|
|
49
|
+
success: true;
|
|
50
|
+
message: string;
|
|
51
|
+
}>;
|
|
41
52
|
private ensureValidTokens;
|
|
42
53
|
}
|
|
43
54
|
|
|
44
|
-
export { Profile, type ProfileResource, ProfileUpdate, PulseIdConfig, PulseIdServer, type ServerConfig, type StoredTokens, TokenResponse, type TokenStorage, type UserClient, UserInfo, type UserInfoResource };
|
|
55
|
+
export { type EmailResource, Profile, type ProfileResource, ProfileUpdate, PulseIdConfig, PulseIdServer, type ServerConfig, type StoredTokens, TokenResponse, type TokenStorage, type UserClient, UserInfo, type UserInfoResource };
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PulseIdClient, PulseIdError } from './chunk-
|
|
2
|
-
export { InsufficientScopeError, InvalidTokenError, PulseIdError } from './chunk-
|
|
1
|
+
import { PulseIdClient, PulseIdError } from './chunk-GAMIRD7Y.js';
|
|
2
|
+
export { InsufficientScopeError, InvalidTokenError, PulseIdError } from './chunk-GAMIRD7Y.js';
|
|
3
3
|
|
|
4
4
|
// src/server.ts
|
|
5
5
|
var PulseIdServer = class extends PulseIdClient {
|
|
@@ -25,6 +25,9 @@ var PulseIdServer = class extends PulseIdClient {
|
|
|
25
25
|
},
|
|
26
26
|
userInfo: {
|
|
27
27
|
get: () => this.getUserInfoWithRefresh(storage, userId)
|
|
28
|
+
},
|
|
29
|
+
email: {
|
|
30
|
+
resendVerification: () => this.resendVerificationWithRefresh(storage, userId)
|
|
28
31
|
}
|
|
29
32
|
};
|
|
30
33
|
}
|
|
@@ -76,6 +79,10 @@ var PulseIdServer = class extends PulseIdClient {
|
|
|
76
79
|
const tokens = await this.ensureValidTokens(storage, userId);
|
|
77
80
|
return this.getUserInfo(tokens.accessToken);
|
|
78
81
|
}
|
|
82
|
+
async resendVerificationWithRefresh(storage, userId) {
|
|
83
|
+
const tokens = await this.ensureValidTokens(storage, userId);
|
|
84
|
+
return this.resendVerificationEmail(tokens.accessToken);
|
|
85
|
+
}
|
|
79
86
|
async ensureValidTokens(storage, userId) {
|
|
80
87
|
const tokens = await storage.getTokens(userId);
|
|
81
88
|
if (!tokens) {
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["import { PulseIdClient } from './client.js';\nimport { PulseIdError } from './errors.js';\nimport type {\n Profile,\n ProfileUpdate,\n PulseIdConfig,\n RefreshOptions,\n TokenResponse,\n UserInfo,\n} from './types.js';\n\nexport type ServerConfig = PulseIdConfig & {\n clientSecret: string;\n storage?: TokenStorage;\n};\n\nexport interface TokenStorage {\n getTokens(userId: string): Promise<StoredTokens | null>;\n setTokens(userId: string, tokens: StoredTokens): Promise<void>;\n deleteTokens(userId: string): Promise<void>;\n}\n\nexport type StoredTokens = {\n accessToken: string;\n refreshToken: string;\n expiresAt: Date;\n scope?: string;\n};\n\nexport interface ProfileResource {\n get(): Promise<Profile>;\n update(data: ProfileUpdate): Promise<Profile>;\n}\n\nexport interface UserInfoResource {\n get(): Promise<UserInfo>;\n}\n\nexport interface EmailResource {\n resendVerification(): Promise<{ success: true; message: string }>;\n}\n\nexport interface UserClient {\n profile: ProfileResource;\n userInfo: UserInfoResource;\n email: EmailResource;\n}\n\nexport class PulseIdServer extends PulseIdClient {\n private readonly clientSecret: string;\n private readonly storage: TokenStorage | undefined;\n\n constructor(config: ServerConfig) {\n if (!config.clientSecret) {\n throw new Error('clientSecret is required for server-side operations');\n }\n super(config);\n this.clientSecret = config.clientSecret;\n this.storage = config.storage;\n }\n\n forUser(userId: string): UserClient {\n if (!this.storage) {\n throw new Error('storage must be configured to use forUser()');\n }\n const storage = this.storage;\n\n return {\n profile: {\n get: () => this.getProfileWithRefresh(storage, userId),\n update: (data: ProfileUpdate) => this.updateProfileWithRefresh(storage, userId, data),\n },\n userInfo: {\n get: () => this.getUserInfoWithRefresh(storage, userId),\n },\n email: {\n resendVerification: () => this.resendVerificationWithRefresh(storage, userId),\n },\n };\n }\n\n async exchangeCode(code: string, redirectUri: string, codeVerifier?: string): Promise<TokenResponse> {\n const data: Record<string, string> = {\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n client_id: this.config.clientId,\n client_secret: this.clientSecret,\n };\n if (codeVerifier) {\n data['code_verifier'] = codeVerifier;\n }\n return this.http.postForm<TokenResponse>('/token', data);\n }\n\n async refreshTokens(options: RefreshOptions): Promise<TokenResponse> {\n const data: Record<string, string> = {\n grant_type: 'refresh_token',\n refresh_token: options.refreshToken,\n client_id: this.config.clientId,\n client_secret: this.clientSecret,\n };\n if (options.scope) {\n data['scope'] = options.scope;\n }\n return this.http.postForm<TokenResponse>('/token', data);\n }\n\n async revokeToken(token: string, tokenTypeHint?: 'access_token' | 'refresh_token'): Promise<void> {\n const data: Record<string, string> = {\n token,\n client_id: this.config.clientId,\n client_secret: this.clientSecret,\n };\n if (tokenTypeHint) {\n data['token_type_hint'] = tokenTypeHint;\n }\n await this.http.postForm<void>('/revoke', data);\n }\n\n async getProfileWithRefresh(storage: TokenStorage, userId: string): Promise<Profile> {\n const tokens = await this.ensureValidTokens(storage, userId);\n return this.getProfile(tokens.accessToken);\n }\n\n async updateProfileWithRefresh(storage: TokenStorage, userId: string, data: ProfileUpdate): Promise<Profile> {\n const tokens = await this.ensureValidTokens(storage, userId);\n return this.updateProfile(tokens.accessToken, data);\n }\n\n async getUserInfoWithRefresh(storage: TokenStorage, userId: string): Promise<UserInfo> {\n const tokens = await this.ensureValidTokens(storage, userId);\n return this.getUserInfo(tokens.accessToken);\n }\n\n async resendVerificationWithRefresh(\n storage: TokenStorage,\n userId: string\n ): Promise<{ success: true; message: string }> {\n const tokens = await this.ensureValidTokens(storage, userId);\n return this.resendVerificationEmail(tokens.accessToken);\n }\n\n private async ensureValidTokens(storage: TokenStorage, userId: string): Promise<StoredTokens> {\n const tokens = await storage.getTokens(userId);\n if (!tokens) {\n throw new PulseIdError('invalid_token', 'No tokens found. User needs to re-authenticate.', 401);\n }\n\n const bufferMs = 5 * 60 * 1000;\n const isExpired = tokens.expiresAt.getTime() - bufferMs < Date.now();\n if (!isExpired) {\n return tokens;\n }\n\n try {\n const newTokens = await this.refreshTokens({ refreshToken: tokens.refreshToken });\n const updatedTokens: StoredTokens = {\n accessToken: newTokens.access_token,\n refreshToken: newTokens.refresh_token ?? tokens.refreshToken,\n expiresAt: new Date(Date.now() + newTokens.expires_in * 1000),\n ...(newTokens.scope ?? tokens.scope ? { scope: newTokens.scope ?? tokens.scope } : {}),\n };\n await storage.setTokens(userId, updatedTokens);\n return updatedTokens;\n } catch {\n await storage.deleteTokens(userId);\n throw new PulseIdError('invalid_token', 'Token refresh failed. User needs to re-authenticate.', 401);\n }\n }\n}\n\nexport type { TokenResponse, Profile, ProfileUpdate, PulseIdConfig, UserInfo } from './types.js';\nexport { PulseIdError, InvalidTokenError, InsufficientScopeError } from './errors.js';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pulseid/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "TypeScript SDK for PULSE ID - Your athlete identity",
|
|
5
5
|
"author": "Patrick Hübl-Neschkudla <patrick@pulserunning.at>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,22 +25,6 @@
|
|
|
25
25
|
"engines": {
|
|
26
26
|
"node": ">=22.0.0"
|
|
27
27
|
},
|
|
28
|
-
"scripts": {
|
|
29
|
-
"build": "tsup",
|
|
30
|
-
"dev": "tsup --watch",
|
|
31
|
-
"test": "vitest run",
|
|
32
|
-
"test:watch": "vitest",
|
|
33
|
-
"test:coverage": "vitest run --coverage",
|
|
34
|
-
"lint": "eslint src --ext .ts",
|
|
35
|
-
"typecheck": "tsc --noEmit",
|
|
36
|
-
"clean": "rm -rf dist",
|
|
37
|
-
"changeset": "changeset",
|
|
38
|
-
"version": "changeset version",
|
|
39
|
-
"release": "pnpm build && changeset publish",
|
|
40
|
-
"prepublishOnly": "npm run build",
|
|
41
|
-
"docs:dev": "cd docs && pnpm dev",
|
|
42
|
-
"docs:build": "cd docs && pnpm build"
|
|
43
|
-
},
|
|
44
28
|
"devDependencies": {
|
|
45
29
|
"@changesets/changelog-github": "0.5.2",
|
|
46
30
|
"@changesets/cli": "2.29.8",
|
|
@@ -48,7 +32,7 @@
|
|
|
48
32
|
"@vitest/coverage-v8": "4.0.18",
|
|
49
33
|
"eslint": "9.39.2",
|
|
50
34
|
"tsup": "8.5.1",
|
|
51
|
-
"typescript": "5.
|
|
35
|
+
"typescript": "5.9.3",
|
|
52
36
|
"vitest": "4.0.18"
|
|
53
37
|
},
|
|
54
38
|
"keywords": [
|
|
@@ -71,5 +55,20 @@
|
|
|
71
55
|
"homepage": "https://github.com/flipace/pulse-id-sdk-ts#readme",
|
|
72
56
|
"directories": {
|
|
73
57
|
"doc": "docs"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsup",
|
|
61
|
+
"dev": "tsup --watch",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"test:watch": "vitest",
|
|
64
|
+
"test:coverage": "vitest run --coverage",
|
|
65
|
+
"lint": "eslint src --ext .ts",
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"clean": "rm -rf dist",
|
|
68
|
+
"changeset": "changeset",
|
|
69
|
+
"version": "changeset version",
|
|
70
|
+
"release": "pnpm build && changeset publish",
|
|
71
|
+
"docs:dev": "cd docs && pnpm dev",
|
|
72
|
+
"docs:build": "cd docs && pnpm build"
|
|
74
73
|
}
|
|
75
|
-
}
|
|
74
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/client.ts"],"names":[],"mappings":"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","file":"chunk-BRQ2T53Z.js","sourcesContent":["/**\n * PULSE ID SDK Errors\n *\n * Custom error classes for better error handling.\n */\n\nimport type { ApiErrorResponse, ErrorCode } from './types.js';\n\n/**\n * Base error class for PULSE ID SDK errors.\n */\nexport class PulseIdError extends Error {\n readonly code: ErrorCode;\n readonly statusCode: number;\n\n constructor(code: ErrorCode, message: string, statusCode = 400) {\n super(message);\n this.name = 'PulseIdError';\n this.code = code;\n this.statusCode = statusCode;\n\n // Maintains proper stack trace in V8 environments\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, PulseIdError);\n }\n }\n\n /**\n * Create an error from an API response.\n */\n static fromResponse(response: ApiErrorResponse, statusCode: number): PulseIdError {\n const code = mapErrorCode(response.error);\n\n switch (code) {\n case 'invalid_token':\n case 'expired_token':\n return new InvalidTokenError(response.error_description);\n case 'insufficient_scope':\n return new InsufficientScopeError(\n response.error_description,\n response.required_scope\n );\n case 'not_found':\n return new NotFoundError(response.error_description);\n default:\n return new PulseIdError(code, response.error_description, statusCode);\n }\n }\n}\n\n/**\n * Error thrown when the access token is invalid or expired.\n */\nexport class InvalidTokenError extends PulseIdError {\n constructor(message = 'Invalid or expired access token') {\n super('invalid_token', message, 401);\n this.name = 'InvalidTokenError';\n }\n}\n\n/**\n * Error thrown when the access token lacks required scopes.\n */\nexport class InsufficientScopeError extends PulseIdError {\n readonly requiredScope: string | undefined;\n\n constructor(message: string, requiredScope?: string) {\n super('insufficient_scope', message, 403);\n this.name = 'InsufficientScopeError';\n this.requiredScope = requiredScope;\n }\n}\n\n/**\n * Error thrown when a resource is not found.\n */\nexport class NotFoundError extends PulseIdError {\n constructor(message = 'Resource not found') {\n super('not_found', message, 404);\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Error thrown when a network request fails.\n */\nexport class NetworkError extends PulseIdError {\n readonly cause: Error | undefined;\n\n constructor(message: string, cause?: Error) {\n super('server_error', message, 0);\n this.name = 'NetworkError';\n this.cause = cause;\n }\n}\n\n/**\n * Error thrown when a request times out.\n */\nexport class TimeoutError extends PulseIdError {\n constructor(message = 'Request timed out') {\n super('server_error', message, 0);\n this.name = 'TimeoutError';\n }\n}\n\n/**\n * Map API error codes to SDK error codes.\n */\nfunction mapErrorCode(apiError: string): ErrorCode {\n switch (apiError) {\n case 'invalid_token':\n return 'invalid_token';\n case 'expired_token':\n return 'expired_token';\n case 'insufficient_scope':\n return 'insufficient_scope';\n case 'not_found':\n return 'not_found';\n case 'invalid_request':\n return 'invalid_request';\n default:\n return 'server_error';\n }\n}\n","/**\n * HTTP Client Utilities\n *\n * Internal utilities for making HTTP requests with proper error handling.\n */\n\nimport { NetworkError, PulseIdError, TimeoutError } from './errors.js';\nimport type { ApiErrorResponse, PulseIdConfig } from './types.js';\n\nconst DEFAULT_TIMEOUT = 30_000; // 30 seconds\n\ntype HttpMethod = 'GET' | 'POST' | 'PATCH' | 'DELETE';\n\ntype RequestOptions = {\n method: HttpMethod;\n headers?: Record<string, string>;\n body?: unknown;\n timeout?: number;\n};\n\n/**\n * Validate that a URL is a valid HTTPS URL.\n * Prevents SSRF and ensures secure communication.\n */\nfunction validateIssuerUrl(issuer: string): string {\n let url: URL;\n try {\n url = new URL(issuer);\n } catch {\n throw new Error(`Invalid issuer URL: ${issuer}`);\n }\n\n if (url.username || url.password) {\n throw new Error(`Issuer URL must not include credentials: ${issuer}`);\n }\n\n // Only allow HTTPS in production (allow HTTP for localhost in development)\n const isLocalhost =\n url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '::1';\n if (url.protocol !== 'https:' && !isLocalhost) {\n throw new Error(`Issuer URL must use HTTPS: ${issuer}`);\n }\n\n // Remove trailing slash for consistent URL building\n return url.origin + url.pathname.replace(/\\/$/, '');\n}\n\n/**\n * Create a configured HTTP client for the PULSE ID API.\n */\nexport function createHttpClient(config: PulseIdConfig) {\n const baseUrl = validateIssuerUrl(config.issuer);\n const fetchFn = config.fetch ?? globalThis.fetch;\n const timeout = config.timeout ?? DEFAULT_TIMEOUT;\n\n /**\n * Make an HTTP request to the PULSE ID API.\n */\n async function request<T>(path: string, options: RequestOptions): Promise<T> {\n const url = `${baseUrl}${path}`;\n const controller = new AbortController();\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, options.timeout ?? timeout);\n\n try {\n const response = await fetchFn(url, {\n method: options.method,\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n ...options.headers,\n },\n ...(options.body !== undefined && { body: JSON.stringify(options.body) }),\n signal: controller.signal,\n });\n\n // Clear the timeout\n clearTimeout(timeoutId);\n\n // Parse response body\n const contentType = response.headers.get('content-type');\n const isJson = contentType?.includes('application/json');\n\n if (!response.ok) {\n if (isJson) {\n const errorBody = (await response.json()) as ApiErrorResponse;\n throw PulseIdError.fromResponse(errorBody, response.status);\n }\n\n const errorText = await response.text();\n throw new PulseIdError(\n 'server_error',\n errorText || `HTTP ${response.status}`,\n response.status\n );\n }\n\n // Return parsed JSON or empty object for 204\n if (response.status === 204 || !isJson) {\n return {} as T;\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n // Re-throw SDK errors as-is\n if (error instanceof PulseIdError) {\n throw error;\n }\n\n // Handle abort (timeout)\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw new TimeoutError(`Request to ${path} timed out after ${timeout}ms`);\n }\n\n // Handle network errors\n if (error instanceof TypeError) {\n throw new NetworkError(`Network request to ${path} failed`, error);\n }\n\n // Unknown error\n throw new NetworkError(\n `Unknown error during request to ${path}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n return {\n /**\n * Make a GET request.\n */\n get<T>(path: string, headers?: Record<string, string>): Promise<T> {\n return request<T>(path, { method: 'GET', ...(headers && { headers }) });\n },\n\n /**\n * Make a POST request.\n */\n post<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return request<T>(path, { method: 'POST', body, ...(headers && { headers }) });\n },\n\n /**\n * Make a PATCH request.\n */\n patch<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T> {\n return request<T>(path, { method: 'PATCH', body, ...(headers && { headers }) });\n },\n\n /**\n * Make a DELETE request.\n */\n delete<T>(path: string, headers?: Record<string, string>): Promise<T> {\n return request<T>(path, { method: 'DELETE', ...(headers && { headers }) });\n },\n\n /**\n * Make a form-encoded POST request (for OAuth token endpoints).\n */\n async postForm<T>(\n path: string,\n data: Record<string, string>,\n headers?: Record<string, string>\n ): Promise<T> {\n const url = `${baseUrl}${path}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetchFn(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n ...headers,\n },\n body: new URLSearchParams(data).toString(),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const contentType = response.headers.get('content-type');\n const isJson = contentType?.includes('application/json');\n\n if (!response.ok) {\n if (isJson) {\n const errorBody = (await response.json()) as ApiErrorResponse;\n throw PulseIdError.fromResponse(errorBody, response.status);\n }\n // Handle non-JSON error responses (e.g., HTML from proxy)\n const errorText = await response.text();\n throw new PulseIdError(\n 'server_error',\n errorText || `HTTP ${response.status}`,\n response.status\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof PulseIdError) throw error;\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw new TimeoutError();\n }\n throw new NetworkError(\n `Request to ${path} failed`,\n error instanceof Error ? error : undefined\n );\n }\n },\n };\n}\n\nexport type HttpClient = ReturnType<typeof createHttpClient>;\n","/**\n * PULSE ID Client\n *\n * Client-side SDK for interacting with the PULSE ID API.\n * Use this in browser environments where you have an access token.\n *\n * For server-side usage with refresh token management, use `PulseIdServer` from './server'.\n */\n\nimport { createHttpClient, type HttpClient } from './http.js';\nimport type { Profile, ProfileUpdate, PulseIdConfig, UserInfo } from './types.js';\n\n/**\n * PULSE ID API Client.\n *\n * @example\n * ```typescript\n * const client = new PulseIdClient({\n * issuer: 'https://id.pulserunning.at',\n * clientId: 'your-client-id',\n * });\n *\n * const profile = await client.getProfile(accessToken);\n * console.log(profile.displayName);\n * ```\n */\nexport class PulseIdClient {\n protected readonly http: HttpClient;\n protected readonly config: PulseIdConfig;\n\n constructor(config: PulseIdConfig) {\n this.config = config;\n this.http = createHttpClient(config);\n }\n\n // ===========================================================================\n // PROFILE\n // ===========================================================================\n\n /**\n * Get the authenticated user's profile.\n *\n * The fields returned depend on the scopes granted to the access token:\n * - `profile`: name, avatar, birthday, etc.\n * - `email`: email address and verification status\n * - `address`: address information\n * - `phone`: phone number\n *\n * @param accessToken - A valid access token\n * @returns The user's profile\n *\n * @example\n * ```typescript\n * const profile = await client.getProfile(accessToken);\n * console.log(`Hello, ${profile.displayName}!`);\n * ```\n */\n async getProfile(accessToken: string): Promise<Profile> {\n return this.http.get<Profile>('/api/v1/me', {\n Authorization: `Bearer ${accessToken}`,\n });\n }\n\n /**\n * Update the authenticated user's profile.\n *\n * Requires the `profile:write` scope.\n *\n * @param accessToken - A valid access token with `profile:write` scope\n * @param data - The profile fields to update\n * @returns The updated profile\n *\n * @example\n * ```typescript\n * const updated = await client.updateProfile(accessToken, {\n * displayName: 'Max Runner',\n * height: 180,\n * });\n * ```\n */\n async updateProfile(accessToken: string, data: ProfileUpdate): Promise<Profile> {\n return this.http.patch<Profile>('/api/v1/me', data, {\n Authorization: `Bearer ${accessToken}`,\n });\n }\n\n /**\n * Get the authenticated user's OIDC userinfo.\n *\n * Requires the `openid` scope. Additional fields depend on granted scopes.\n *\n * @param accessToken - A valid access token\n * @returns The user's OIDC userinfo\n *\n * @example\n * ```typescript\n * const info = await client.getUserInfo(accessToken);\n * console.log(info.sub);\n * ```\n */\n async getUserInfo(accessToken: string): Promise<UserInfo> {\n return this.http.get<UserInfo>('/userinfo', {\n Authorization: `Bearer ${accessToken}`,\n });\n }\n\n // ===========================================================================\n // UTILITY METHODS\n // ===========================================================================\n\n /**\n * Get the configured issuer URL.\n */\n get issuer(): string {\n return this.config.issuer;\n }\n\n /**\n * Get the configured client ID.\n */\n get clientId(): string {\n return this.config.clientId;\n }\n\n /**\n * Build an authorization URL for the OAuth flow.\n *\n * @param options - Authorization options\n * @returns The authorization URL to redirect the user to\n *\n * @example\n * ```typescript\n * const authUrl = client.buildAuthorizationUrl({\n * redirectUri: 'https://myapp.com/callback',\n * scope: 'openid profile email',\n * state: 'random-state-string',\n * });\n * window.location.href = authUrl;\n * ```\n */\n buildAuthorizationUrl(options: {\n redirectUri: string;\n scope: string;\n state: string;\n nonce?: string;\n codeChallenge: string;\n codeChallengeMethod?: 'S256';\n prompt?: 'none' | 'login' | 'consent' | 'create';\n loginHint?: string;\n }): string {\n if (options.codeChallengeMethod && options.codeChallengeMethod !== 'S256') {\n throw new Error('code_challenge_method must be S256');\n }\n\n if (!options.state) {\n throw new Error('state is required for authorization requests');\n }\n\n if (!options.codeChallenge) {\n throw new Error('code_challenge is required for authorization requests');\n }\n\n const scopes = options.scope.split(' ').filter(Boolean);\n if (scopes.includes('openid') && !options.nonce) {\n throw new Error('nonce is required when requesting openid scope');\n }\n\n const url = new URL(`${this.config.issuer}/authorize`);\n\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('client_id', this.config.clientId);\n url.searchParams.set('redirect_uri', options.redirectUri);\n url.searchParams.set('scope', options.scope);\n\n url.searchParams.set('state', options.state);\n if (options.nonce) {\n url.searchParams.set('nonce', options.nonce);\n }\n url.searchParams.set('code_challenge', options.codeChallenge);\n url.searchParams.set('code_challenge_method', options.codeChallengeMethod ?? 'S256');\n if (options.prompt) {\n url.searchParams.set('prompt', options.prompt);\n }\n if (options.loginHint) {\n url.searchParams.set('login_hint', options.loginHint);\n }\n\n return url.toString();\n }\n\n /**\n * Build a logout URL for ending the session.\n *\n * @param options - Logout options\n * @returns The logout URL to redirect the user to\n *\n * @example\n * ```typescript\n * const logoutUrl = client.buildLogoutUrl({\n * idTokenHint: idToken,\n * postLogoutRedirectUri: 'https://myapp.com',\n * });\n * window.location.href = logoutUrl;\n * ```\n */\n buildLogoutUrl(options?: {\n idTokenHint?: string;\n postLogoutRedirectUri?: string;\n state?: string;\n }): string {\n const url = new URL(`${this.config.issuer}/logout`);\n\n if (options?.idTokenHint) {\n url.searchParams.set('id_token_hint', options.idTokenHint);\n }\n if (options?.postLogoutRedirectUri) {\n url.searchParams.set('post_logout_redirect_uri', options.postLogoutRedirectUri);\n }\n if (options?.state) {\n url.searchParams.set('state', options.state);\n }\n\n return url.toString();\n }\n}\n"]}
|