@pixelume/sdk 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../src/http/HttpClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseErrorEnvelope } from '../contracts/index.js';\nimport {\n PixelumeAbortError,\n PixelumeConfigError,\n PixelumeHttpError,\n PixelumeInvalidResponseError,\n PixelumeNetworkError,\n PixelumeTimeoutError,\n type PixelumeRequestInfo,\n} from '../core/errors.js';\nimport { validateTimeout } from '../core/config.js';\nimport type {\n FetchLike,\n HttpClientOptions,\n HttpMethod,\n HttpRequest,\n HttpResponse,\n} from './types.js';\nimport { buildUrl, normalizePath } from './url.js';\n\n/**\n * Headers that only the runtime (or the SDK itself) may set. `origin`/`referer` in particular\n * must never be forged: the API uses them as a CSRF defence and the SDK does not rely on them.\n */\nconst RESERVED_HEADERS = new Set([\n 'content-length',\n 'cookie',\n 'cookie2',\n 'host',\n 'origin',\n 'referer',\n 'set-cookie',\n]);\n\ntype DecodedBody =\n | { readonly type: 'empty'; readonly value: undefined }\n | { readonly type: 'json'; readonly value: unknown }\n | { readonly type: 'text'; readonly value: string }\n | { readonly type: 'invalid_json'; readonly value: string };\n\n/**\n * Small typed HTTP client over `fetch`. Internal to the SDK: feature modules build on it,\n * consumers use the modules.\n *\n * Policy:\n * - timeout covers the whole exchange, including reading the body;\n * - the caller's `AbortSignal` is honoured before and during the request;\n * - no automatic retries (the caller decides; see `docs/architecture.md`);\n * - credentials default to the client policy and can be overridden per request.\n */\nexport class HttpClient {\n readonly #baseUrl: string;\n readonly #fetch: FetchLike;\n readonly #timeoutMs: number;\n readonly #credentials: HttpClientOptions['credentials'];\n\n constructor(options: HttpClientOptions) {\n this.#baseUrl = options.baseUrl;\n this.#fetch = options.fetch;\n this.#timeoutMs = options.timeoutMs;\n this.#credentials = options.credentials;\n }\n\n async request<T>(request: HttpRequest<T>): Promise<HttpResponse<T>> {\n if (request.json !== undefined && request.form !== undefined) {\n throw new PixelumeConfigError('HTTP requests cannot contain both json and form bodies');\n }\n const info: PixelumeRequestInfo = { method: request.method, path: normalizePath(request.path) };\n const url = buildUrl(this.#baseUrl, request.path, request.query);\n const timeoutMs =\n request.timeoutMs === undefined ? this.#timeoutMs : validateTimeout(request.timeoutMs);\n const init: RequestInit = {\n method: request.method,\n headers: buildHeaders(request),\n credentials: request.credentials ?? this.#credentials,\n };\n if (request.json !== undefined) init.body = JSON.stringify(request.json);\n if (request.form !== undefined) init.body = new URLSearchParams(request.form).toString();\n\n const callerSignal = request.signal;\n if (callerSignal?.aborted) throw new PixelumeAbortError(info, { cause: callerSignal.reason });\n\n // Timeout and caller abort share one controller; the first abort reason wins.\n const controller = new AbortController();\n const timeoutReason = new DOMException(`Timed out after ${timeoutMs} ms`, 'TimeoutError');\n const timer = setTimeout(() => {\n controller.abort(timeoutReason);\n }, timeoutMs);\n const onCallerAbort = () => {\n controller.abort(callerSignal?.reason);\n };\n callerSignal?.addEventListener('abort', onCallerAbort, { once: true });\n // Settles on abort even if an injected `fetch` ignores the signal.\n const abortion = new Promise<never>((_, reject) => {\n controller.signal.addEventListener(\n 'abort',\n () => {\n reject(controller.signal.reason as Error);\n },\n { once: true },\n );\n });\n abortion.catch(() => undefined);\n\n // The function is invoked without a receiver on purpose: calling a browser's native `fetch`\n // with `this` bound to another object throws \"Illegal invocation\".\n const fetchFn = this.#fetch;\n let response: Response;\n let body: DecodedBody;\n try {\n const pending = Promise.resolve().then(() =>\n fetchFn(url, { ...init, signal: controller.signal }),\n );\n // Promise.race subscribes to every contender, so a losing promise that rejects later is\n // handled and never surfaces as an unhandled rejection.\n response = await Promise.race([pending, abortion]);\n body = await Promise.race([readBody(response, request.method), abortion]);\n } catch (error) {\n if (controller.signal.reason === timeoutReason) {\n throw new PixelumeTimeoutError(info, timeoutMs, { cause: error });\n }\n if (callerSignal?.aborted) {\n throw new PixelumeAbortError(info, { cause: callerSignal.reason });\n }\n throw new PixelumeNetworkError(info, { cause: error });\n } finally {\n clearTimeout(timer);\n callerSignal?.removeEventListener('abort', onCallerAbort);\n }\n\n if (!response.ok) throw toHttpError(info, response, body);\n if (body.type === 'invalid_json') {\n throw new PixelumeInvalidResponseError(info, response.status, 'body is not valid JSON');\n }\n const parsed = request.parse(body.value);\n if (!parsed.ok) throw new PixelumeInvalidResponseError(info, response.status, parsed.reason);\n return { status: response.status, headers: response.headers, data: parsed.value };\n }\n}\n\nfunction buildHeaders(request: HttpRequest<unknown>): Headers {\n const headers = new Headers({ accept: 'application/json' });\n for (const [name, value] of Object.entries(request.headers ?? {})) {\n if (RESERVED_HEADERS.has(name.toLowerCase())) {\n throw new PixelumeConfigError(`Header \"${name}\" is managed by the runtime and cannot be set`);\n }\n headers.set(name, value);\n }\n if (request.json !== undefined) headers.set('content-type', 'application/json');\n if (request.form !== undefined) {\n headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');\n }\n return headers;\n}\n\nasync function readBody(response: Response, method: HttpMethod): Promise<DecodedBody> {\n if (method === 'HEAD' || [204, 205, 304].includes(response.status)) {\n return { type: 'empty', value: undefined };\n }\n const text = await response.text();\n if (text === '') return { type: 'empty', value: undefined };\n if (!isJsonContentType(response.headers.get('content-type')))\n return { type: 'text', value: text };\n try {\n return { type: 'json', value: JSON.parse(text) as unknown };\n } catch {\n return { type: 'invalid_json', value: text };\n }\n}\n\nfunction isJsonContentType(contentType: string | null): boolean {\n const mediaType = contentType?.split(';')[0]?.trim().toLowerCase() ?? '';\n return mediaType === 'application/json' || mediaType.endsWith('+json');\n}\n\nfunction toHttpError(\n info: PixelumeRequestInfo,\n response: Response,\n body: DecodedBody,\n): PixelumeHttpError {\n const envelope = body.type === 'json' ? parseErrorEnvelope(body.value) : null;\n return new PixelumeHttpError({\n request: info,\n status: response.status,\n code: envelope?.error.code ?? null,\n apiMessage: envelope?.error.message ?? null,\n requestId: envelope?.error.requestId ?? response.headers.get('x-request-id'),\n payload: body.value,\n });\n}\n"]}
1
+ {"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../src/http/HttpClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseErrorEnvelope } from '../contracts/index.js';\nimport {\n PixelumeAbortError,\n PixelumeConfigError,\n PixelumeHttpError,\n PixelumeInvalidResponseError,\n PixelumeNetworkError,\n PixelumeTimeoutError,\n type PixelumeRequestInfo,\n} from '../core/errors.js';\nimport { validateTimeout } from '../core/config.js';\nimport type {\n FetchLike,\n HttpClientOptions,\n HttpMethod,\n HttpRequest,\n HttpResponse,\n} from './types.js';\nimport { buildUrl, normalizePath } from './url.js';\n\n/**\n * Headers that only the runtime (or the SDK itself) may set. `origin`/`referer` in particular\n * must never be forged: the API uses them as a CSRF defence and the SDK does not rely on them.\n */\nconst RESERVED_HEADERS = new Set([\n 'content-length',\n 'cookie',\n 'cookie2',\n 'host',\n 'origin',\n 'referer',\n 'set-cookie',\n]);\n\ntype DecodedBody =\n | { readonly type: 'empty'; readonly value: undefined }\n | { readonly type: 'json'; readonly value: unknown }\n | { readonly type: 'text'; readonly value: string }\n | { readonly type: 'invalid_json'; readonly value: string };\n\n/**\n * Small typed HTTP client over `fetch`. Internal to the SDK: feature modules build on it,\n * consumers use the modules.\n *\n * Policy:\n * - timeout covers the whole exchange, including reading the body;\n * - the caller's `AbortSignal` is honoured before and during the request;\n * - no automatic retries (the caller decides; see `docs/architecture.md`);\n * - credentials default to the client policy and can be overridden per request.\n */\nexport class HttpClient {\n readonly #baseUrl: string;\n readonly #fetch: FetchLike;\n readonly #timeoutMs: number;\n readonly #credentials: HttpClientOptions['credentials'];\n\n constructor(options: HttpClientOptions) {\n this.#baseUrl = options.baseUrl;\n this.#fetch = options.fetch;\n this.#timeoutMs = options.timeoutMs;\n this.#credentials = options.credentials;\n }\n\n async request<T>(request: HttpRequest<T>): Promise<HttpResponse<T>> {\n if (request.json !== undefined && request.form !== undefined) {\n throw new PixelumeConfigError('HTTP requests cannot contain both json and form bodies');\n }\n const info: PixelumeRequestInfo = { method: request.method, path: normalizePath(request.path) };\n const url = buildUrl(this.#baseUrl, request.path, request.query);\n const timeoutMs =\n request.timeoutMs === undefined ? this.#timeoutMs : validateTimeout(request.timeoutMs);\n const init: RequestInit = {\n method: request.method,\n headers: buildHeaders(request),\n credentials: request.credentials ?? this.#credentials,\n };\n if (request.json !== undefined) init.body = JSON.stringify(request.json);\n if (request.form !== undefined) init.body = new URLSearchParams(request.form).toString();\n\n const callerSignal = request.signal;\n if (callerSignal?.aborted) throw new PixelumeAbortError(info, { cause: callerSignal.reason });\n\n // Timeout and caller abort share one controller; the first abort reason wins.\n const controller = new AbortController();\n const timeoutReason = new DOMException(`Timed out after ${timeoutMs} ms`, 'TimeoutError');\n const timer = setTimeout(() => {\n controller.abort(timeoutReason);\n }, timeoutMs);\n const onCallerAbort = () => {\n controller.abort(callerSignal?.reason);\n };\n callerSignal?.addEventListener('abort', onCallerAbort, { once: true });\n // Settles on abort even if an injected `fetch` ignores the signal.\n const abortion = new Promise<never>((_, reject) => {\n controller.signal.addEventListener(\n 'abort',\n () => {\n reject(controller.signal.reason as Error);\n },\n { once: true },\n );\n });\n abortion.catch(() => undefined);\n\n // The function is invoked without a receiver on purpose: calling a browser's native `fetch`\n // with `this` bound to another object throws \"Illegal invocation\".\n const fetchFn = this.#fetch;\n let response: Response;\n let body: DecodedBody;\n try {\n const pending = Promise.resolve().then(() =>\n fetchFn(url, { ...init, signal: controller.signal }),\n );\n // Promise.race subscribes to every contender, so a losing promise that rejects later is\n // handled and never surfaces as an unhandled rejection.\n response = await Promise.race([pending, abortion]);\n body = await Promise.race([readBody(response, request.method), abortion]);\n } catch (error) {\n if (controller.signal.reason === timeoutReason) {\n throw new PixelumeTimeoutError(info, timeoutMs, { cause: error });\n }\n if (callerSignal?.aborted) {\n throw new PixelumeAbortError(info, { cause: callerSignal.reason });\n }\n throw new PixelumeNetworkError(info, { cause: error });\n } finally {\n clearTimeout(timer);\n callerSignal?.removeEventListener('abort', onCallerAbort);\n }\n\n if (!response.ok) throw toHttpError(info, response, body);\n if (body.type === 'invalid_json') {\n throw new PixelumeInvalidResponseError(info, response.status, 'body is not valid JSON');\n }\n const parsed = request.parse(body.value);\n if (!parsed.ok) throw new PixelumeInvalidResponseError(info, response.status, parsed.reason);\n return { status: response.status, headers: response.headers, data: parsed.value };\n }\n}\n\nfunction buildHeaders(request: HttpRequest<unknown>): Headers {\n const headers = new Headers({ accept: 'application/json' });\n for (const [name, value] of Object.entries(request.headers ?? {})) {\n if (RESERVED_HEADERS.has(name.toLowerCase())) {\n throw new PixelumeConfigError(`Header \"${name}\" is managed by the runtime and cannot be set`);\n }\n headers.set(name, value);\n }\n if (request.json !== undefined) headers.set('content-type', 'application/json');\n if (request.form !== undefined) {\n headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');\n }\n return headers;\n}\n\nasync function readBody(response: Response, method: HttpMethod): Promise<DecodedBody> {\n if (method === 'HEAD' || [204, 205, 304].includes(response.status)) {\n return { type: 'empty', value: undefined };\n }\n const text = await response.text();\n if (text === '') return { type: 'empty', value: undefined };\n if (!isJsonContentType(response.headers.get('content-type')))\n return { type: 'text', value: text };\n try {\n return { type: 'json', value: JSON.parse(text) as unknown };\n } catch {\n return { type: 'invalid_json', value: text };\n }\n}\n\nfunction isJsonContentType(contentType: string | null): boolean {\n const mediaType = contentType?.split(';')[0]?.trim().toLowerCase() ?? '';\n return mediaType === 'application/json' || mediaType.endsWith('+json');\n}\n\nfunction toHttpError(\n info: PixelumeRequestInfo,\n response: Response,\n body: DecodedBody,\n): PixelumeHttpError {\n const envelope = body.type === 'json' ? parseErrorEnvelope(body.value) : null;\n return new PixelumeHttpError({\n request: info,\n status: response.status,\n code: envelope?.error.code ?? null,\n apiMessage: envelope?.error.message ?? null,\n requestId: envelope?.error.requestId ?? response.headers.get('x-request-id'),\n details: envelope?.error.details ?? null,\n payload: body.value,\n });\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  export { PixelumeClient, Pixelume } from './core/PixelumeClient.js';
2
2
  export { DEFAULT_API_URL, DEFAULT_AUTH_URL, DEFAULT_TIMEOUT_MS } from './core/config.js';
3
3
  export { SDK_VERSION } from './version.js';
4
- export { PixelumeError, PixelumeConfigError, PixelumeAuthError, PixelumeRequestError, PixelumeHttpError, PixelumeNetworkError, PixelumeTimeoutError, PixelumeAbortError, PixelumeInvalidResponseError, isPixelumeError, } from './core/errors.js';
5
- export type { PixelumeErrorKind, PixelumeApiErrorCode, PixelumeAuthErrorReason, PixelumeRequestInfo, } from './core/errors.js';
6
- export type { PixelumeClientOptions, PixelumeClientConfig, PixelumeRequestOptions, PixelumeCredentialsPolicy, PixelumeFetch, PixelumeBrowserAdapter, PixelumeSessionStorage, } from './core/types.js';
4
+ export { PixelumeError, PixelumeConfigError, PixelumeAuthError, PixelumeRequestError, PixelumeHttpError, PixelumeNetworkError, PixelumeTimeoutError, PixelumeAbortError, PixelumeInvalidResponseError, PixelumeSaveConflictError, isPixelumeError, } from './core/errors.js';
5
+ export type { PixelumeErrorKind, PixelumeApiErrorCode, PixelumeAuthErrorReason, PixelumeRequestInfo, PixelumeSaveMetadata, } from './core/errors.js';
6
+ export type { PixelumeClientOptions, PixelumeClientConfig, PixelumeRequestOptions, PixelumeCredentialsPolicy, PixelumeFetch, PixelumeBrowserAdapter, PixelumeSessionStorage, PixelumeCrossSessionRestoreOptions, } from './core/types.js';
7
7
  export type { PixelumeHealthApi, PixelumeHealthStatus, PixelumeRegistrationMode, } from './modules/health/HealthModule.js';
8
- export type { PixelumeAuthApi, PixelumeAuthState, PixelumeAuthListener, PixelumeAnonymousReason, PixelumeLoginOptions, PixelumePlayer, } from './modules/auth/AuthModule.js';
8
+ export type { PixelumeAuthApi, PixelumeAuthState, PixelumeAuthListener, PixelumeAnonymousReason, PixelumeLoginOptions, PixelumePlayer, PixelumeScopeRequest, } from './modules/auth/AuthModule.js';
9
+ export type { PixelumeScope, PixelumeSessionState, PixelumeSessionListener, } from './modules/auth/SessionManager.js';
10
+ export type { PixelumeSavesApi, PixelumeSave, PixelumeSaveList, PixelumeSaveWrite, PixelumeSaveResult, PixelumeSaveDeleteOptions, PixelumeSaveDeleteResult, PixelumeSavesActivity, PixelumeSavesListener, PixelumeSavesOperation, } from './modules/saves/SavesModule.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { PixelumeClient, Pixelume } from './core/PixelumeClient.js';
2
2
  export { DEFAULT_API_URL, DEFAULT_AUTH_URL, DEFAULT_TIMEOUT_MS } from './core/config.js';
3
3
  export { SDK_VERSION } from './version.js';
4
- export { PixelumeError, PixelumeConfigError, PixelumeAuthError, PixelumeRequestError, PixelumeHttpError, PixelumeNetworkError, PixelumeTimeoutError, PixelumeAbortError, PixelumeInvalidResponseError, isPixelumeError, } from './core/errors.js';
4
+ export { PixelumeError, PixelumeConfigError, PixelumeAuthError, PixelumeRequestError, PixelumeHttpError, PixelumeNetworkError, PixelumeTimeoutError, PixelumeAbortError, PixelumeInvalidResponseError, PixelumeSaveConflictError, isPixelumeError, } from './core/errors.js';
5
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,4BAA4B,EAC5B,eAAe,GAChB,MAAM,kBAAkB,CAAC","sourcesContent":["export { PixelumeClient, Pixelume } from './core/PixelumeClient.js';\nexport { DEFAULT_API_URL, DEFAULT_AUTH_URL, DEFAULT_TIMEOUT_MS } from './core/config.js';\nexport { SDK_VERSION } from './version.js';\nexport {\n PixelumeError,\n PixelumeConfigError,\n PixelumeAuthError,\n PixelumeRequestError,\n PixelumeHttpError,\n PixelumeNetworkError,\n PixelumeTimeoutError,\n PixelumeAbortError,\n PixelumeInvalidResponseError,\n isPixelumeError,\n} from './core/errors.js';\nexport type {\n PixelumeErrorKind,\n PixelumeApiErrorCode,\n PixelumeAuthErrorReason,\n PixelumeRequestInfo,\n} from './core/errors.js';\nexport type {\n PixelumeClientOptions,\n PixelumeClientConfig,\n PixelumeRequestOptions,\n PixelumeCredentialsPolicy,\n PixelumeFetch,\n PixelumeBrowserAdapter,\n PixelumeSessionStorage,\n} from './core/types.js';\nexport type {\n PixelumeHealthApi,\n PixelumeHealthStatus,\n PixelumeRegistrationMode,\n} from './modules/health/HealthModule.js';\nexport type {\n PixelumeAuthApi,\n PixelumeAuthState,\n PixelumeAuthListener,\n PixelumeAnonymousReason,\n PixelumeLoginOptions,\n PixelumePlayer,\n} from './modules/auth/AuthModule.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,4BAA4B,EAC5B,yBAAyB,EACzB,eAAe,GAChB,MAAM,kBAAkB,CAAC","sourcesContent":["export { PixelumeClient, Pixelume } from './core/PixelumeClient.js';\nexport { DEFAULT_API_URL, DEFAULT_AUTH_URL, DEFAULT_TIMEOUT_MS } from './core/config.js';\nexport { SDK_VERSION } from './version.js';\nexport {\n PixelumeError,\n PixelumeConfigError,\n PixelumeAuthError,\n PixelumeRequestError,\n PixelumeHttpError,\n PixelumeNetworkError,\n PixelumeTimeoutError,\n PixelumeAbortError,\n PixelumeInvalidResponseError,\n PixelumeSaveConflictError,\n isPixelumeError,\n} from './core/errors.js';\nexport type {\n PixelumeErrorKind,\n PixelumeApiErrorCode,\n PixelumeAuthErrorReason,\n PixelumeRequestInfo,\n PixelumeSaveMetadata,\n} from './core/errors.js';\nexport type {\n PixelumeClientOptions,\n PixelumeClientConfig,\n PixelumeRequestOptions,\n PixelumeCredentialsPolicy,\n PixelumeFetch,\n PixelumeBrowserAdapter,\n PixelumeSessionStorage,\n PixelumeCrossSessionRestoreOptions,\n} from './core/types.js';\nexport type {\n PixelumeHealthApi,\n PixelumeHealthStatus,\n PixelumeRegistrationMode,\n} from './modules/health/HealthModule.js';\nexport type {\n PixelumeAuthApi,\n PixelumeAuthState,\n PixelumeAuthListener,\n PixelumeAnonymousReason,\n PixelumeLoginOptions,\n PixelumePlayer,\n PixelumeScopeRequest,\n} from './modules/auth/AuthModule.js';\nexport type {\n PixelumeScope,\n PixelumeSessionState,\n PixelumeSessionListener,\n} from './modules/auth/SessionManager.js';\nexport type {\n PixelumeSavesApi,\n PixelumeSave,\n PixelumeSaveList,\n PixelumeSaveWrite,\n PixelumeSaveResult,\n PixelumeSaveDeleteOptions,\n PixelumeSaveDeleteResult,\n PixelumeSavesActivity,\n PixelumeSavesListener,\n PixelumeSavesOperation,\n} from './modules/saves/SavesModule.js';\n"]}
@@ -2,21 +2,41 @@ import { type PixelumeError } from '../../core/errors.js';
2
2
  import type { PixelumeRequestOptions } from '../../core/types.js';
3
3
  import type { ResolvedConfig } from '../../core/config.js';
4
4
  import type { HttpClient } from '../../http/HttpClient.js';
5
+ import { type PixelumeSessionListener, type PixelumeSessionState } from './SessionManager.js';
5
6
  export interface PixelumePlayer {
6
7
  readonly id: string;
7
8
  readonly displayName: string;
8
9
  readonly avatarUrl: string | null;
9
10
  }
10
- export type PixelumeAnonymousReason = 'visitor' | 'cancelled' | 'expired' | 'logged_out' | 'error';
11
+ /**
12
+ * Why there is no signed-in player:
13
+ * - `visitor`: no login to restore in this tab/browser (or restoration is off). Not proof that the
14
+ * central session ended.
15
+ * - `cancelled`: the player cancelled the login in the portal.
16
+ * - `expired`: a session that was running ended (renewal refused).
17
+ * - `logged_out`: `auth.logout()`.
18
+ * - `session_ended`: a cross-session restoration attempt found no valid central session
19
+ * (`login_required`); the hint was removed and no further automatic attempt is made.
20
+ * - `offline`: a cross-session restoration could not run or finish for lack of connectivity. The
21
+ * hint is kept; the next start (or `login()`) tries again. Local progress is untouched.
22
+ * - `error`: anything else; see `error`.
23
+ */
24
+ export type PixelumeAnonymousReason = 'visitor' | 'cancelled' | 'expired' | 'logged_out' | 'session_ended' | 'offline' | 'error';
25
+ /**
26
+ * `restoring: true` marks the silent cross-session attempt (`restoreAcrossSessions`): the page is
27
+ * leaving for a brief round trip without UI, or completing it. Interactive logins omit it.
28
+ */
11
29
  export type PixelumeAuthState = {
12
30
  readonly status: 'uninitialized';
13
31
  readonly player: null;
14
32
  } | {
15
33
  readonly status: 'redirecting';
16
34
  readonly player: null;
35
+ readonly restoring?: true;
17
36
  } | {
18
37
  readonly status: 'exchanging';
19
38
  readonly player: null;
39
+ readonly restoring?: true;
20
40
  } | {
21
41
  readonly status: 'anonymous';
22
42
  readonly player: null;
@@ -27,9 +47,14 @@ export type PixelumeAuthState = {
27
47
  readonly player: PixelumePlayer;
28
48
  };
29
49
  export type PixelumeAuthListener = (state: PixelumeAuthState, previous: PixelumeAuthState) => void;
50
+ /**
51
+ * OAuth scope requested at login. `profile` identifies the player; `profile saves` also allows
52
+ * Cloud Saves and requires `saves` to be enabled for the game in the Pixelume Game Registry.
53
+ */
54
+ export type PixelumeScopeRequest = 'profile' | 'profile saves';
30
55
  export interface PixelumeLoginOptions {
31
- /** OAuth scope. The current API accepts only `profile`. */
32
- readonly scope?: 'profile';
56
+ /** Defaults to the client `scope` option (`profile` unless configured). */
57
+ readonly scope?: PixelumeScopeRequest;
33
58
  }
34
59
  export interface PixelumeAuthApi {
35
60
  /** Current synchronous authentication state. */
@@ -38,15 +63,34 @@ export interface PixelumeAuthApi {
38
63
  login(options?: PixelumeLoginOptions): Promise<void>;
39
64
  /** Returns the current player, revalidating the memory-only access token with the API. */
40
65
  getPlayer(options?: PixelumeRequestOptions): Promise<PixelumePlayer | null>;
41
- /** Revokes this game's access token and clears local authentication state. */
66
+ /**
67
+ * Revokes this game's authorization (refresh token family and access tokens) and clears local
68
+ * authentication state. The central Pixelume session in the portal is not affected.
69
+ */
42
70
  logout(options?: PixelumeRequestOptions): Promise<void>;
43
71
  /** Subscribes to state changes. The returned function removes the listener. */
44
72
  subscribe(listener: PixelumeAuthListener): () => void;
73
+ /**
74
+ * Token lifecycle of the signed-in player (scopes, expiry, renewal in flight, last transient
75
+ * renewal error). Never exposes tokens.
76
+ */
77
+ readonly session: PixelumeSessionState;
78
+ /** Subscribes to `session` changes. The returned function removes the listener. */
79
+ subscribeSession(listener: PixelumeSessionListener): () => void;
80
+ /**
81
+ * Renews the access token now. Renewal is automatic; call this only to renew ahead of a
82
+ * critical operation. Rejects with the transient error (the session is kept and retried) or
83
+ * with `PixelumeAuthError` when there is no session or it ended.
84
+ */
85
+ refresh(options?: PixelumeRequestOptions): Promise<void>;
45
86
  }
46
87
  export declare class AuthModule implements PixelumeAuthApi {
47
88
  #private;
48
89
  constructor(http: HttpClient, config: ResolvedConfig);
49
90
  get state(): PixelumeAuthState;
91
+ get session(): PixelumeSessionState;
92
+ subscribeSession(listener: PixelumeSessionListener): () => void;
93
+ refresh(options?: PixelumeRequestOptions): Promise<void>;
50
94
  initialize(): Promise<PixelumeAuthState>;
51
95
  subscribe(listener: PixelumeAuthListener): () => void;
52
96
  login(options?: PixelumeLoginOptions): Promise<void>;