@lootlog/sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -40
- package/dist/activity.d.ts +9 -2
- package/dist/activity.d.ts.map +1 -1
- package/dist/activity.js +2 -2
- package/dist/activity.js.map +1 -1
- package/dist/battlelog.d.ts +280 -5
- package/dist/battlelog.d.ts.map +1 -1
- package/dist/battlelog.js +11 -6
- package/dist/battlelog.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/main.d.ts +1457 -918
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +400 -284
- package/dist/main.js.map +1 -1
- package/dist/{mutators-Da_vMUva.d.ts → mutators-BaZDDfwh.d.ts} +2 -2
- package/dist/{mutators-Da_vMUva.d.ts.map → mutators-BaZDDfwh.d.ts.map} +1 -1
- package/dist/{mutators-CaBTxpi-.js → mutators-Dj5qBH3y.js} +2 -2
- package/dist/{mutators-CaBTxpi-.js.map → mutators-Dj5qBH3y.js.map} +1 -1
- package/dist/realtime.d.ts +427 -12
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +768 -471
- package/dist/realtime.js.map +1 -1
- package/dist/search.d.ts +247 -5
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +115 -2
- package/dist/search.js.map +1 -1
- package/dist/{transport-CIfewyM7.js → transport-Cn1V6y-o.js} +46 -8
- package/dist/transport-Cn1V6y-o.js.map +1 -0
- package/dist/{transport-BHbtsYo_.d.ts → transport-CoTymLxF.d.ts} +3 -1
- package/dist/transport-CoTymLxF.d.ts.map +1 -0
- package/openapi/activity.json +16 -1
- package/openapi/battlelog.json +805 -14
- package/openapi/main.json +5752 -4060
- package/openapi/search.json +721 -53
- package/package.json +4 -4
- package/dist/transport-BHbtsYo_.d.ts.map +0 -1
- package/dist/transport-CIfewyM7.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Predicate } from "effect";
|
|
2
|
-
|
|
2
|
+
//#region ../schema/src/records.ts
|
|
3
3
|
/** Keeps property lookup available on legacy payloads, including arrays. */
|
|
4
4
|
const isObjectRecord = (value) => Predicate.isObjectOrArray(value);
|
|
5
5
|
//#endregion
|
|
@@ -128,6 +128,7 @@ const resolveRequestConfiguration = (service, override, path) => {
|
|
|
128
128
|
baseUrl,
|
|
129
129
|
credentials: override?.credentials ?? serviceConfiguration?.credentials,
|
|
130
130
|
fetch: fetchImplementation,
|
|
131
|
+
timeoutMs: override?.timeoutMs ?? serviceConfiguration?.timeoutMs,
|
|
131
132
|
getHeaders: override?.getHeaders ?? serviceConfiguration?.getHeaders,
|
|
132
133
|
onError: override?.onError ?? serviceConfiguration?.onError
|
|
133
134
|
};
|
|
@@ -141,16 +142,54 @@ const notifyError = (onError, error, service) => {
|
|
|
141
142
|
});
|
|
142
143
|
} catch {}
|
|
143
144
|
};
|
|
144
|
-
const
|
|
145
|
+
const withRequestTimeout = async (execute, callerSignal, timeoutMs) => {
|
|
146
|
+
const controller = new AbortController();
|
|
147
|
+
let timeout;
|
|
148
|
+
let cancel;
|
|
149
|
+
const interrupted = new Promise((_resolve, reject) => {
|
|
150
|
+
cancel = () => {
|
|
151
|
+
controller.abort(callerSignal?.reason);
|
|
152
|
+
reject(controller.signal.reason);
|
|
153
|
+
};
|
|
154
|
+
if (callerSignal?.aborted) {
|
|
155
|
+
cancel();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
callerSignal?.addEventListener("abort", cancel, { once: true });
|
|
159
|
+
timeout = setTimeout(() => {
|
|
160
|
+
controller.abort(new DOMException("API request timed out", "TimeoutError"));
|
|
161
|
+
reject(controller.signal.reason);
|
|
162
|
+
}, timeoutMs);
|
|
163
|
+
});
|
|
164
|
+
try {
|
|
165
|
+
if (controller.signal.aborted) return await interrupted;
|
|
166
|
+
return await Promise.race([execute(controller.signal), interrupted]);
|
|
167
|
+
} finally {
|
|
168
|
+
clearTimeout(timeout);
|
|
169
|
+
if (cancel) callerSignal?.removeEventListener("abort", cancel);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const executeRequest = async ({ configuration, headers, method, requestInit, service, url }) => {
|
|
145
173
|
try {
|
|
146
174
|
const requestOptions = {
|
|
147
175
|
...requestInit,
|
|
148
176
|
credentials: requestInit.credentials ?? configuration.credentials,
|
|
149
177
|
headers
|
|
150
178
|
};
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
179
|
+
const fetchAndRead = async (signal) => {
|
|
180
|
+
const fetchImplementation = configuration.fetch;
|
|
181
|
+
const options = {
|
|
182
|
+
...requestOptions,
|
|
183
|
+
signal
|
|
184
|
+
};
|
|
185
|
+
const response = fetchImplementation ? await fetchImplementation.call(globalThis, url, options) : await fetch(url, options);
|
|
186
|
+
return {
|
|
187
|
+
response,
|
|
188
|
+
data: await parseResponse(response)
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
if (configuration.timeoutMs !== void 0) return await withRequestTimeout(fetchAndRead, requestInit.signal, configuration.timeoutMs);
|
|
192
|
+
return await fetchAndRead(requestInit.signal);
|
|
154
193
|
} catch (caughtError) {
|
|
155
194
|
const error = new ApiError({
|
|
156
195
|
cause: caughtError,
|
|
@@ -174,7 +213,7 @@ const executeApiRequest = async (service, path, options = {}) => {
|
|
|
174
213
|
headers.set(key, value);
|
|
175
214
|
});
|
|
176
215
|
const method = requestInit.method ?? "GET";
|
|
177
|
-
const response = await
|
|
216
|
+
const { response, data } = await executeRequest({
|
|
178
217
|
configuration,
|
|
179
218
|
headers,
|
|
180
219
|
method,
|
|
@@ -182,7 +221,6 @@ const executeApiRequest = async (service, path, options = {}) => {
|
|
|
182
221
|
service,
|
|
183
222
|
url
|
|
184
223
|
});
|
|
185
|
-
const data = await parseResponse(response);
|
|
186
224
|
if (!response.ok) {
|
|
187
225
|
const error = new ApiError({
|
|
188
226
|
data,
|
|
@@ -199,4 +237,4 @@ const executeApiRequest = async (service, path, options = {}) => {
|
|
|
199
237
|
//#endregion
|
|
200
238
|
export { executeApiRequest as n, configureApiClients as t };
|
|
201
239
|
|
|
202
|
-
//# sourceMappingURL=transport-
|
|
240
|
+
//# sourceMappingURL=transport-Cn1V6y-o.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-Cn1V6y-o.js","names":["isObject"],"sources":["../../schema/src/records.ts","../../client/src/transport.ts"],"sourcesContent":["import { Predicate } from \"effect\";\n\n/** Keeps property lookup available on legacy payloads, including arrays. */\nexport const isObjectRecord = (\n value: unknown,\n): value is Record<string, unknown> => Predicate.isObjectOrArray(value);\n","import { Predicate } from \"effect\";\nimport { isObjectRecord as isObject } from \"@lootlog/schema/records\";\n\nconst API_SERVICES = [\n \"activity\",\n \"auth\",\n \"battlelog\",\n \"main\",\n \"search\",\n] as const;\n\nexport type ApiService = (typeof API_SERVICES)[number];\n\ntype FetchImplementation = (\n input: RequestInfo | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport type ApiRequestContext = {\n method: string;\n service: ApiService;\n url: string;\n};\n\nexport type ApiServiceConfig = {\n baseUrl: string;\n credentials?: RequestCredentials;\n fetch?: FetchImplementation;\n /** Bounds the HTTP request through completion of its response body. */\n timeoutMs?: number;\n getHeaders?: () => HeadersInit | Promise<HeadersInit>;\n onError?: (error: ApiError<unknown>, context: ApiRequestContext) => void;\n};\n\nexport type ApiClientOverride = Partial<ApiServiceConfig>;\n\nexport type ApiRequestOptions = RequestInit & {\n apiClient?: ApiClientOverride;\n};\n\nexport type ApiClientRequestOptions = ApiRequestOptions & {\n params?: RawQueryParameters;\n};\n\n// Query serialization preserves nested values and delegates scalar coercion to String.\ntype RawQueryParameters = Record<string, unknown>;\n\nexport type ApiClient = {\n get<T>(path: string, options?: ApiClientRequestOptions): Promise<T>;\n post<T>(\n path: string,\n body?: unknown,\n options?: ApiClientRequestOptions,\n ): Promise<T>;\n put<T>(\n path: string,\n body?: unknown,\n options?: ApiClientRequestOptions,\n ): Promise<T>;\n patch<T>(\n path: string,\n body?: unknown,\n options?: ApiClientRequestOptions,\n ): Promise<T>;\n delete<T>(path: string, options?: ApiClientRequestOptions): Promise<T>;\n};\n\nexport class ApiError<TData = unknown> extends Error {\n public readonly cause: unknown;\n public readonly status?: number;\n public readonly data: TData | undefined;\n public readonly url: string;\n public readonly method: string;\n\n public constructor({\n cause,\n data,\n message,\n method,\n status,\n url,\n }: {\n cause?: unknown;\n data?: TData;\n message: string;\n method: string;\n status?: number;\n url: string;\n }) {\n super(message);\n this.cause = cause;\n this.name = \"ApiError\";\n this.status = status;\n this.data = data;\n this.url = url;\n this.method = method;\n }\n}\n\nconst serviceConfigurations = new Map<ApiService, ApiServiceConfig>();\n\nconst configurationRegistrations: Array<{\n configurations: Partial<Record<ApiService, ApiServiceConfig>>;\n}> = [];\n\nconst rebuildServiceConfigurations = (): void => {\n serviceConfigurations.clear();\n\n for (const registration of configurationRegistrations) {\n for (const service of API_SERVICES) {\n const configuration = registration.configurations[service];\n\n if (configuration) {\n serviceConfigurations.set(service, configuration);\n }\n }\n }\n};\n\nexport const configureApiClients = (\n configurations: Partial<Record<ApiService, ApiServiceConfig>>,\n) => {\n const registration = { configurations };\n configurationRegistrations.push(registration);\n rebuildServiceConfigurations();\n\n let restored = false;\n\n return () => {\n if (restored) {\n return;\n }\n\n restored = true;\n const registrationIndex = configurationRegistrations.indexOf(registration);\n\n if (registrationIndex !== -1) {\n configurationRegistrations.splice(registrationIndex, 1);\n rebuildServiceConfigurations();\n }\n };\n};\n\nconst getApiMessageFromData = (data: unknown): string | undefined => {\n if (typeof data === \"string\") {\n return data.trim() || undefined;\n }\n\n if (!isObject(data)) {\n return undefined;\n }\n\n const rawMessage = data.message;\n const message = Array.isArray(rawMessage) ? rawMessage[0] : rawMessage;\n\n return typeof message === \"string\" ? message.trim() || undefined : undefined;\n};\n\nconst encodeQueryComponent = (value: string) => {\n return encodeURIComponent(value).replace(\n /[!'()*]/g,\n (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`,\n );\n};\n\nconst appendQueryValue = (\n entries: string[],\n key: string,\n value: unknown,\n ancestors: Set<object>,\n): void => {\n if (value === null || value === undefined) {\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n appendQueryValue(entries, key, item, ancestors);\n }\n\n return;\n }\n\n if (value instanceof Date) {\n entries.push(\n `${encodeQueryComponent(key)}=${encodeQueryComponent(value.toISOString())}`,\n );\n\n return;\n }\n\n if (isObject(value)) {\n if (ancestors.has(value)) {\n throw new RangeError(\"Cannot serialize circular query parameters\");\n }\n\n ancestors.add(value);\n\n for (const [nestedKey, nestedValue] of Object.entries(value)) {\n appendQueryValue(entries, `${key}[${nestedKey}]`, nestedValue, ancestors);\n }\n\n ancestors.delete(value);\n\n return;\n }\n\n entries.push(\n `${encodeQueryComponent(key)}=${encodeQueryComponent(String(value))}`,\n );\n};\n\nconst serializeQueryParams = (params: RawQueryParameters) => {\n const entries: string[] = [];\n const ancestors = new Set<object>();\n\n for (const [key, value] of Object.entries(params)) {\n appendQueryValue(entries, key, value, ancestors);\n }\n\n return entries.join(\"&\");\n};\n\nconst isAbsoluteUrl = (value: string) => {\n return /^[a-z][a-z\\d+.-]*:\\/\\//i.test(value);\n};\n\nconst buildRequestUrl = ({\n baseUrl,\n params,\n path,\n}: {\n baseUrl: string;\n params?: RawQueryParameters;\n path: string;\n}) => {\n const normalizedBaseUrl = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const normalizedPath = path.replace(/^\\/+/, \"\");\n\n const url = isAbsoluteUrl(path)\n ? new URL(path)\n : new URL(normalizedPath, normalizedBaseUrl);\n\n const query = params ? serializeQueryParams(params) : \"\";\n\n if (query) {\n url.search = query;\n }\n\n return url;\n};\n\nconst isJsonContentType = (contentType: string | null) => {\n return Boolean(\n contentType?.includes(\"application/json\") || contentType?.includes(\"+json\"),\n );\n};\n\nconst parseResponse = async (response: Response) => {\n const responseText = await response.text();\n\n if (!responseText) {\n return undefined;\n }\n\n if (!isJsonContentType(response.headers.get(\"content-type\"))) {\n return responseText;\n }\n\n try {\n const parsed: unknown = JSON.parse(responseText);\n\n return parsed;\n } catch {\n return responseText;\n }\n};\n\nconst isBinaryBody = (body: unknown): body is BodyInit => {\n return (\n typeof body === \"string\" ||\n (typeof Blob !== \"undefined\" && body instanceof Blob) ||\n (typeof FormData !== \"undefined\" && body instanceof FormData) ||\n (typeof URLSearchParams !== \"undefined\" &&\n body instanceof URLSearchParams) ||\n (typeof ArrayBuffer !== \"undefined\" && body instanceof ArrayBuffer) ||\n (typeof ArrayBuffer !== \"undefined\" && ArrayBuffer.isView(body))\n );\n};\n\nconst createRequestBody = (\n body: unknown,\n headers: Headers,\n): BodyInit | undefined => {\n if (body === undefined) {\n return undefined;\n }\n\n if (isBinaryBody(body)) {\n return body;\n }\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n\n return JSON.stringify(body);\n};\n\nconst resolveBaseUrl = (\n service: ApiService,\n override: ApiClientOverride | undefined,\n serviceConfiguration: ApiClientOverride | undefined,\n path: string,\n) => {\n const baseUrl =\n override?.baseUrl ??\n serviceConfiguration?.baseUrl ??\n (isAbsoluteUrl(path) ? new URL(path).origin : undefined);\n\n if (!baseUrl) {\n throw new Error(`Missing base URL for ${service} API request`);\n }\n\n return baseUrl;\n};\n\nconst resolveFetchImplementation = (\n service: ApiService,\n override: ApiClientOverride | undefined,\n serviceConfiguration: ApiClientOverride | undefined,\n) => {\n const fetchImplementation = override?.fetch ?? serviceConfiguration?.fetch;\n\n if (!fetchImplementation && typeof fetch === \"undefined\") {\n throw new Error(`Fetch is unavailable for ${service} API request`);\n }\n\n return fetchImplementation;\n};\n\nconst resolveRequestConfiguration = (\n service: ApiService,\n override: ApiClientOverride | undefined,\n path: string,\n) => {\n const serviceConfiguration = serviceConfigurations.get(service);\n const baseUrl = resolveBaseUrl(service, override, serviceConfiguration, path);\n\n const fetchImplementation = resolveFetchImplementation(\n service,\n override,\n serviceConfiguration,\n );\n\n return {\n baseUrl,\n credentials: override?.credentials ?? serviceConfiguration?.credentials,\n fetch: fetchImplementation,\n timeoutMs: override?.timeoutMs ?? serviceConfiguration?.timeoutMs,\n getHeaders: override?.getHeaders ?? serviceConfiguration?.getHeaders,\n onError: override?.onError ?? serviceConfiguration?.onError,\n };\n};\n\nconst notifyError = (\n onError: ApiServiceConfig[\"onError\"],\n error: ApiError<unknown>,\n service: ApiService,\n) => {\n try {\n onError?.(error, {\n method: error.method,\n service,\n url: error.url,\n });\n } catch {\n // Error observers must not replace the request error.\n }\n};\n\nconst withRequestTimeout = async <T>(\n execute: (signal: AbortSignal) => Promise<T>,\n callerSignal: AbortSignal | null | undefined,\n timeoutMs: number,\n): Promise<T> => {\n const controller = new AbortController();\n let timeout: ReturnType<typeof setTimeout> | undefined;\n let cancel: (() => void) | undefined;\n\n const interrupted = new Promise<never>((_resolve, reject) => {\n cancel = () => {\n controller.abort(callerSignal?.reason);\n reject(controller.signal.reason);\n };\n\n if (callerSignal?.aborted) {\n cancel();\n\n return;\n }\n\n callerSignal?.addEventListener(\"abort\", cancel, { once: true });\n timeout = setTimeout(() => {\n controller.abort(\n new DOMException(\"API request timed out\", \"TimeoutError\"),\n );\n reject(controller.signal.reason);\n }, timeoutMs);\n });\n\n try {\n if (controller.signal.aborted) return await interrupted;\n\n return await Promise.race([execute(controller.signal), interrupted]);\n } finally {\n clearTimeout(timeout);\n\n if (cancel) callerSignal?.removeEventListener(\"abort\", cancel);\n }\n};\n\nconst executeRequest = async ({\n configuration,\n headers,\n method,\n requestInit,\n service,\n url,\n}: {\n configuration: ReturnType<typeof resolveRequestConfiguration>;\n headers: Headers;\n method: string;\n requestInit: RequestInit;\n service: ApiService;\n url: URL;\n}) => {\n try {\n const requestOptions = {\n ...requestInit,\n credentials: requestInit.credentials ?? configuration.credentials,\n headers,\n };\n\n const fetchAndRead = async (signal: AbortSignal | null | undefined) => {\n const fetchImplementation = configuration.fetch;\n const options = { ...requestOptions, signal };\n\n const response = fetchImplementation\n ? await fetchImplementation.call(globalThis, url, options)\n : await fetch(url, options);\n\n return { response, data: await parseResponse(response) };\n };\n\n if (configuration.timeoutMs !== undefined)\n return await withRequestTimeout(\n fetchAndRead,\n requestInit.signal,\n configuration.timeoutMs,\n );\n\n return await fetchAndRead(requestInit.signal);\n } catch (caughtError) {\n const error = new ApiError({\n cause: caughtError,\n message:\n caughtError instanceof Error\n ? caughtError.message\n : \"Network request failed\",\n method,\n url: url.toString(),\n });\n\n notifyError(configuration.onError, error, service);\n throw error;\n }\n};\n\nexport const executeApiRequest = async <TData>(\n service: ApiService,\n path: string,\n options: ApiRequestOptions = {},\n): Promise<TData> => {\n const { apiClient, headers: requestHeaders, ...requestInit } = options;\n const configuration = resolveRequestConfiguration(service, apiClient, path);\n\n const url = buildRequestUrl({\n baseUrl: configuration.baseUrl,\n path,\n });\n\n const headers = new Headers(await configuration.getHeaders?.());\n\n new Headers(requestHeaders).forEach((value, key) => {\n headers.set(key, value);\n });\n\n const method = requestInit.method ?? \"GET\";\n\n const { response, data } = await executeRequest({\n configuration,\n headers,\n method,\n requestInit,\n service,\n url,\n });\n\n if (!response.ok) {\n const error = new ApiError({\n data,\n message:\n getApiMessageFromData(data) || response.statusText || \"Request failed\",\n method,\n status: response.status,\n url: url.toString(),\n });\n\n notifyError(configuration.onError, error, service);\n throw error;\n }\n\n // SAFETY: generated callers supply TData from the matching OpenAPI response contract.\n // This transport decodes content types; endpoint-specific validation belongs to the service contract.\n return data as TData;\n};\n\nconst requestWithBody = <TData>(\n service: ApiService,\n method: string,\n path: string,\n body: unknown,\n options: ApiClientRequestOptions = {},\n) => {\n try {\n const { params, ...requestOptions } = options;\n\n const configuration = resolveRequestConfiguration(\n service,\n requestOptions.apiClient,\n path,\n );\n\n const url = buildRequestUrl({\n baseUrl: configuration.baseUrl,\n params,\n path,\n });\n\n const headers = new Headers(requestOptions.headers);\n const requestBody = createRequestBody(body, headers);\n\n return executeApiRequest<TData>(service, url.toString(), {\n ...requestOptions,\n body: requestBody,\n headers,\n method,\n });\n } catch (error) {\n return Promise.reject(error);\n }\n};\n\nexport const createApiClient = (\n service: ApiService,\n overrides?: ApiClientOverride,\n): ApiClient => {\n const withOverrides = (\n options: ApiClientRequestOptions = {},\n ): ApiClientRequestOptions => ({\n ...options,\n apiClient: {\n ...overrides,\n ...options.apiClient,\n },\n });\n\n return {\n get: <TData>(path: string, options?: ApiClientRequestOptions) =>\n requestWithBody<TData>(\n service,\n \"GET\",\n path,\n undefined,\n withOverrides(options),\n ),\n post: <TData>(\n path: string,\n body?: unknown,\n options?: ApiClientRequestOptions,\n ) =>\n requestWithBody<TData>(\n service,\n \"POST\",\n path,\n body,\n withOverrides(options),\n ),\n put: <TData>(\n path: string,\n body?: unknown,\n options?: ApiClientRequestOptions,\n ) =>\n requestWithBody<TData>(\n service,\n \"PUT\",\n path,\n body,\n withOverrides(options),\n ),\n patch: <TData>(\n path: string,\n body?: unknown,\n options?: ApiClientRequestOptions,\n ) =>\n requestWithBody<TData>(\n service,\n \"PATCH\",\n path,\n body,\n withOverrides(options),\n ),\n delete: <TData>(path: string, options?: ApiClientRequestOptions) =>\n requestWithBody<TData>(\n service,\n \"DELETE\",\n path,\n undefined,\n withOverrides(options),\n ),\n };\n};\n\nexport const isApiError = (error: unknown): error is ApiError<unknown> => {\n return error instanceof ApiError;\n};\n\n/** Read a raw API error field without normalizing display text or array messages. */\nexport const getApiErrorStringField = (\n cause: unknown,\n field: \"message\" | \"code\",\n): string | undefined => {\n if (!isApiError(cause) || !isObject(cause.data)) return undefined;\n const value = cause.data[field];\n\n return typeof value === \"string\" ? value : undefined;\n};\n\nconst getApiErrorDetail = (cause: unknown, key: string) => {\n if (!isApiError(cause) || !isObject(cause.data)) return undefined;\n const details = cause.data.details;\n\n return isObject(details) ? details[key] : undefined;\n};\n\n/** Read a string from an API error's `details`, the reason's parameters. */\nexport const getApiErrorStringDetail = (\n cause: unknown,\n key: string,\n): string | undefined => {\n const value = getApiErrorDetail(cause, key);\n\n return Predicate.isString(value) ? value : undefined;\n};\n\n/** Read a finite number from an API error's `details`. */\nexport const getApiErrorNumberDetail = (\n cause: unknown,\n key: string,\n): number | undefined => {\n const value = getApiErrorDetail(cause, key);\n\n return Predicate.isNumber(value) && Number.isFinite(value)\n ? value\n : undefined;\n};\n\nexport const getApiErrorStatus = (error: unknown) => {\n if (isApiError(error)) {\n return error.status;\n }\n\n if (isObject(error) && typeof error.statusCode === \"number\") {\n return error.statusCode;\n }\n\n if (isObject(error) && typeof error.status === \"number\") {\n return error.status;\n }\n\n return undefined;\n};\n\nconst MAX_QUERY_RETRIES = 2;\n\nconst REQUEST_TIMEOUT_STATUS = 408;\n\nconst TOO_MANY_REQUESTS_STATUS = 429;\n\n/**\n * A client error is an answer, not a failure: retrying a 401, 403 or 404 only\n * repeats a request the server will reject again, and on the Game client an\n * expired session would keep re-asking the API and auth for it. Everything\n * else — a timeout, a rate limit, a server error, a dropped connection — can\n * succeed on a second attempt.\n */\nexport const isRetryableApiFailure = (cause: unknown): boolean => {\n const status = getApiErrorStatus(cause);\n\n return !(\n status !== undefined &&\n status >= 400 &&\n status < 500 &&\n status !== REQUEST_TIMEOUT_STATUS &&\n status !== TOO_MANY_REQUESTS_STATUS\n );\n};\n\nexport const shouldRetryQuery = (failureCount: number, error: Error) =>\n isRetryableApiFailure(error) && failureCount < MAX_QUERY_RETRIES;\n\nexport const getApiErrorMessage = (error: unknown) => {\n if (isApiError(error)) {\n return getApiMessageFromData(error.data) ?? error.message;\n }\n\n if (error instanceof Error && error.message.trim()) {\n return error.message;\n }\n\n return undefined;\n};\n"],"mappings":"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"}
|
|
@@ -11,6 +11,8 @@ type ApiServiceConfig = {
|
|
|
11
11
|
baseUrl: string;
|
|
12
12
|
credentials?: RequestCredentials;
|
|
13
13
|
fetch?: FetchImplementation;
|
|
14
|
+
/** Bounds the HTTP request through completion of its response body. */
|
|
15
|
+
timeoutMs?: number;
|
|
14
16
|
getHeaders?: () => HeadersInit | Promise<HeadersInit>;
|
|
15
17
|
onError?: (error: ApiError<unknown>, context: ApiRequestContext) => void;
|
|
16
18
|
};
|
|
@@ -35,4 +37,4 @@ declare class ApiError<TData = unknown> extends Error {
|
|
|
35
37
|
}
|
|
36
38
|
//#endregion
|
|
37
39
|
export { ApiServiceConfig as n, ApiRequestOptions as t };
|
|
38
|
-
//# sourceMappingURL=transport-
|
|
40
|
+
//# sourceMappingURL=transport-CoTymLxF.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-CoTymLxF.d.ts","names":[],"sources":["../../client/src/transport.ts"],"mappings":";cAGM;KAQM,qBAAqB;KAE5B,uBACH,OAAO,cAAc,KACrB,OAAO,gBACJ,QAAQ;KAED;EACV;EACA,SAAS;EACT;;KAGU;EACV;EACA,cAAc;EACd,QAAQ;;EAER;EACA,mBAAmB,cAAc,QAAQ;EACzC,WAAW,OAAO,mBAAmB,SAAS;;KAGpC,oBAAoB,QAAQ;KAE5B,oBAAoB;EAC9B,YAAY;;cA8BD,SAAS,yBAAyB;WAC7B;WACA;WACA,MAAM;WACN;WACA;EAEhB,cACE,OACA,MACA,SACA,QACA,QACA;IAEA;IACA,OAAO;IACP;IACA;IACA;IACA"}
|
package/openapi/activity.json
CHANGED
|
@@ -1129,6 +1129,16 @@
|
|
|
1129
1129
|
"type": "string"
|
|
1130
1130
|
},
|
|
1131
1131
|
"required": true
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
"name": "world",
|
|
1135
|
+
"in": "query",
|
|
1136
|
+
"schema": {
|
|
1137
|
+
"nullable": true,
|
|
1138
|
+
"type": "string",
|
|
1139
|
+
"minLength": 1
|
|
1140
|
+
},
|
|
1141
|
+
"required": false
|
|
1132
1142
|
}
|
|
1133
1143
|
],
|
|
1134
1144
|
"security": [
|
|
@@ -1213,7 +1223,7 @@
|
|
|
1213
1223
|
}
|
|
1214
1224
|
}
|
|
1215
1225
|
},
|
|
1216
|
-
"description": "An inclusive range of at most
|
|
1226
|
+
"description": "An inclusive range of at most 365 Warsaw calendar dates. Only the latest 365 days of confirmed online intervals are retained.",
|
|
1217
1227
|
"summary": "Get the signed-in user's confirmed game online time by Warsaw calendar day",
|
|
1218
1228
|
"x-lootlog-access": "read",
|
|
1219
1229
|
"x-lootlog-data": "personal"
|
|
@@ -1560,6 +1570,10 @@
|
|
|
1560
1570
|
"type": "string",
|
|
1561
1571
|
"enum": ["fresh", "stale", "unavailable"]
|
|
1562
1572
|
},
|
|
1573
|
+
"world": {
|
|
1574
|
+
"nullable": true,
|
|
1575
|
+
"type": "string"
|
|
1576
|
+
},
|
|
1563
1577
|
"days": {
|
|
1564
1578
|
"type": "array",
|
|
1565
1579
|
"items": {
|
|
@@ -1600,6 +1614,7 @@
|
|
|
1600
1614
|
"trackingStartedAt",
|
|
1601
1615
|
"lastObservedAt",
|
|
1602
1616
|
"status",
|
|
1617
|
+
"world",
|
|
1603
1618
|
"days"
|
|
1604
1619
|
]
|
|
1605
1620
|
}
|