@gpc-cli/api 1.0.3 → 1.0.5
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/index.js +15 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -493,6 +493,9 @@ function createApiClient(options) {
|
|
|
493
493
|
filePath,
|
|
494
494
|
filePath.endsWith(".png") ? "image/png" : "image/jpeg"
|
|
495
495
|
);
|
|
496
|
+
if (!data.image) {
|
|
497
|
+
throw new Error("Upload succeeded but no image data returned");
|
|
498
|
+
}
|
|
496
499
|
return data.image;
|
|
497
500
|
},
|
|
498
501
|
async delete(packageName, editId, language, imageType, imageId) {
|
|
@@ -579,7 +582,7 @@ function createApiClient(options) {
|
|
|
579
582
|
async update(packageName, productId, body, updateMask) {
|
|
580
583
|
let path = `/${packageName}/monetization/subscriptions/${productId}`;
|
|
581
584
|
if (updateMask) {
|
|
582
|
-
path +=
|
|
585
|
+
path += `?${new URLSearchParams({ updateMask }).toString()}`;
|
|
583
586
|
}
|
|
584
587
|
const { data } = await http.patch(path, body);
|
|
585
588
|
return data;
|
|
@@ -633,7 +636,7 @@ function createApiClient(options) {
|
|
|
633
636
|
async updateOffer(packageName, productId, basePlanId, offerId, body, updateMask) {
|
|
634
637
|
let path = `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`;
|
|
635
638
|
if (updateMask) {
|
|
636
|
-
path +=
|
|
639
|
+
path += `?${new URLSearchParams({ updateMask }).toString()}`;
|
|
637
640
|
}
|
|
638
641
|
const { data } = await http.patch(path, body);
|
|
639
642
|
return data;
|
|
@@ -788,6 +791,9 @@ function createApiClient(options) {
|
|
|
788
791
|
filePath,
|
|
789
792
|
"application/octet-stream"
|
|
790
793
|
);
|
|
794
|
+
if (!data.deobfuscationFile) {
|
|
795
|
+
throw new Error("Upload succeeded but no deobfuscation file data returned");
|
|
796
|
+
}
|
|
791
797
|
return data.deobfuscationFile;
|
|
792
798
|
}
|
|
793
799
|
}
|
|
@@ -923,8 +929,13 @@ function createRateLimiter(buckets) {
|
|
|
923
929
|
tokensNeeded / state.config.refillRate * state.config.refillIntervalMs
|
|
924
930
|
);
|
|
925
931
|
await new Promise((r) => setTimeout(r, waitMs));
|
|
926
|
-
|
|
927
|
-
|
|
932
|
+
const afterWait = Date.now();
|
|
933
|
+
const totalElapsed = afterWait - state.lastRefillTime;
|
|
934
|
+
const newTokens = Math.floor(
|
|
935
|
+
totalElapsed / state.config.refillIntervalMs * state.config.refillRate
|
|
936
|
+
);
|
|
937
|
+
state.tokens = Math.min(state.config.maxTokens, newTokens) - 1;
|
|
938
|
+
state.lastRefillTime = afterWait;
|
|
928
939
|
}
|
|
929
940
|
};
|
|
930
941
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http.ts","../src/errors.ts","../src/client.ts","../src/reporting-client.ts","../src/users-client.ts","../src/rate-limiter.ts","../src/paginate.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { resolve, isAbsolute } from \"node:path\";\nimport { ApiError } from \"./errors.js\";\nimport type { ApiClientOptions, ApiResponse } from \"./types.js\";\n\n/** Extract a short, safe error summary from API response body (no tokens/secrets). */\nfunction sanitizeErrorBody(body: string): string {\n try {\n const parsed = JSON.parse(body) as {\n error?: { message?: string; status?: string; code?: number };\n };\n if (parsed?.error?.message) {\n return `${parsed.error.code ?? \"?\"} ${parsed.error.status ?? \"\"}: ${parsed.error.message}`.trim();\n }\n } catch {\n // not JSON\n }\n // Truncate raw body to prevent leaking large payloads\n return body.length > 200 ? body.slice(0, 200) + \"...\" : body;\n}\n\n/** Validate upload file path to prevent path traversal. */\nfunction validateFilePath(filePath: string): string {\n const resolved = resolve(filePath);\n if (!isAbsolute(resolved)) {\n throw new ApiError(\n \"Invalid file path\",\n \"API_INVALID_PATH\",\n undefined,\n \"File path must resolve to an absolute path.\",\n );\n }\n // Block obvious traversal patterns in the original input\n if (filePath.includes(\"\\0\")) {\n throw new ApiError(\"Invalid file path: null bytes not allowed\", \"API_INVALID_PATH\");\n }\n return resolved;\n}\n\nconst BASE_URL = \"https://androidpublisher.googleapis.com/androidpublisher/v3/applications\";\n\nconst UPLOAD_BASE_URL =\n \"https://androidpublisher.googleapis.com/upload/androidpublisher/v3/applications\";\n\nexport interface HttpClient {\n get<T>(path: string, params?: Record<string, string>): Promise<ApiResponse<T>>;\n post<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n put<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n patch<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n delete<T>(path: string): Promise<ApiResponse<T>>;\n upload<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;\n}\n\nfunction envInt(name: string): number | undefined {\n const val = process.env[name];\n if (val === undefined) return undefined;\n const n = Number(val);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction resolveOption(explicit: number | undefined, envName: string, fallback: number): number {\n return explicit ?? envInt(envName) ?? fallback;\n}\n\nfunction mapStatusToError(status: number, _body: string): { code: string; suggestion?: string } {\n switch (status) {\n case 401:\n return {\n code: \"API_UNAUTHORIZED\",\n suggestion: \"Check that your access token is valid and not expired.\",\n };\n case 403:\n return {\n code: \"API_FORBIDDEN\",\n suggestion: \"Ensure the service account has the required permissions for this operation.\",\n };\n case 404:\n return {\n code: \"API_NOT_FOUND\",\n suggestion: \"Verify the package name and resource IDs are correct.\",\n };\n case 409:\n return {\n code: \"API_EDIT_CONFLICT\",\n suggestion: \"Another edit may be in progress. Delete the existing edit and retry.\",\n };\n case 429:\n return {\n code: \"API_RATE_LIMITED\",\n suggestion: \"Too many requests. The client will retry automatically.\",\n };\n default:\n if (status >= 500) {\n return {\n code: \"API_SERVER_ERROR\",\n suggestion: \"Google Play API server error. The client will retry automatically.\",\n };\n }\n return { code: `API_HTTP_${status}` };\n }\n}\n\nfunction isRetryable(status: number): boolean {\n return status === 429 || status >= 500;\n}\n\nfunction jitteredDelay(base: number, attempt: number, max: number): number {\n const exponential = base * 2 ** attempt;\n const capped = Math.min(exponential, max);\n return capped * (0.5 + Math.random() * 0.5);\n}\n\nexport function createHttpClient(options: ApiClientOptions): HttpClient {\n const maxRetries = resolveOption(options.maxRetries, \"GPC_MAX_RETRIES\", 3);\n const timeout = resolveOption(options.timeout, \"GPC_TIMEOUT\", 30_000);\n const baseDelay = resolveOption(options.baseDelay, \"GPC_BASE_DELAY\", 1_000);\n const maxDelay = resolveOption(options.maxDelay, \"GPC_MAX_DELAY\", 60_000);\n const onRetry = options.onRetry;\n\n async function request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<ApiResponse<T>> {\n let url = `${options.baseUrl ?? BASE_URL}${path}`;\n if (params) {\n const search = new URLSearchParams(params);\n url += `?${search.toString()}`;\n }\n\n // Fetch token once before retries — the auth layer handles its own caching and mutex\n let token = await options.auth.getAccessToken();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = jitteredDelay(baseDelay, attempt - 1, maxDelay);\n await new Promise((r) => setTimeout(r, delay));\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n };\n\n const init: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n keepalive: true,\n };\n\n if (body !== undefined) {\n init.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, init);\n\n if (response.ok) {\n const text = await response.text();\n const data = text ? (JSON.parse(text) as T) : ({} as T);\n return { data, status: response.status };\n }\n\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n\n const err = new ApiError(\n `${method} ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n\n if (isRetryable(response.status) && attempt < maxRetries) {\n lastError = err;\n const delay = jitteredDelay(baseDelay, attempt, maxDelay);\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n status: response.status,\n error: err.message,\n delayMs: Math.round(delay),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n\n // On 401, refresh token once before giving up\n if (response.status === 401 && attempt < maxRetries) {\n token = await options.auth.getAccessToken();\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (error) {\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const timeoutErr = new ApiError(\n `${method} ${path} timed out after ${timeout}ms`,\n \"API_TIMEOUT\",\n undefined,\n \"The request exceeded the configured timeout. Consider increasing the timeout value.\",\n );\n if (attempt < maxRetries) {\n lastError = timeoutErr;\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n error: timeoutErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw timeoutErr;\n }\n\n const networkErr = new ApiError(\n `${method} ${path} failed: ${error instanceof Error ? error.message : String(error)}`,\n \"API_NETWORK_ERROR\",\n undefined,\n \"A network error occurred. Check your internet connection.\",\n );\n if (attempt < maxRetries) {\n lastError = networkErr;\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n error: networkErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw networkErr;\n } finally {\n clearTimeout(timer);\n }\n }\n\n // Should not reach here, but just in case\n throw lastError ?? new ApiError(\"Request failed\", \"API_NETWORK_ERROR\");\n }\n\n async function uploadRequest<T>(\n path: string,\n filePath: string,\n contentType: string,\n ): Promise<ApiResponse<T>> {\n const url = `${UPLOAD_BASE_URL}${path}`;\n const safeFilePath = validateFilePath(filePath);\n const fileBuffer = await readFile(safeFilePath);\n\n // Fetch token once before retries\n let token = await options.auth.getAccessToken();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = jitteredDelay(baseDelay, attempt - 1, maxDelay);\n await new Promise((r) => setTimeout(r, delay));\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": contentType,\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: fileBuffer,\n signal: controller.signal,\n keepalive: true,\n });\n\n if (response.ok) {\n const text = await response.text();\n const data = text ? (JSON.parse(text) as T) : ({} as T);\n return { data, status: response.status };\n }\n\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n\n const err = new ApiError(\n `POST upload ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n\n if (isRetryable(response.status) && attempt < maxRetries) {\n lastError = err;\n const delay = jitteredDelay(baseDelay, attempt, maxDelay);\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n status: response.status,\n error: err.message,\n delayMs: Math.round(delay),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n\n // On 401, refresh token once before giving up\n if (response.status === 401 && attempt < maxRetries) {\n token = await options.auth.getAccessToken();\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (error) {\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const timeoutErr = new ApiError(\n `POST upload ${path} timed out after ${timeout}ms`,\n \"API_TIMEOUT\",\n undefined,\n \"The request exceeded the configured timeout. Consider increasing the timeout value.\",\n );\n if (attempt < maxRetries) {\n lastError = timeoutErr;\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n error: timeoutErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw timeoutErr;\n }\n\n const networkErr = new ApiError(\n `POST upload ${path} failed: ${error instanceof Error ? error.message : String(error)}`,\n \"API_NETWORK_ERROR\",\n undefined,\n \"A network error occurred. Check your internet connection.\",\n );\n if (attempt < maxRetries) {\n lastError = networkErr;\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n error: networkErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw networkErr;\n } finally {\n clearTimeout(timer);\n }\n }\n\n throw lastError ?? new ApiError(\"Upload request failed\", \"API_NETWORK_ERROR\");\n }\n\n return {\n get<T>(path: string, params?: Record<string, string>) {\n return request<T>(\"GET\", path, undefined, params);\n },\n post<T>(path: string, body?: unknown) {\n return request<T>(\"POST\", path, body);\n },\n put<T>(path: string, body?: unknown) {\n return request<T>(\"PUT\", path, body);\n },\n patch<T>(path: string, body?: unknown) {\n return request<T>(\"PATCH\", path, body);\n },\n delete<T>(path: string) {\n return request<T>(\"DELETE\", path);\n },\n upload<T>(path: string, filePath: string, contentType: string) {\n return uploadRequest<T>(path, filePath, contentType);\n },\n };\n}\n","export class ApiError extends Error {\n public readonly exitCode = 4;\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode?: number,\n public readonly suggestion?: string,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n toJSON() {\n return {\n success: false,\n error: {\n code: this.code,\n message: this.message,\n suggestion: this.suggestion,\n },\n };\n }\n}\n","import { createHttpClient } from \"./http.js\";\nimport type { RateLimiter } from \"./rate-limiter.js\";\nimport type {\n ApiClientOptions,\n AppDetails,\n AppEdit,\n BasePlanMigratePricesRequest,\n Bundle,\n BundleListResponse,\n ConvertRegionPricesRequest,\n ConvertRegionPricesResponse,\n CountryAvailability,\n DeobfuscationFile,\n DeobfuscationUploadResponse,\n Image,\n ImageType,\n ImageUploadResponse,\n ImagesDeleteAllResponse,\n ImagesListResponse,\n InAppProduct,\n InAppProductsListResponse,\n Listing,\n ListingsListResponse,\n OffersListResponse,\n ProductPurchase,\n Release,\n ReportsListResponse,\n ReportType,\n Review,\n ReviewReplyRequest,\n ReviewReplyResponse,\n ReviewsListOptions,\n ReviewsListResponse,\n Subscription,\n SubscriptionDeferRequest,\n SubscriptionDeferResponse,\n SubscriptionOffer,\n SubscriptionPurchase,\n SubscriptionPurchaseV2,\n SubscriptionsListResponse,\n Testers,\n Track,\n TrackListResponse,\n UploadResponse,\n VoidedPurchasesListResponse,\n} from \"./types.js\";\n\nexport interface PlayApiClient {\n edits: {\n insert(packageName: string): Promise<AppEdit>;\n get(packageName: string, editId: string): Promise<AppEdit>;\n validate(packageName: string, editId: string): Promise<AppEdit>;\n commit(packageName: string, editId: string): Promise<AppEdit>;\n delete(packageName: string, editId: string): Promise<void>;\n };\n\n details: {\n get(packageName: string, editId: string): Promise<AppDetails>;\n update(packageName: string, editId: string, details: Partial<AppDetails>): Promise<AppDetails>;\n patch(packageName: string, editId: string, partial: Partial<AppDetails>): Promise<AppDetails>;\n };\n\n bundles: {\n list(packageName: string, editId: string): Promise<Bundle[]>;\n upload(packageName: string, editId: string, filePath: string): Promise<Bundle>;\n };\n\n tracks: {\n list(packageName: string, editId: string): Promise<Track[]>;\n get(packageName: string, editId: string, track: string): Promise<Track>;\n update(packageName: string, editId: string, track: string, release: Release): Promise<Track>;\n };\n\n listings: {\n list(packageName: string, editId: string): Promise<Listing[]>;\n get(packageName: string, editId: string, language: string): Promise<Listing>;\n update(\n packageName: string,\n editId: string,\n language: string,\n listing: Omit<Listing, \"language\">,\n ): Promise<Listing>;\n patch(\n packageName: string,\n editId: string,\n language: string,\n partial: Partial<Omit<Listing, \"language\">>,\n ): Promise<Listing>;\n delete(packageName: string, editId: string, language: string): Promise<void>;\n deleteAll(packageName: string, editId: string): Promise<void>;\n };\n\n images: {\n list(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n ): Promise<Image[]>;\n upload(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n filePath: string,\n ): Promise<Image>;\n delete(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n imageId: string,\n ): Promise<void>;\n deleteAll(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n ): Promise<Image[]>;\n };\n\n countryAvailability: {\n get(packageName: string, editId: string, track: string): Promise<CountryAvailability>;\n };\n\n reviews: {\n list(packageName: string, options?: ReviewsListOptions): Promise<ReviewsListResponse>;\n get(packageName: string, reviewId: string, translationLanguage?: string): Promise<Review>;\n reply(packageName: string, reviewId: string, replyText: string): Promise<ReviewReplyResponse>;\n };\n\n subscriptions: {\n list(\n packageName: string,\n options?: { pageToken?: string; pageSize?: number },\n ): Promise<SubscriptionsListResponse>;\n get(packageName: string, productId: string): Promise<Subscription>;\n create(packageName: string, data: Subscription): Promise<Subscription>;\n update(\n packageName: string,\n productId: string,\n data: Subscription,\n updateMask?: string,\n ): Promise<Subscription>;\n delete(packageName: string, productId: string): Promise<void>;\n activateBasePlan(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<Subscription>;\n deactivateBasePlan(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<Subscription>;\n deleteBasePlan(packageName: string, productId: string, basePlanId: string): Promise<void>;\n migratePrices(\n packageName: string,\n productId: string,\n basePlanId: string,\n body: BasePlanMigratePricesRequest,\n ): Promise<Subscription>;\n listOffers(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<OffersListResponse>;\n getOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n createOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n data: SubscriptionOffer,\n ): Promise<SubscriptionOffer>;\n updateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n data: SubscriptionOffer,\n updateMask?: string,\n ): Promise<SubscriptionOffer>;\n deleteOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<void>;\n activateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n deactivateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n };\n\n inappproducts: {\n list(\n packageName: string,\n options?: { token?: string; maxResults?: number },\n ): Promise<InAppProductsListResponse>;\n get(packageName: string, sku: string): Promise<InAppProduct>;\n create(packageName: string, data: InAppProduct): Promise<InAppProduct>;\n update(packageName: string, sku: string, data: InAppProduct): Promise<InAppProduct>;\n delete(packageName: string, sku: string): Promise<void>;\n };\n\n purchases: {\n getProduct(packageName: string, productId: string, token: string): Promise<ProductPurchase>;\n acknowledgeProduct(\n packageName: string,\n productId: string,\n token: string,\n body?: { developerPayload?: string },\n ): Promise<void>;\n consumeProduct(packageName: string, productId: string, token: string): Promise<void>;\n getSubscriptionV2(packageName: string, token: string): Promise<SubscriptionPurchaseV2>;\n getSubscriptionV1(\n packageName: string,\n subscriptionId: string,\n token: string,\n ): Promise<SubscriptionPurchase>;\n cancelSubscription(packageName: string, subscriptionId: string, token: string): Promise<void>;\n deferSubscription(\n packageName: string,\n subscriptionId: string,\n token: string,\n body: SubscriptionDeferRequest,\n ): Promise<SubscriptionDeferResponse>;\n revokeSubscriptionV2(packageName: string, token: string): Promise<void>;\n listVoided(\n packageName: string,\n options?: { startTime?: string; endTime?: string; maxResults?: number; token?: string },\n ): Promise<VoidedPurchasesListResponse>;\n };\n\n orders: {\n refund(\n packageName: string,\n orderId: string,\n body?: { fullRefund?: boolean; proratedRefund?: boolean },\n ): Promise<void>;\n };\n\n monetization: {\n convertRegionPrices(\n packageName: string,\n price: ConvertRegionPricesRequest,\n ): Promise<ConvertRegionPricesResponse>;\n };\n\n reports: {\n list(\n packageName: string,\n reportType: ReportType,\n year: number,\n month: number,\n ): Promise<ReportsListResponse>;\n };\n\n testers: {\n get(packageName: string, editId: string, track: string): Promise<Testers>;\n update(packageName: string, editId: string, track: string, testers: Testers): Promise<Testers>;\n };\n\n deobfuscation: {\n upload(\n packageName: string,\n editId: string,\n versionCode: number,\n filePath: string,\n ): Promise<DeobfuscationFile>;\n };\n}\n\nasync function rateLimit(limiter: RateLimiter | undefined, bucket: string): Promise<void> {\n if (limiter) await limiter.acquire(bucket);\n}\n\nexport function createApiClient(options: ApiClientOptions): PlayApiClient {\n const http = createHttpClient(options);\n const limiter = options.rateLimiter || undefined;\n\n return {\n edits: {\n async insert(packageName) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits`);\n return data;\n },\n\n async get(packageName, editId) {\n const { data } = await http.get<AppEdit>(`/${packageName}/edits/${editId}`);\n return data;\n },\n\n async validate(packageName, editId) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits/${editId}:validate`);\n return data;\n },\n\n async commit(packageName, editId) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits/${editId}:commit`);\n return data;\n },\n\n async delete(packageName, editId) {\n await http.delete(`/${packageName}/edits/${editId}`);\n },\n },\n\n details: {\n async get(packageName, editId) {\n const { data } = await http.get<AppDetails>(`/${packageName}/edits/${editId}/details`);\n return data;\n },\n\n async update(packageName, editId, details) {\n const { data } = await http.put<AppDetails>(\n `/${packageName}/edits/${editId}/details`,\n details,\n );\n return data;\n },\n\n async patch(packageName, editId, partial) {\n const { data } = await http.patch<AppDetails>(\n `/${packageName}/edits/${editId}/details`,\n partial,\n );\n return data;\n },\n },\n\n bundles: {\n async list(packageName, editId) {\n const { data } = await http.get<BundleListResponse>(\n `/${packageName}/edits/${editId}/bundles`,\n );\n return data.bundles;\n },\n\n async upload(packageName, editId, filePath) {\n const { data } = await http.upload<UploadResponse>(\n `/${packageName}/edits/${editId}/bundles`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data.bundle) {\n throw new Error(\"Upload succeeded but no bundle data returned\");\n }\n return data.bundle;\n },\n },\n\n tracks: {\n async list(packageName, editId) {\n const { data } = await http.get<TrackListResponse>(\n `/${packageName}/edits/${editId}/tracks`,\n );\n return data.tracks;\n },\n\n async get(packageName, editId, track) {\n const { data } = await http.get<Track>(`/${packageName}/edits/${editId}/tracks/${track}`);\n return data;\n },\n\n async update(packageName, editId, track, release) {\n const { data } = await http.put<Track>(`/${packageName}/edits/${editId}/tracks/${track}`, {\n track,\n releases: [release],\n });\n return data;\n },\n },\n\n listings: {\n async list(packageName, editId) {\n const { data } = await http.get<ListingsListResponse>(\n `/${packageName}/edits/${editId}/listings`,\n );\n return data.listings || [];\n },\n\n async get(packageName, editId, language) {\n const { data } = await http.get<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n );\n return data;\n },\n\n async update(packageName, editId, language, listing) {\n const { data } = await http.put<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n listing,\n );\n return data;\n },\n\n async patch(packageName, editId, language, partial) {\n const { data } = await http.patch<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n partial,\n );\n return data;\n },\n\n async delete(packageName, editId, language) {\n await http.delete(`/${packageName}/edits/${editId}/listings/${language}`);\n },\n\n async deleteAll(packageName, editId) {\n await http.delete(`/${packageName}/edits/${editId}/listings`);\n },\n },\n\n images: {\n async list(packageName, editId, language, imageType) {\n const { data } = await http.get<ImagesListResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n );\n return data.images || [];\n },\n\n async upload(packageName, editId, language, imageType, filePath) {\n const { data } = await http.upload<ImageUploadResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n filePath,\n filePath.endsWith(\".png\") ? \"image/png\" : \"image/jpeg\",\n );\n return data.image;\n },\n\n async delete(packageName, editId, language, imageType, imageId) {\n await http.delete(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}/${imageId}`,\n );\n },\n\n async deleteAll(packageName, editId, language, imageType) {\n const { data } = await http.delete<ImagesDeleteAllResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n );\n return data.deleted || [];\n },\n },\n\n countryAvailability: {\n async get(packageName, editId, track) {\n const { data } = await http.get<CountryAvailability>(\n `/${packageName}/edits/${editId}/countryAvailability/${track}`,\n );\n return data;\n },\n },\n\n reviews: {\n async list(packageName, options?) {\n await rateLimit(limiter, \"reviewsGet\");\n const params: Record<string, string> = {};\n if (options?.token) params[\"token\"] = options.token;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n if (options?.translationLanguage)\n params[\"translationLanguage\"] = options.translationLanguage;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<ReviewsListResponse>(\n `/${packageName}/reviews`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, reviewId, translationLanguage?) {\n await rateLimit(limiter, \"reviewsGet\");\n const params: Record<string, string> = {};\n if (translationLanguage) params[\"translationLanguage\"] = translationLanguage;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<Review>(\n `/${packageName}/reviews/${reviewId}`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async reply(packageName, reviewId, replyText) {\n await rateLimit(limiter, \"reviewsPost\");\n const body: ReviewReplyRequest = { replyText };\n const { data } = await http.post<ReviewReplyResponse>(\n `/${packageName}/reviews/${reviewId}:reply`,\n body,\n );\n return data;\n },\n },\n\n subscriptions: {\n async list(packageName, options?) {\n const params: Record<string, string> = {};\n if (options?.pageToken) params[\"pageToken\"] = options.pageToken;\n if (options?.pageSize) params[\"pageSize\"] = String(options.pageSize);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<SubscriptionsListResponse>(\n `/${packageName}/monetization/subscriptions`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, productId) {\n const { data } = await http.get<Subscription>(\n `/${packageName}/monetization/subscriptions/${productId}`,\n );\n return data;\n },\n\n async create(packageName, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions`,\n body,\n );\n return data;\n },\n\n async update(packageName, productId, body, updateMask?) {\n let path = `/${packageName}/monetization/subscriptions/${productId}`;\n if (updateMask) {\n path += `?updateMask=${encodeURIComponent(updateMask).replace(/%2C/gi, \",\")}`;\n }\n const { data } = await http.patch<Subscription>(path, body);\n return data;\n },\n\n async delete(packageName, productId) {\n await http.delete(`/${packageName}/monetization/subscriptions/${productId}`);\n },\n\n async activateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}:activate`,\n );\n return data;\n },\n\n async deactivateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}:deactivate`,\n );\n return data;\n },\n\n async deleteBasePlan(packageName, productId, basePlanId) {\n await http.delete(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}`,\n );\n },\n\n async migratePrices(packageName, productId, basePlanId, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}:migratePrices`,\n body,\n );\n return data;\n },\n\n async listOffers(packageName, productId, basePlanId) {\n const { data } = await http.get<OffersListResponse>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers`,\n );\n return data;\n },\n\n async getOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.get<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n return data;\n },\n\n async createOffer(packageName, productId, basePlanId, body) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers`,\n body,\n );\n return data;\n },\n\n async updateOffer(packageName, productId, basePlanId, offerId, body, updateMask?) {\n let path = `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`;\n if (updateMask) {\n path += `?updateMask=${encodeURIComponent(updateMask).replace(/%2C/gi, \",\")}`;\n }\n const { data } = await http.patch<SubscriptionOffer>(path, body);\n return data;\n },\n\n async deleteOffer(packageName, productId, basePlanId, offerId) {\n await http.delete(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n },\n\n async activateOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:activate`,\n );\n return data;\n },\n\n async deactivateOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:deactivate`,\n );\n return data;\n },\n },\n\n inappproducts: {\n async list(packageName, options?) {\n const params: Record<string, string> = {};\n if (options?.token) params[\"token\"] = options.token;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<InAppProductsListResponse>(\n `/${packageName}/inappproducts`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, sku) {\n const { data } = await http.get<InAppProduct>(`/${packageName}/inappproducts/${sku}`);\n return data;\n },\n\n async create(packageName, body) {\n const { data } = await http.post<InAppProduct>(`/${packageName}/inappproducts`, body);\n return data;\n },\n\n async update(packageName, sku, body) {\n const { data } = await http.put<InAppProduct>(`/${packageName}/inappproducts/${sku}`, body);\n return data;\n },\n\n async delete(packageName, sku) {\n await http.delete(`/${packageName}/inappproducts/${sku}`);\n },\n },\n\n purchases: {\n async getProduct(packageName, productId, token) {\n const { data } = await http.get<ProductPurchase>(\n `/${packageName}/purchases/products/${productId}/tokens/${token}`,\n );\n return data;\n },\n\n async acknowledgeProduct(packageName, productId, token, body?) {\n await http.post(\n `/${packageName}/purchases/products/${productId}/tokens/${token}:acknowledge`,\n body,\n );\n },\n\n async consumeProduct(packageName, productId, token) {\n await http.post(`/${packageName}/purchases/products/${productId}/tokens/${token}:consume`);\n },\n\n async getSubscriptionV2(packageName, token) {\n const { data } = await http.get<SubscriptionPurchaseV2>(\n `/${packageName}/purchases/subscriptionsv2/tokens/${token}`,\n );\n return data;\n },\n\n async getSubscriptionV1(packageName, subscriptionId, token) {\n const { data } = await http.get<SubscriptionPurchase>(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}`,\n );\n return data;\n },\n\n async cancelSubscription(packageName, subscriptionId, token) {\n await http.post(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:cancel`,\n );\n },\n\n async deferSubscription(packageName, subscriptionId, token, body) {\n const { data } = await http.post<SubscriptionDeferResponse>(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:defer`,\n body,\n );\n return data;\n },\n\n async revokeSubscriptionV2(packageName, token) {\n await http.post(`/${packageName}/purchases/subscriptionsv2/tokens/${token}:revoke`);\n },\n\n async listVoided(packageName, options?) {\n await rateLimit(limiter, \"voidedBurst\");\n await rateLimit(limiter, \"voidedDaily\");\n const params: Record<string, string> = {};\n if (options?.startTime) params[\"startTime\"] = options.startTime;\n if (options?.endTime) params[\"endTime\"] = options.endTime;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n if (options?.token) params[\"token\"] = options.token;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<VoidedPurchasesListResponse>(\n `/${packageName}/purchases/voidedpurchases`,\n hasParams ? params : undefined,\n );\n return data;\n },\n },\n\n orders: {\n async refund(packageName, orderId, body?) {\n await http.post(`/${packageName}/orders/${orderId}:refund`, body);\n },\n },\n\n monetization: {\n async convertRegionPrices(packageName, price) {\n const { data } = await http.post<ConvertRegionPricesResponse>(\n `/${packageName}/monetization/convertRegionPrices`,\n price,\n );\n return data;\n },\n },\n\n reports: {\n async list(packageName, reportType, year, month) {\n const monthStr = String(month).padStart(2, \"0\");\n const { data } = await http.get<ReportsListResponse>(\n `/${packageName}/reports/${reportType}/${year}/${monthStr}`,\n );\n return data;\n },\n },\n\n testers: {\n async get(packageName, editId, track) {\n const { data } = await http.get<Testers>(\n `/${packageName}/edits/${editId}/testers/${track}`,\n );\n return data;\n },\n\n async update(packageName, editId, track, testersData) {\n const { data } = await http.put<Testers>(\n `/${packageName}/edits/${editId}/testers/${track}`,\n testersData,\n );\n return data;\n },\n },\n\n deobfuscation: {\n async upload(packageName, editId, versionCode, filePath) {\n const { data } = await http.upload<DeobfuscationUploadResponse>(\n `/${packageName}/edits/${editId}/apks/${versionCode}/deobfuscationFiles/proguard`,\n filePath,\n \"application/octet-stream\",\n );\n return data.deobfuscationFile;\n },\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type {\n AnomalyDetectionResponse,\n ApiClientOptions,\n ErrorIssuesResponse,\n ErrorReportsResponse,\n MetricSetQuery,\n MetricSetResponse,\n VitalsMetricSet,\n} from \"./types.js\";\n\nconst REPORTING_BASE_URL = \"https://playdeveloperreporting.googleapis.com/v1beta1\";\n\nexport interface ReportingApiClient {\n queryMetricSet(\n packageName: string,\n metricSet: VitalsMetricSet,\n query: MetricSetQuery,\n ): Promise<MetricSetResponse>;\n\n getAnomalies(packageName: string): Promise<AnomalyDetectionResponse>;\n\n searchErrorIssues(\n packageName: string,\n filter?: string,\n pageSize?: number,\n pageToken?: string,\n ): Promise<ErrorIssuesResponse>;\n\n searchErrorReports(\n packageName: string,\n issueName: string,\n pageSize?: number,\n pageToken?: string,\n ): Promise<ErrorReportsResponse>;\n}\n\nexport function createReportingClient(options: ApiClientOptions): ReportingApiClient {\n const http = createHttpClient({ ...options, baseUrl: REPORTING_BASE_URL });\n\n return {\n async queryMetricSet(packageName, metricSet, query) {\n const { data } = await http.post<MetricSetResponse>(\n `/apps/${packageName}/${metricSet}:query`,\n query,\n );\n return data;\n },\n\n async getAnomalies(packageName) {\n const { data } = await http.get<AnomalyDetectionResponse>(`/apps/${packageName}/anomalies`);\n return data;\n },\n\n async searchErrorIssues(packageName, filter?, pageSize?, pageToken?) {\n const params: Record<string, string> = {};\n if (filter) params[\"filter\"] = filter;\n if (pageSize) params[\"pageSize\"] = String(pageSize);\n if (pageToken) params[\"pageToken\"] = pageToken;\n const { data } = await http.get<ErrorIssuesResponse>(\n `/apps/${packageName}/errorIssues:search`,\n params,\n );\n return data;\n },\n\n async searchErrorReports(packageName, issueName, pageSize?, pageToken?) {\n const params: Record<string, string> = {};\n if (pageSize) params[\"pageSize\"] = String(pageSize);\n if (pageToken) params[\"pageToken\"] = pageToken;\n const { data } = await http.get<ErrorReportsResponse>(\n `/apps/${packageName}/errorIssues/${issueName}/reports`,\n params,\n );\n return data;\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type { ApiClientOptions, User, UsersListResponse } from \"./types.js\";\n\nconst USERS_BASE_URL = \"https://androidpublisher.googleapis.com/androidpublisher/v3/developers\";\n\nexport interface UsersApiClient {\n list(\n developerId: string,\n options?: { pageToken?: string; pageSize?: number },\n ): Promise<UsersListResponse>;\n\n get(developerId: string, userId: string): Promise<User>;\n\n create(developerId: string, user: Partial<User>): Promise<User>;\n\n update(\n developerId: string,\n userId: string,\n user: Partial<User>,\n updateMask?: string,\n ): Promise<User>;\n\n delete(developerId: string, userId: string): Promise<void>;\n}\n\nexport function createUsersClient(options: ApiClientOptions): UsersApiClient {\n const http = createHttpClient({ ...options, baseUrl: USERS_BASE_URL });\n\n return {\n async list(developerId, listOptions?) {\n const params: Record<string, string> = {};\n if (listOptions?.pageToken) params[\"pageToken\"] = listOptions.pageToken;\n if (listOptions?.pageSize) params[\"pageSize\"] = String(listOptions.pageSize);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<UsersListResponse>(\n `/${developerId}/users`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(developerId, userId) {\n const { data } = await http.get<User>(`/${developerId}/users/${userId}`);\n return data;\n },\n\n async create(developerId, user) {\n const { data } = await http.post<User>(`/${developerId}/users`, user);\n return data;\n },\n\n async update(developerId, userId, user, updateMask?) {\n let path = `/${developerId}/users/${userId}`;\n if (updateMask) {\n path += `?updateMask=${encodeURIComponent(updateMask).replace(/%2C/gi, \",\")}`;\n }\n const { data } = await http.patch<User>(path, user);\n return data;\n },\n\n async delete(developerId, userId) {\n await http.delete(`/${developerId}/users/${userId}`);\n },\n };\n}\n","export interface RateLimitBucket {\n name: string;\n maxTokens: number;\n refillRate: number;\n refillIntervalMs: number;\n}\n\nexport interface RateLimiter {\n acquire(bucket: string): Promise<void>;\n}\n\ninterface BucketState {\n tokens: number;\n lastRefillTime: number;\n config: RateLimitBucket;\n}\n\nexport const RATE_LIMIT_BUCKETS: Record<string, RateLimitBucket> = {\n default: { name: \"default\", maxTokens: 200, refillRate: 200, refillIntervalMs: 1_000 },\n reviewsGet: { name: \"reviewsGet\", maxTokens: 200, refillRate: 200, refillIntervalMs: 3_600_000 },\n reviewsPost: {\n name: \"reviewsPost\",\n maxTokens: 2_000,\n refillRate: 2_000,\n refillIntervalMs: 86_400_000,\n },\n voidedBurst: { name: \"voidedBurst\", maxTokens: 30, refillRate: 30, refillIntervalMs: 30_000 },\n voidedDaily: {\n name: \"voidedDaily\",\n maxTokens: 6_000,\n refillRate: 6_000,\n refillIntervalMs: 86_400_000,\n },\n};\n\nexport function createRateLimiter(buckets?: RateLimitBucket[]): RateLimiter {\n const states = new Map<string, BucketState>();\n\n if (buckets) {\n for (const bucket of buckets) {\n states.set(bucket.name, {\n tokens: bucket.maxTokens,\n lastRefillTime: Date.now(),\n config: bucket,\n });\n }\n }\n\n return {\n async acquire(bucket: string): Promise<void> {\n const state = states.get(bucket);\n if (!state) return;\n\n const now = Date.now();\n const elapsed = now - state.lastRefillTime;\n const refill = Math.floor(\n (elapsed / state.config.refillIntervalMs) * state.config.refillRate,\n );\n\n if (refill > 0) {\n state.tokens = Math.min(state.config.maxTokens, state.tokens + refill);\n state.lastRefillTime = now;\n }\n\n if (state.tokens > 0) {\n state.tokens--;\n return;\n }\n\n const tokensNeeded = 1;\n const waitMs = Math.ceil(\n (tokensNeeded / state.config.refillRate) * state.config.refillIntervalMs,\n );\n await new Promise((r) => setTimeout(r, waitMs));\n\n state.tokens = state.config.refillRate - 1;\n state.lastRefillTime = Date.now();\n },\n };\n}\n","export interface PaginateOptions {\n limit?: number;\n startPageToken?: string;\n}\n\nexport async function* paginate<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n options?: PaginateOptions,\n): AsyncGenerator<TItem[], void, unknown> {\n let pageToken = options?.startPageToken;\n let collected = 0;\n const limit = options?.limit;\n\n for (;;) {\n if (limit !== undefined && collected >= limit) break;\n\n const page = await fetchPage(pageToken);\n const items = page.items;\n\n if (items.length === 0) break;\n\n if (limit !== undefined) {\n const remaining = limit - collected;\n if (items.length > remaining) {\n yield items.slice(0, remaining);\n return;\n }\n }\n\n yield items;\n collected += items.length;\n pageToken = page.nextPageToken;\n\n if (!pageToken) break;\n }\n}\n\nexport async function paginateAll<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n options?: PaginateOptions,\n): Promise<{ items: TItem[]; nextPageToken?: string }> {\n const allItems: TItem[] = [];\n let lastPageToken: string | undefined;\n const limit = options?.limit;\n\n for await (const items of paginate(fetchPage, options)) {\n allItems.push(...items);\n if (limit !== undefined && allItems.length >= limit) break;\n }\n\n // If we stopped due to limit, try to get the next page token for resumption\n if (limit !== undefined && allItems.length >= limit) {\n lastPageToken = undefined; // Already truncated by paginate\n }\n\n return { items: allItems, nextPageToken: lastPageToken };\n}\n\n/**\n * Fetch multiple known pages in parallel.\n * Useful when page tokens are predictable or when pre-fetching subsequent pages\n * after an initial sequential fetch reveals the token pattern.\n *\n * @param fetchPage - Function that fetches a page given a token\n * @param pageTokens - Array of page tokens to fetch concurrently\n * @param concurrency - Max concurrent requests (default: 4)\n */\nexport async function paginateParallel<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n pageTokens: string[],\n concurrency = 4,\n): Promise<{ items: TItem[]; nextPageToken?: string }> {\n const allItems: TItem[] = [];\n let lastNextPageToken: string | undefined;\n\n // Process in batches of `concurrency`\n for (let i = 0; i < pageTokens.length; i += concurrency) {\n const batch = pageTokens.slice(i, i + concurrency);\n const results = await Promise.all(batch.map((token) => fetchPage(token)));\n\n for (const result of results) {\n allItems.push(...result.items);\n if (result.nextPageToken) {\n lastNextPageToken = result.nextPageToken;\n }\n }\n }\n\n return { items: allItems, nextPageToken: lastNextPageToken };\n}\n"],"mappings":"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","names":["options"]}
|
|
1
|
+
{"version":3,"sources":["../src/http.ts","../src/errors.ts","../src/client.ts","../src/reporting-client.ts","../src/users-client.ts","../src/rate-limiter.ts","../src/paginate.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { resolve, isAbsolute } from \"node:path\";\nimport { ApiError } from \"./errors.js\";\nimport type { ApiClientOptions, ApiResponse } from \"./types.js\";\n\n/** Extract a short, safe error summary from API response body (no tokens/secrets). */\nfunction sanitizeErrorBody(body: string): string {\n try {\n const parsed = JSON.parse(body) as {\n error?: { message?: string; status?: string; code?: number };\n };\n if (parsed?.error?.message) {\n return `${parsed.error.code ?? \"?\"} ${parsed.error.status ?? \"\"}: ${parsed.error.message}`.trim();\n }\n } catch {\n // not JSON\n }\n // Truncate raw body to prevent leaking large payloads\n return body.length > 200 ? body.slice(0, 200) + \"...\" : body;\n}\n\n/** Validate upload file path to prevent path traversal. */\nfunction validateFilePath(filePath: string): string {\n const resolved = resolve(filePath);\n if (!isAbsolute(resolved)) {\n throw new ApiError(\n \"Invalid file path\",\n \"API_INVALID_PATH\",\n undefined,\n \"File path must resolve to an absolute path.\",\n );\n }\n // Block obvious traversal patterns in the original input\n if (filePath.includes(\"\\0\")) {\n throw new ApiError(\"Invalid file path: null bytes not allowed\", \"API_INVALID_PATH\");\n }\n return resolved;\n}\n\nconst BASE_URL = \"https://androidpublisher.googleapis.com/androidpublisher/v3/applications\";\n\nconst UPLOAD_BASE_URL =\n \"https://androidpublisher.googleapis.com/upload/androidpublisher/v3/applications\";\n\nexport interface HttpClient {\n get<T>(path: string, params?: Record<string, string>): Promise<ApiResponse<T>>;\n post<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n put<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n patch<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n delete<T>(path: string): Promise<ApiResponse<T>>;\n upload<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;\n}\n\nfunction envInt(name: string): number | undefined {\n const val = process.env[name];\n if (val === undefined) return undefined;\n const n = Number(val);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction resolveOption(explicit: number | undefined, envName: string, fallback: number): number {\n return explicit ?? envInt(envName) ?? fallback;\n}\n\nfunction mapStatusToError(status: number, _body: string): { code: string; suggestion?: string } {\n switch (status) {\n case 401:\n return {\n code: \"API_UNAUTHORIZED\",\n suggestion: \"Check that your access token is valid and not expired.\",\n };\n case 403:\n return {\n code: \"API_FORBIDDEN\",\n suggestion: \"Ensure the service account has the required permissions for this operation.\",\n };\n case 404:\n return {\n code: \"API_NOT_FOUND\",\n suggestion: \"Verify the package name and resource IDs are correct.\",\n };\n case 409:\n return {\n code: \"API_EDIT_CONFLICT\",\n suggestion: \"Another edit may be in progress. Delete the existing edit and retry.\",\n };\n case 429:\n return {\n code: \"API_RATE_LIMITED\",\n suggestion: \"Too many requests. The client will retry automatically.\",\n };\n default:\n if (status >= 500) {\n return {\n code: \"API_SERVER_ERROR\",\n suggestion: \"Google Play API server error. The client will retry automatically.\",\n };\n }\n return { code: `API_HTTP_${status}` };\n }\n}\n\nfunction isRetryable(status: number): boolean {\n return status === 429 || status >= 500;\n}\n\nfunction jitteredDelay(base: number, attempt: number, max: number): number {\n const exponential = base * 2 ** attempt;\n const capped = Math.min(exponential, max);\n return capped * (0.5 + Math.random() * 0.5);\n}\n\nexport function createHttpClient(options: ApiClientOptions): HttpClient {\n const maxRetries = resolveOption(options.maxRetries, \"GPC_MAX_RETRIES\", 3);\n const timeout = resolveOption(options.timeout, \"GPC_TIMEOUT\", 30_000);\n const baseDelay = resolveOption(options.baseDelay, \"GPC_BASE_DELAY\", 1_000);\n const maxDelay = resolveOption(options.maxDelay, \"GPC_MAX_DELAY\", 60_000);\n const onRetry = options.onRetry;\n\n async function request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<ApiResponse<T>> {\n let url = `${options.baseUrl ?? BASE_URL}${path}`;\n if (params) {\n const search = new URLSearchParams(params);\n url += `?${search.toString()}`;\n }\n\n // Fetch token once before retries — the auth layer handles its own caching and mutex\n let token = await options.auth.getAccessToken();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = jitteredDelay(baseDelay, attempt - 1, maxDelay);\n await new Promise((r) => setTimeout(r, delay));\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n };\n\n const init: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n keepalive: true,\n };\n\n if (body !== undefined) {\n init.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, init);\n\n if (response.ok) {\n const text = await response.text();\n const data = text ? (JSON.parse(text) as T) : ({} as T);\n return { data, status: response.status };\n }\n\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n\n const err = new ApiError(\n `${method} ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n\n if (isRetryable(response.status) && attempt < maxRetries) {\n lastError = err;\n const delay = jitteredDelay(baseDelay, attempt, maxDelay);\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n status: response.status,\n error: err.message,\n delayMs: Math.round(delay),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n\n // On 401, refresh token once before giving up\n if (response.status === 401 && attempt < maxRetries) {\n token = await options.auth.getAccessToken();\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (error) {\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const timeoutErr = new ApiError(\n `${method} ${path} timed out after ${timeout}ms`,\n \"API_TIMEOUT\",\n undefined,\n \"The request exceeded the configured timeout. Consider increasing the timeout value.\",\n );\n if (attempt < maxRetries) {\n lastError = timeoutErr;\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n error: timeoutErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw timeoutErr;\n }\n\n const networkErr = new ApiError(\n `${method} ${path} failed: ${error instanceof Error ? error.message : String(error)}`,\n \"API_NETWORK_ERROR\",\n undefined,\n \"A network error occurred. Check your internet connection.\",\n );\n if (attempt < maxRetries) {\n lastError = networkErr;\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n error: networkErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw networkErr;\n } finally {\n clearTimeout(timer);\n }\n }\n\n // Should not reach here, but just in case\n throw lastError ?? new ApiError(\"Request failed\", \"API_NETWORK_ERROR\");\n }\n\n async function uploadRequest<T>(\n path: string,\n filePath: string,\n contentType: string,\n ): Promise<ApiResponse<T>> {\n const url = `${UPLOAD_BASE_URL}${path}`;\n const safeFilePath = validateFilePath(filePath);\n const fileBuffer = await readFile(safeFilePath);\n\n // Fetch token once before retries\n let token = await options.auth.getAccessToken();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = jitteredDelay(baseDelay, attempt - 1, maxDelay);\n await new Promise((r) => setTimeout(r, delay));\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": contentType,\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: fileBuffer,\n signal: controller.signal,\n keepalive: true,\n });\n\n if (response.ok) {\n const text = await response.text();\n const data = text ? (JSON.parse(text) as T) : ({} as T);\n return { data, status: response.status };\n }\n\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n\n const err = new ApiError(\n `POST upload ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n\n if (isRetryable(response.status) && attempt < maxRetries) {\n lastError = err;\n const delay = jitteredDelay(baseDelay, attempt, maxDelay);\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n status: response.status,\n error: err.message,\n delayMs: Math.round(delay),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n\n // On 401, refresh token once before giving up\n if (response.status === 401 && attempt < maxRetries) {\n token = await options.auth.getAccessToken();\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (error) {\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const timeoutErr = new ApiError(\n `POST upload ${path} timed out after ${timeout}ms`,\n \"API_TIMEOUT\",\n undefined,\n \"The request exceeded the configured timeout. Consider increasing the timeout value.\",\n );\n if (attempt < maxRetries) {\n lastError = timeoutErr;\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n error: timeoutErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw timeoutErr;\n }\n\n const networkErr = new ApiError(\n `POST upload ${path} failed: ${error instanceof Error ? error.message : String(error)}`,\n \"API_NETWORK_ERROR\",\n undefined,\n \"A network error occurred. Check your internet connection.\",\n );\n if (attempt < maxRetries) {\n lastError = networkErr;\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n error: networkErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw networkErr;\n } finally {\n clearTimeout(timer);\n }\n }\n\n throw lastError ?? new ApiError(\"Upload request failed\", \"API_NETWORK_ERROR\");\n }\n\n return {\n get<T>(path: string, params?: Record<string, string>) {\n return request<T>(\"GET\", path, undefined, params);\n },\n post<T>(path: string, body?: unknown) {\n return request<T>(\"POST\", path, body);\n },\n put<T>(path: string, body?: unknown) {\n return request<T>(\"PUT\", path, body);\n },\n patch<T>(path: string, body?: unknown) {\n return request<T>(\"PATCH\", path, body);\n },\n delete<T>(path: string) {\n return request<T>(\"DELETE\", path);\n },\n upload<T>(path: string, filePath: string, contentType: string) {\n return uploadRequest<T>(path, filePath, contentType);\n },\n };\n}\n","export class ApiError extends Error {\n public readonly exitCode = 4;\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode?: number,\n public readonly suggestion?: string,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n toJSON() {\n return {\n success: false,\n error: {\n code: this.code,\n message: this.message,\n suggestion: this.suggestion,\n },\n };\n }\n}\n","import { createHttpClient } from \"./http.js\";\nimport type { RateLimiter } from \"./rate-limiter.js\";\nimport type {\n ApiClientOptions,\n AppDetails,\n AppEdit,\n BasePlanMigratePricesRequest,\n Bundle,\n BundleListResponse,\n ConvertRegionPricesRequest,\n ConvertRegionPricesResponse,\n CountryAvailability,\n DeobfuscationFile,\n DeobfuscationUploadResponse,\n Image,\n ImageType,\n ImageUploadResponse,\n ImagesDeleteAllResponse,\n ImagesListResponse,\n InAppProduct,\n InAppProductsListResponse,\n Listing,\n ListingsListResponse,\n OffersListResponse,\n ProductPurchase,\n Release,\n ReportsListResponse,\n ReportType,\n Review,\n ReviewReplyRequest,\n ReviewReplyResponse,\n ReviewsListOptions,\n ReviewsListResponse,\n Subscription,\n SubscriptionDeferRequest,\n SubscriptionDeferResponse,\n SubscriptionOffer,\n SubscriptionPurchase,\n SubscriptionPurchaseV2,\n SubscriptionsListResponse,\n Testers,\n Track,\n TrackListResponse,\n UploadResponse,\n VoidedPurchasesListResponse,\n} from \"./types.js\";\n\nexport interface PlayApiClient {\n edits: {\n insert(packageName: string): Promise<AppEdit>;\n get(packageName: string, editId: string): Promise<AppEdit>;\n validate(packageName: string, editId: string): Promise<AppEdit>;\n commit(packageName: string, editId: string): Promise<AppEdit>;\n delete(packageName: string, editId: string): Promise<void>;\n };\n\n details: {\n get(packageName: string, editId: string): Promise<AppDetails>;\n update(packageName: string, editId: string, details: Partial<AppDetails>): Promise<AppDetails>;\n patch(packageName: string, editId: string, partial: Partial<AppDetails>): Promise<AppDetails>;\n };\n\n bundles: {\n list(packageName: string, editId: string): Promise<Bundle[]>;\n upload(packageName: string, editId: string, filePath: string): Promise<Bundle>;\n };\n\n tracks: {\n list(packageName: string, editId: string): Promise<Track[]>;\n get(packageName: string, editId: string, track: string): Promise<Track>;\n update(packageName: string, editId: string, track: string, release: Release): Promise<Track>;\n };\n\n listings: {\n list(packageName: string, editId: string): Promise<Listing[]>;\n get(packageName: string, editId: string, language: string): Promise<Listing>;\n update(\n packageName: string,\n editId: string,\n language: string,\n listing: Omit<Listing, \"language\">,\n ): Promise<Listing>;\n patch(\n packageName: string,\n editId: string,\n language: string,\n partial: Partial<Omit<Listing, \"language\">>,\n ): Promise<Listing>;\n delete(packageName: string, editId: string, language: string): Promise<void>;\n deleteAll(packageName: string, editId: string): Promise<void>;\n };\n\n images: {\n list(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n ): Promise<Image[]>;\n upload(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n filePath: string,\n ): Promise<Image>;\n delete(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n imageId: string,\n ): Promise<void>;\n deleteAll(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n ): Promise<Image[]>;\n };\n\n countryAvailability: {\n get(packageName: string, editId: string, track: string): Promise<CountryAvailability>;\n };\n\n reviews: {\n list(packageName: string, options?: ReviewsListOptions): Promise<ReviewsListResponse>;\n get(packageName: string, reviewId: string, translationLanguage?: string): Promise<Review>;\n reply(packageName: string, reviewId: string, replyText: string): Promise<ReviewReplyResponse>;\n };\n\n subscriptions: {\n list(\n packageName: string,\n options?: { pageToken?: string; pageSize?: number },\n ): Promise<SubscriptionsListResponse>;\n get(packageName: string, productId: string): Promise<Subscription>;\n create(packageName: string, data: Subscription): Promise<Subscription>;\n update(\n packageName: string,\n productId: string,\n data: Subscription,\n updateMask?: string,\n ): Promise<Subscription>;\n delete(packageName: string, productId: string): Promise<void>;\n activateBasePlan(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<Subscription>;\n deactivateBasePlan(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<Subscription>;\n deleteBasePlan(packageName: string, productId: string, basePlanId: string): Promise<void>;\n migratePrices(\n packageName: string,\n productId: string,\n basePlanId: string,\n body: BasePlanMigratePricesRequest,\n ): Promise<Subscription>;\n listOffers(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<OffersListResponse>;\n getOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n createOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n data: SubscriptionOffer,\n ): Promise<SubscriptionOffer>;\n updateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n data: SubscriptionOffer,\n updateMask?: string,\n ): Promise<SubscriptionOffer>;\n deleteOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<void>;\n activateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n deactivateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n };\n\n inappproducts: {\n list(\n packageName: string,\n options?: { token?: string; maxResults?: number },\n ): Promise<InAppProductsListResponse>;\n get(packageName: string, sku: string): Promise<InAppProduct>;\n create(packageName: string, data: InAppProduct): Promise<InAppProduct>;\n update(packageName: string, sku: string, data: InAppProduct): Promise<InAppProduct>;\n delete(packageName: string, sku: string): Promise<void>;\n };\n\n purchases: {\n getProduct(packageName: string, productId: string, token: string): Promise<ProductPurchase>;\n acknowledgeProduct(\n packageName: string,\n productId: string,\n token: string,\n body?: { developerPayload?: string },\n ): Promise<void>;\n consumeProduct(packageName: string, productId: string, token: string): Promise<void>;\n getSubscriptionV2(packageName: string, token: string): Promise<SubscriptionPurchaseV2>;\n getSubscriptionV1(\n packageName: string,\n subscriptionId: string,\n token: string,\n ): Promise<SubscriptionPurchase>;\n cancelSubscription(packageName: string, subscriptionId: string, token: string): Promise<void>;\n deferSubscription(\n packageName: string,\n subscriptionId: string,\n token: string,\n body: SubscriptionDeferRequest,\n ): Promise<SubscriptionDeferResponse>;\n revokeSubscriptionV2(packageName: string, token: string): Promise<void>;\n listVoided(\n packageName: string,\n options?: { startTime?: string; endTime?: string; maxResults?: number; token?: string },\n ): Promise<VoidedPurchasesListResponse>;\n };\n\n orders: {\n refund(\n packageName: string,\n orderId: string,\n body?: { fullRefund?: boolean; proratedRefund?: boolean },\n ): Promise<void>;\n };\n\n monetization: {\n convertRegionPrices(\n packageName: string,\n price: ConvertRegionPricesRequest,\n ): Promise<ConvertRegionPricesResponse>;\n };\n\n reports: {\n list(\n packageName: string,\n reportType: ReportType,\n year: number,\n month: number,\n ): Promise<ReportsListResponse>;\n };\n\n testers: {\n get(packageName: string, editId: string, track: string): Promise<Testers>;\n update(packageName: string, editId: string, track: string, testers: Testers): Promise<Testers>;\n };\n\n deobfuscation: {\n upload(\n packageName: string,\n editId: string,\n versionCode: number,\n filePath: string,\n ): Promise<DeobfuscationFile>;\n };\n}\n\nasync function rateLimit(limiter: RateLimiter | undefined, bucket: string): Promise<void> {\n if (limiter) await limiter.acquire(bucket);\n}\n\nexport function createApiClient(options: ApiClientOptions): PlayApiClient {\n const http = createHttpClient(options);\n const limiter = options.rateLimiter || undefined;\n\n return {\n edits: {\n async insert(packageName) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits`);\n return data;\n },\n\n async get(packageName, editId) {\n const { data } = await http.get<AppEdit>(`/${packageName}/edits/${editId}`);\n return data;\n },\n\n async validate(packageName, editId) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits/${editId}:validate`);\n return data;\n },\n\n async commit(packageName, editId) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits/${editId}:commit`);\n return data;\n },\n\n async delete(packageName, editId) {\n await http.delete(`/${packageName}/edits/${editId}`);\n },\n },\n\n details: {\n async get(packageName, editId) {\n const { data } = await http.get<AppDetails>(`/${packageName}/edits/${editId}/details`);\n return data;\n },\n\n async update(packageName, editId, details) {\n const { data } = await http.put<AppDetails>(\n `/${packageName}/edits/${editId}/details`,\n details,\n );\n return data;\n },\n\n async patch(packageName, editId, partial) {\n const { data } = await http.patch<AppDetails>(\n `/${packageName}/edits/${editId}/details`,\n partial,\n );\n return data;\n },\n },\n\n bundles: {\n async list(packageName, editId) {\n const { data } = await http.get<BundleListResponse>(\n `/${packageName}/edits/${editId}/bundles`,\n );\n return data.bundles;\n },\n\n async upload(packageName, editId, filePath) {\n const { data } = await http.upload<UploadResponse>(\n `/${packageName}/edits/${editId}/bundles`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data.bundle) {\n throw new Error(\"Upload succeeded but no bundle data returned\");\n }\n return data.bundle;\n },\n },\n\n tracks: {\n async list(packageName, editId) {\n const { data } = await http.get<TrackListResponse>(\n `/${packageName}/edits/${editId}/tracks`,\n );\n return data.tracks;\n },\n\n async get(packageName, editId, track) {\n const { data } = await http.get<Track>(`/${packageName}/edits/${editId}/tracks/${track}`);\n return data;\n },\n\n async update(packageName, editId, track, release) {\n const { data } = await http.put<Track>(`/${packageName}/edits/${editId}/tracks/${track}`, {\n track,\n releases: [release],\n });\n return data;\n },\n },\n\n listings: {\n async list(packageName, editId) {\n const { data } = await http.get<ListingsListResponse>(\n `/${packageName}/edits/${editId}/listings`,\n );\n return data.listings || [];\n },\n\n async get(packageName, editId, language) {\n const { data } = await http.get<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n );\n return data;\n },\n\n async update(packageName, editId, language, listing) {\n const { data } = await http.put<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n listing,\n );\n return data;\n },\n\n async patch(packageName, editId, language, partial) {\n const { data } = await http.patch<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n partial,\n );\n return data;\n },\n\n async delete(packageName, editId, language) {\n await http.delete(`/${packageName}/edits/${editId}/listings/${language}`);\n },\n\n async deleteAll(packageName, editId) {\n await http.delete(`/${packageName}/edits/${editId}/listings`);\n },\n },\n\n images: {\n async list(packageName, editId, language, imageType) {\n const { data } = await http.get<ImagesListResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n );\n return data.images || [];\n },\n\n async upload(packageName, editId, language, imageType, filePath) {\n const { data } = await http.upload<ImageUploadResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n filePath,\n filePath.endsWith(\".png\") ? \"image/png\" : \"image/jpeg\",\n );\n if (!data.image) {\n throw new Error(\"Upload succeeded but no image data returned\");\n }\n return data.image;\n },\n\n async delete(packageName, editId, language, imageType, imageId) {\n await http.delete(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}/${imageId}`,\n );\n },\n\n async deleteAll(packageName, editId, language, imageType) {\n const { data } = await http.delete<ImagesDeleteAllResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n );\n return data.deleted || [];\n },\n },\n\n countryAvailability: {\n async get(packageName, editId, track) {\n const { data } = await http.get<CountryAvailability>(\n `/${packageName}/edits/${editId}/countryAvailability/${track}`,\n );\n return data;\n },\n },\n\n reviews: {\n async list(packageName, options?) {\n await rateLimit(limiter, \"reviewsGet\");\n const params: Record<string, string> = {};\n if (options?.token) params[\"token\"] = options.token;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n if (options?.translationLanguage)\n params[\"translationLanguage\"] = options.translationLanguage;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<ReviewsListResponse>(\n `/${packageName}/reviews`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, reviewId, translationLanguage?) {\n await rateLimit(limiter, \"reviewsGet\");\n const params: Record<string, string> = {};\n if (translationLanguage) params[\"translationLanguage\"] = translationLanguage;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<Review>(\n `/${packageName}/reviews/${reviewId}`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async reply(packageName, reviewId, replyText) {\n await rateLimit(limiter, \"reviewsPost\");\n const body: ReviewReplyRequest = { replyText };\n const { data } = await http.post<ReviewReplyResponse>(\n `/${packageName}/reviews/${reviewId}:reply`,\n body,\n );\n return data;\n },\n },\n\n subscriptions: {\n async list(packageName, options?) {\n const params: Record<string, string> = {};\n if (options?.pageToken) params[\"pageToken\"] = options.pageToken;\n if (options?.pageSize) params[\"pageSize\"] = String(options.pageSize);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<SubscriptionsListResponse>(\n `/${packageName}/monetization/subscriptions`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, productId) {\n const { data } = await http.get<Subscription>(\n `/${packageName}/monetization/subscriptions/${productId}`,\n );\n return data;\n },\n\n async create(packageName, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions`,\n body,\n );\n return data;\n },\n\n async update(packageName, productId, body, updateMask?) {\n let path = `/${packageName}/monetization/subscriptions/${productId}`;\n if (updateMask) {\n path += `?${new URLSearchParams({ updateMask }).toString()}`;\n }\n const { data } = await http.patch<Subscription>(path, body);\n return data;\n },\n\n async delete(packageName, productId) {\n await http.delete(`/${packageName}/monetization/subscriptions/${productId}`);\n },\n\n async activateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}:activate`,\n );\n return data;\n },\n\n async deactivateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}:deactivate`,\n );\n return data;\n },\n\n async deleteBasePlan(packageName, productId, basePlanId) {\n await http.delete(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}`,\n );\n },\n\n async migratePrices(packageName, productId, basePlanId, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}:migratePrices`,\n body,\n );\n return data;\n },\n\n async listOffers(packageName, productId, basePlanId) {\n const { data } = await http.get<OffersListResponse>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers`,\n );\n return data;\n },\n\n async getOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.get<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n return data;\n },\n\n async createOffer(packageName, productId, basePlanId, body) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers`,\n body,\n );\n return data;\n },\n\n async updateOffer(packageName, productId, basePlanId, offerId, body, updateMask?) {\n let path = `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`;\n if (updateMask) {\n path += `?${new URLSearchParams({ updateMask }).toString()}`;\n }\n const { data } = await http.patch<SubscriptionOffer>(path, body);\n return data;\n },\n\n async deleteOffer(packageName, productId, basePlanId, offerId) {\n await http.delete(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n },\n\n async activateOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:activate`,\n );\n return data;\n },\n\n async deactivateOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:deactivate`,\n );\n return data;\n },\n },\n\n inappproducts: {\n async list(packageName, options?) {\n const params: Record<string, string> = {};\n if (options?.token) params[\"token\"] = options.token;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<InAppProductsListResponse>(\n `/${packageName}/inappproducts`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, sku) {\n const { data } = await http.get<InAppProduct>(`/${packageName}/inappproducts/${sku}`);\n return data;\n },\n\n async create(packageName, body) {\n const { data } = await http.post<InAppProduct>(`/${packageName}/inappproducts`, body);\n return data;\n },\n\n async update(packageName, sku, body) {\n const { data } = await http.put<InAppProduct>(`/${packageName}/inappproducts/${sku}`, body);\n return data;\n },\n\n async delete(packageName, sku) {\n await http.delete(`/${packageName}/inappproducts/${sku}`);\n },\n },\n\n purchases: {\n async getProduct(packageName, productId, token) {\n const { data } = await http.get<ProductPurchase>(\n `/${packageName}/purchases/products/${productId}/tokens/${token}`,\n );\n return data;\n },\n\n async acknowledgeProduct(packageName, productId, token, body?) {\n await http.post(\n `/${packageName}/purchases/products/${productId}/tokens/${token}:acknowledge`,\n body,\n );\n },\n\n async consumeProduct(packageName, productId, token) {\n await http.post(`/${packageName}/purchases/products/${productId}/tokens/${token}:consume`);\n },\n\n async getSubscriptionV2(packageName, token) {\n const { data } = await http.get<SubscriptionPurchaseV2>(\n `/${packageName}/purchases/subscriptionsv2/tokens/${token}`,\n );\n return data;\n },\n\n async getSubscriptionV1(packageName, subscriptionId, token) {\n const { data } = await http.get<SubscriptionPurchase>(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}`,\n );\n return data;\n },\n\n async cancelSubscription(packageName, subscriptionId, token) {\n await http.post(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:cancel`,\n );\n },\n\n async deferSubscription(packageName, subscriptionId, token, body) {\n const { data } = await http.post<SubscriptionDeferResponse>(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:defer`,\n body,\n );\n return data;\n },\n\n async revokeSubscriptionV2(packageName, token) {\n await http.post(`/${packageName}/purchases/subscriptionsv2/tokens/${token}:revoke`);\n },\n\n async listVoided(packageName, options?) {\n await rateLimit(limiter, \"voidedBurst\");\n await rateLimit(limiter, \"voidedDaily\");\n const params: Record<string, string> = {};\n if (options?.startTime) params[\"startTime\"] = options.startTime;\n if (options?.endTime) params[\"endTime\"] = options.endTime;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n if (options?.token) params[\"token\"] = options.token;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<VoidedPurchasesListResponse>(\n `/${packageName}/purchases/voidedpurchases`,\n hasParams ? params : undefined,\n );\n return data;\n },\n },\n\n orders: {\n async refund(packageName, orderId, body?) {\n await http.post(`/${packageName}/orders/${orderId}:refund`, body);\n },\n },\n\n monetization: {\n async convertRegionPrices(packageName, price) {\n const { data } = await http.post<ConvertRegionPricesResponse>(\n `/${packageName}/monetization/convertRegionPrices`,\n price,\n );\n return data;\n },\n },\n\n reports: {\n async list(packageName, reportType, year, month) {\n const monthStr = String(month).padStart(2, \"0\");\n const { data } = await http.get<ReportsListResponse>(\n `/${packageName}/reports/${reportType}/${year}/${monthStr}`,\n );\n return data;\n },\n },\n\n testers: {\n async get(packageName, editId, track) {\n const { data } = await http.get<Testers>(\n `/${packageName}/edits/${editId}/testers/${track}`,\n );\n return data;\n },\n\n async update(packageName, editId, track, testersData) {\n const { data } = await http.put<Testers>(\n `/${packageName}/edits/${editId}/testers/${track}`,\n testersData,\n );\n return data;\n },\n },\n\n deobfuscation: {\n async upload(packageName, editId, versionCode, filePath) {\n const { data } = await http.upload<DeobfuscationUploadResponse>(\n `/${packageName}/edits/${editId}/apks/${versionCode}/deobfuscationFiles/proguard`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data.deobfuscationFile) {\n throw new Error(\"Upload succeeded but no deobfuscation file data returned\");\n }\n return data.deobfuscationFile;\n },\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type {\n AnomalyDetectionResponse,\n ApiClientOptions,\n ErrorIssuesResponse,\n ErrorReportsResponse,\n MetricSetQuery,\n MetricSetResponse,\n VitalsMetricSet,\n} from \"./types.js\";\n\nconst REPORTING_BASE_URL = \"https://playdeveloperreporting.googleapis.com/v1beta1\";\n\nexport interface ReportingApiClient {\n queryMetricSet(\n packageName: string,\n metricSet: VitalsMetricSet,\n query: MetricSetQuery,\n ): Promise<MetricSetResponse>;\n\n getAnomalies(packageName: string): Promise<AnomalyDetectionResponse>;\n\n searchErrorIssues(\n packageName: string,\n filter?: string,\n pageSize?: number,\n pageToken?: string,\n ): Promise<ErrorIssuesResponse>;\n\n searchErrorReports(\n packageName: string,\n issueName: string,\n pageSize?: number,\n pageToken?: string,\n ): Promise<ErrorReportsResponse>;\n}\n\nexport function createReportingClient(options: ApiClientOptions): ReportingApiClient {\n const http = createHttpClient({ ...options, baseUrl: REPORTING_BASE_URL });\n\n return {\n async queryMetricSet(packageName, metricSet, query) {\n const { data } = await http.post<MetricSetResponse>(\n `/apps/${packageName}/${metricSet}:query`,\n query,\n );\n return data;\n },\n\n async getAnomalies(packageName) {\n const { data } = await http.get<AnomalyDetectionResponse>(`/apps/${packageName}/anomalies`);\n return data;\n },\n\n async searchErrorIssues(packageName, filter?, pageSize?, pageToken?) {\n const params: Record<string, string> = {};\n if (filter) params[\"filter\"] = filter;\n if (pageSize) params[\"pageSize\"] = String(pageSize);\n if (pageToken) params[\"pageToken\"] = pageToken;\n const { data } = await http.get<ErrorIssuesResponse>(\n `/apps/${packageName}/errorIssues:search`,\n params,\n );\n return data;\n },\n\n async searchErrorReports(packageName, issueName, pageSize?, pageToken?) {\n const params: Record<string, string> = {};\n if (pageSize) params[\"pageSize\"] = String(pageSize);\n if (pageToken) params[\"pageToken\"] = pageToken;\n const { data } = await http.get<ErrorReportsResponse>(\n `/apps/${packageName}/errorIssues/${issueName}/reports`,\n params,\n );\n return data;\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type { ApiClientOptions, User, UsersListResponse } from \"./types.js\";\n\nconst USERS_BASE_URL = \"https://androidpublisher.googleapis.com/androidpublisher/v3/developers\";\n\nexport interface UsersApiClient {\n list(\n developerId: string,\n options?: { pageToken?: string; pageSize?: number },\n ): Promise<UsersListResponse>;\n\n get(developerId: string, userId: string): Promise<User>;\n\n create(developerId: string, user: Partial<User>): Promise<User>;\n\n update(\n developerId: string,\n userId: string,\n user: Partial<User>,\n updateMask?: string,\n ): Promise<User>;\n\n delete(developerId: string, userId: string): Promise<void>;\n}\n\nexport function createUsersClient(options: ApiClientOptions): UsersApiClient {\n const http = createHttpClient({ ...options, baseUrl: USERS_BASE_URL });\n\n return {\n async list(developerId, listOptions?) {\n const params: Record<string, string> = {};\n if (listOptions?.pageToken) params[\"pageToken\"] = listOptions.pageToken;\n if (listOptions?.pageSize) params[\"pageSize\"] = String(listOptions.pageSize);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<UsersListResponse>(\n `/${developerId}/users`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(developerId, userId) {\n const { data } = await http.get<User>(`/${developerId}/users/${userId}`);\n return data;\n },\n\n async create(developerId, user) {\n const { data } = await http.post<User>(`/${developerId}/users`, user);\n return data;\n },\n\n async update(developerId, userId, user, updateMask?) {\n let path = `/${developerId}/users/${userId}`;\n if (updateMask) {\n path += `?updateMask=${encodeURIComponent(updateMask).replace(/%2C/gi, \",\")}`;\n }\n const { data } = await http.patch<User>(path, user);\n return data;\n },\n\n async delete(developerId, userId) {\n await http.delete(`/${developerId}/users/${userId}`);\n },\n };\n}\n","export interface RateLimitBucket {\n name: string;\n maxTokens: number;\n refillRate: number;\n refillIntervalMs: number;\n}\n\nexport interface RateLimiter {\n acquire(bucket: string): Promise<void>;\n}\n\ninterface BucketState {\n tokens: number;\n lastRefillTime: number;\n config: RateLimitBucket;\n}\n\nexport const RATE_LIMIT_BUCKETS: Record<string, RateLimitBucket> = {\n default: { name: \"default\", maxTokens: 200, refillRate: 200, refillIntervalMs: 1_000 },\n reviewsGet: { name: \"reviewsGet\", maxTokens: 200, refillRate: 200, refillIntervalMs: 3_600_000 },\n reviewsPost: {\n name: \"reviewsPost\",\n maxTokens: 2_000,\n refillRate: 2_000,\n refillIntervalMs: 86_400_000,\n },\n voidedBurst: { name: \"voidedBurst\", maxTokens: 30, refillRate: 30, refillIntervalMs: 30_000 },\n voidedDaily: {\n name: \"voidedDaily\",\n maxTokens: 6_000,\n refillRate: 6_000,\n refillIntervalMs: 86_400_000,\n },\n};\n\nexport function createRateLimiter(buckets?: RateLimitBucket[]): RateLimiter {\n const states = new Map<string, BucketState>();\n\n if (buckets) {\n for (const bucket of buckets) {\n states.set(bucket.name, {\n tokens: bucket.maxTokens,\n lastRefillTime: Date.now(),\n config: bucket,\n });\n }\n }\n\n return {\n async acquire(bucket: string): Promise<void> {\n const state = states.get(bucket);\n if (!state) return;\n\n const now = Date.now();\n const elapsed = now - state.lastRefillTime;\n const refill = Math.floor(\n (elapsed / state.config.refillIntervalMs) * state.config.refillRate,\n );\n\n if (refill > 0) {\n state.tokens = Math.min(state.config.maxTokens, state.tokens + refill);\n state.lastRefillTime = now;\n }\n\n if (state.tokens > 0) {\n state.tokens--;\n return;\n }\n\n const tokensNeeded = 1;\n const waitMs = Math.ceil(\n (tokensNeeded / state.config.refillRate) * state.config.refillIntervalMs,\n );\n await new Promise((r) => setTimeout(r, waitMs));\n\n // Recalculate refill based on actual elapsed time since last refill\n const afterWait = Date.now();\n const totalElapsed = afterWait - state.lastRefillTime;\n const newTokens = Math.floor(\n (totalElapsed / state.config.refillIntervalMs) * state.config.refillRate,\n );\n state.tokens = Math.min(state.config.maxTokens, newTokens) - 1;\n state.lastRefillTime = afterWait;\n },\n };\n}\n","export interface PaginateOptions {\n limit?: number;\n startPageToken?: string;\n}\n\nexport async function* paginate<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n options?: PaginateOptions,\n): AsyncGenerator<TItem[], void, unknown> {\n let pageToken = options?.startPageToken;\n let collected = 0;\n const limit = options?.limit;\n\n for (;;) {\n if (limit !== undefined && collected >= limit) break;\n\n const page = await fetchPage(pageToken);\n const items = page.items;\n\n if (items.length === 0) break;\n\n if (limit !== undefined) {\n const remaining = limit - collected;\n if (items.length > remaining) {\n yield items.slice(0, remaining);\n return;\n }\n }\n\n yield items;\n collected += items.length;\n pageToken = page.nextPageToken;\n\n if (!pageToken) break;\n }\n}\n\nexport async function paginateAll<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n options?: PaginateOptions,\n): Promise<{ items: TItem[]; nextPageToken?: string }> {\n const allItems: TItem[] = [];\n let lastPageToken: string | undefined;\n const limit = options?.limit;\n\n for await (const items of paginate(fetchPage, options)) {\n allItems.push(...items);\n if (limit !== undefined && allItems.length >= limit) break;\n }\n\n // If we stopped due to limit, try to get the next page token for resumption\n if (limit !== undefined && allItems.length >= limit) {\n lastPageToken = undefined; // Already truncated by paginate\n }\n\n return { items: allItems, nextPageToken: lastPageToken };\n}\n\n/**\n * Fetch multiple known pages in parallel.\n * Useful when page tokens are predictable or when pre-fetching subsequent pages\n * after an initial sequential fetch reveals the token pattern.\n *\n * @param fetchPage - Function that fetches a page given a token\n * @param pageTokens - Array of page tokens to fetch concurrently\n * @param concurrency - Max concurrent requests (default: 4)\n */\nexport async function paginateParallel<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n pageTokens: string[],\n concurrency = 4,\n): Promise<{ items: TItem[]; nextPageToken?: string }> {\n const allItems: TItem[] = [];\n let lastNextPageToken: string | undefined;\n\n // Process in batches of `concurrency`\n for (let i = 0; i < pageTokens.length; i += concurrency) {\n const batch = pageTokens.slice(i, i + concurrency);\n const results = await Promise.all(batch.map((token) => fetchPage(token)));\n\n for (const result of results) {\n allItems.push(...result.items);\n if (result.nextPageToken) {\n lastNextPageToken = result.nextPageToken;\n }\n }\n }\n\n return { items: allItems, nextPageToken: lastNextPageToken };\n}\n"],"mappings":";AAAA,SAAS,gBAAgB;AACzB,SAAS,SAAS,kBAAkB;;;ACD7B,IAAM,WAAN,cAAuB,MAAM;AAAA,EAElC,YACE,SACgB,MACA,YACA,YAChB;AACA,UAAM,OAAO;AAJG;AACA;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EATgB,WAAW;AAAA,EAU3B,SAAS;AACP,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,QACL,MAAM,KAAK;AAAA,QACX,SAAS,KAAK;AAAA,QACd,YAAY,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;;;ADfA,SAAS,kBAAkB,MAAsB;AAC/C,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAG9B,QAAI,QAAQ,OAAO,SAAS;AAC1B,aAAO,GAAG,OAAO,MAAM,QAAQ,GAAG,IAAI,OAAO,MAAM,UAAU,EAAE,KAAK,OAAO,MAAM,OAAO,GAAG,KAAK;AAAA,IAClG;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO,KAAK,SAAS,MAAM,KAAK,MAAM,GAAG,GAAG,IAAI,QAAQ;AAC1D;AAGA,SAAS,iBAAiB,UAA0B;AAClD,QAAM,WAAW,QAAQ,QAAQ;AACjC,MAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAS,SAAS,IAAI,GAAG;AAC3B,UAAM,IAAI,SAAS,6CAA6C,kBAAkB;AAAA,EACpF;AACA,SAAO;AACT;AAEA,IAAM,WAAW;AAEjB,IAAM,kBACJ;AAWF,SAAS,OAAO,MAAkC;AAChD,QAAM,MAAM,QAAQ,IAAI,IAAI;AAC5B,MAAI,QAAQ,OAAW,QAAO;AAC9B,QAAM,IAAI,OAAO,GAAG;AACpB,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AAEA,SAAS,cAAc,UAA8B,SAAiB,UAA0B;AAC9F,SAAO,YAAY,OAAO,OAAO,KAAK;AACxC;AAEA,SAAS,iBAAiB,QAAgB,OAAsD;AAC9F,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,MACd;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,MACd;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,MACd;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,MACd;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,MACd;AAAA,IACF;AACE,UAAI,UAAU,KAAK;AACjB,eAAO;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,QACd;AAAA,MACF;AACA,aAAO,EAAE,MAAM,YAAY,MAAM,GAAG;AAAA,EACxC;AACF;AAEA,SAAS,YAAY,QAAyB;AAC5C,SAAO,WAAW,OAAO,UAAU;AACrC;AAEA,SAAS,cAAc,MAAc,SAAiB,KAAqB;AACzE,QAAM,cAAc,OAAO,KAAK;AAChC,QAAM,SAAS,KAAK,IAAI,aAAa,GAAG;AACxC,SAAO,UAAU,MAAM,KAAK,OAAO,IAAI;AACzC;AAEO,SAAS,iBAAiB,SAAuC;AACtE,QAAM,aAAa,cAAc,QAAQ,YAAY,mBAAmB,CAAC;AACzE,QAAM,UAAU,cAAc,QAAQ,SAAS,eAAe,GAAM;AACpE,QAAM,YAAY,cAAc,QAAQ,WAAW,kBAAkB,GAAK;AAC1E,QAAM,WAAW,cAAc,QAAQ,UAAU,iBAAiB,GAAM;AACxE,QAAM,UAAU,QAAQ;AAExB,iBAAe,QACb,QACA,MACA,MACA,QACyB;AACzB,QAAI,MAAM,GAAG,QAAQ,WAAW,QAAQ,GAAG,IAAI;AAC/C,QAAI,QAAQ;AACV,YAAM,SAAS,IAAI,gBAAgB,MAAM;AACzC,aAAO,IAAI,OAAO,SAAS,CAAC;AAAA,IAC9B;AAGA,QAAI,QAAQ,MAAM,QAAQ,KAAK,eAAe;AAC9C,QAAI;AAEJ,aAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACtD,UAAI,UAAU,GAAG;AACf,cAAM,QAAQ,cAAc,WAAW,UAAU,GAAG,QAAQ;AAC5D,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC;AAAA,MAC/C;AAEA,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO;AAE1D,UAAI;AACF,cAAM,UAAkC;AAAA,UACtC,eAAe,UAAU,KAAK;AAAA,UAC9B,gBAAgB;AAAA,UAChB,mBAAmB;AAAA,UACnB,YAAY;AAAA,QACd;AAEA,cAAM,OAAoB;AAAA,UACxB;AAAA,UACA;AAAA,UACA,QAAQ,WAAW;AAAA,UACnB,WAAW;AAAA,QACb;AAEA,YAAI,SAAS,QAAW;AACtB,eAAK,OAAO,KAAK,UAAU,IAAI;AAAA,QACjC;AAEA,cAAM,WAAW,MAAM,MAAM,KAAK,IAAI;AAEtC,YAAI,SAAS,IAAI;AACf,gBAAM,OAAO,MAAM,SAAS,KAAK;AACjC,gBAAM,OAAO,OAAQ,KAAK,MAAM,IAAI,IAAW,CAAC;AAChD,iBAAO,EAAE,MAAM,QAAQ,SAAS,OAAO;AAAA,QACzC;AAEA,cAAM,YAAY,MAAM,SAAS,KAAK;AACtC,cAAM,EAAE,MAAM,WAAW,IAAI,iBAAiB,SAAS,QAAQ,SAAS;AAExE,cAAM,MAAM,IAAI;AAAA,UACd,GAAG,MAAM,IAAI,IAAI,uBAAuB,SAAS,MAAM,KAAK,kBAAkB,SAAS,CAAC;AAAA,UACxF;AAAA,UACA,SAAS;AAAA,UACT;AAAA,QACF;AAEA,YAAI,YAAY,SAAS,MAAM,KAAK,UAAU,YAAY;AACxD,sBAAY;AACZ,gBAAM,QAAQ,cAAc,WAAW,SAAS,QAAQ;AACxD,oBAAU;AAAA,YACR,SAAS,UAAU;AAAA,YACnB;AAAA,YACA;AAAA,YACA,QAAQ,SAAS;AAAA,YACjB,OAAO,IAAI;AAAA,YACX,SAAS,KAAK,MAAM,KAAK;AAAA,YACzB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AACD;AAAA,QACF;AAGA,YAAI,SAAS,WAAW,OAAO,UAAU,YAAY;AACnD,kBAAQ,MAAM,QAAQ,KAAK,eAAe;AAC1C,sBAAY;AACZ;AAAA,QACF;AAEA,cAAM;AAAA,MACR,SAAS,OAAO;AACd,YAAI,iBAAiB,UAAU;AAC7B,gBAAM;AAAA,QACR;AAEA,YAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,gBAAM,aAAa,IAAI;AAAA,YACrB,GAAG,MAAM,IAAI,IAAI,oBAAoB,OAAO;AAAA,YAC5C;AAAA,YACA;AAAA,YACA;AAAA,UACF;AACA,cAAI,UAAU,YAAY;AACxB,wBAAY;AACZ,sBAAU;AAAA,cACR,SAAS,UAAU;AAAA,cACnB;AAAA,cACA;AAAA,cACA,OAAO,WAAW;AAAA,cAClB,SAAS,KAAK,MAAM,cAAc,WAAW,SAAS,QAAQ,CAAC;AAAA,cAC/D,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YACpC,CAAC;AACD;AAAA,UACF;AACA,gBAAM;AAAA,QACR;AAEA,cAAM,aAAa,IAAI;AAAA,UACrB,GAAG,MAAM,IAAI,IAAI,YAAY,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACnF;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,YAAI,UAAU,YAAY;AACxB,sBAAY;AACZ,oBAAU;AAAA,YACR,SAAS,UAAU;AAAA,YACnB;AAAA,YACA;AAAA,YACA,OAAO,WAAW;AAAA,YAClB,SAAS,KAAK,MAAM,cAAc,WAAW,SAAS,QAAQ,CAAC;AAAA,YAC/D,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AACD;AAAA,QACF;AACA,cAAM;AAAA,MACR,UAAE;AACA,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAGA,UAAM,aAAa,IAAI,SAAS,kBAAkB,mBAAmB;AAAA,EACvE;AAEA,iBAAe,cACb,MACA,UACA,aACyB;AACzB,UAAM,MAAM,GAAG,eAAe,GAAG,IAAI;AACrC,UAAM,eAAe,iBAAiB,QAAQ;AAC9C,UAAM,aAAa,MAAM,SAAS,YAAY;AAG9C,QAAI,QAAQ,MAAM,QAAQ,KAAK,eAAe;AAC9C,QAAI;AAEJ,aAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACtD,UAAI,UAAU,GAAG;AACf,cAAM,QAAQ,cAAc,WAAW,UAAU,GAAG,QAAQ;AAC5D,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC;AAAA,MAC/C;AAEA,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO;AAE1D,UAAI;AACF,cAAM,UAAkC;AAAA,UACtC,eAAe,UAAU,KAAK;AAAA,UAC9B,gBAAgB;AAAA,UAChB,mBAAmB;AAAA,UACnB,YAAY;AAAA,QACd;AAEA,cAAM,WAAW,MAAM,MAAM,KAAK;AAAA,UAChC,QAAQ;AAAA,UACR;AAAA,UACA,MAAM;AAAA,UACN,QAAQ,WAAW;AAAA,UACnB,WAAW;AAAA,QACb,CAAC;AAED,YAAI,SAAS,IAAI;AACf,gBAAM,OAAO,MAAM,SAAS,KAAK;AACjC,gBAAM,OAAO,OAAQ,KAAK,MAAM,IAAI,IAAW,CAAC;AAChD,iBAAO,EAAE,MAAM,QAAQ,SAAS,OAAO;AAAA,QACzC;AAEA,cAAM,YAAY,MAAM,SAAS,KAAK;AACtC,cAAM,EAAE,MAAM,WAAW,IAAI,iBAAiB,SAAS,QAAQ,SAAS;AAExE,cAAM,MAAM,IAAI;AAAA,UACd,eAAe,IAAI,uBAAuB,SAAS,MAAM,KAAK,kBAAkB,SAAS,CAAC;AAAA,UAC1F;AAAA,UACA,SAAS;AAAA,UACT;AAAA,QACF;AAEA,YAAI,YAAY,SAAS,MAAM,KAAK,UAAU,YAAY;AACxD,sBAAY;AACZ,gBAAM,QAAQ,cAAc,WAAW,SAAS,QAAQ;AACxD,oBAAU;AAAA,YACR,SAAS,UAAU;AAAA,YACnB,QAAQ;AAAA,YACR,MAAM,UAAU,IAAI;AAAA,YACpB,QAAQ,SAAS;AAAA,YACjB,OAAO,IAAI;AAAA,YACX,SAAS,KAAK,MAAM,KAAK;AAAA,YACzB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AACD;AAAA,QACF;AAGA,YAAI,SAAS,WAAW,OAAO,UAAU,YAAY;AACnD,kBAAQ,MAAM,QAAQ,KAAK,eAAe;AAC1C,sBAAY;AACZ;AAAA,QACF;AAEA,cAAM;AAAA,MACR,SAAS,OAAO;AACd,YAAI,iBAAiB,UAAU;AAC7B,gBAAM;AAAA,QACR;AAEA,YAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,gBAAM,aAAa,IAAI;AAAA,YACrB,eAAe,IAAI,oBAAoB,OAAO;AAAA,YAC9C;AAAA,YACA;AAAA,YACA;AAAA,UACF;AACA,cAAI,UAAU,YAAY;AACxB,wBAAY;AACZ,sBAAU;AAAA,cACR,SAAS,UAAU;AAAA,cACnB,QAAQ;AAAA,cACR,MAAM,UAAU,IAAI;AAAA,cACpB,OAAO,WAAW;AAAA,cAClB,SAAS,KAAK,MAAM,cAAc,WAAW,SAAS,QAAQ,CAAC;AAAA,cAC/D,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YACpC,CAAC;AACD;AAAA,UACF;AACA,gBAAM;AAAA,QACR;AAEA,cAAM,aAAa,IAAI;AAAA,UACrB,eAAe,IAAI,YAAY,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACrF;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,YAAI,UAAU,YAAY;AACxB,sBAAY;AACZ,oBAAU;AAAA,YACR,SAAS,UAAU;AAAA,YACnB,QAAQ;AAAA,YACR,MAAM,UAAU,IAAI;AAAA,YACpB,OAAO,WAAW;AAAA,YAClB,SAAS,KAAK,MAAM,cAAc,WAAW,SAAS,QAAQ,CAAC;AAAA,YAC/D,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AACD;AAAA,QACF;AACA,cAAM;AAAA,MACR,UAAE;AACA,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,SAAS,yBAAyB,mBAAmB;AAAA,EAC9E;AAEA,SAAO;AAAA,IACL,IAAO,MAAc,QAAiC;AACpD,aAAO,QAAW,OAAO,MAAM,QAAW,MAAM;AAAA,IAClD;AAAA,IACA,KAAQ,MAAc,MAAgB;AACpC,aAAO,QAAW,QAAQ,MAAM,IAAI;AAAA,IACtC;AAAA,IACA,IAAO,MAAc,MAAgB;AACnC,aAAO,QAAW,OAAO,MAAM,IAAI;AAAA,IACrC;AAAA,IACA,MAAS,MAAc,MAAgB;AACrC,aAAO,QAAW,SAAS,MAAM,IAAI;AAAA,IACvC;AAAA,IACA,OAAU,MAAc;AACtB,aAAO,QAAW,UAAU,IAAI;AAAA,IAClC;AAAA,IACA,OAAU,MAAc,UAAkB,aAAqB;AAC7D,aAAO,cAAiB,MAAM,UAAU,WAAW;AAAA,IACrD;AAAA,EACF;AACF;;;AE5HA,eAAe,UAAU,SAAkC,QAA+B;AACxF,MAAI,QAAS,OAAM,QAAQ,QAAQ,MAAM;AAC3C;AAEO,SAAS,gBAAgB,SAA0C;AACxE,QAAM,OAAO,iBAAiB,OAAO;AACrC,QAAM,UAAU,QAAQ,eAAe;AAEvC,SAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM,OAAO,aAAa;AACxB,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,KAAc,IAAI,WAAW,QAAQ;AACjE,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,IAAI,aAAa,QAAQ;AAC7B,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,IAAa,IAAI,WAAW,UAAU,MAAM,EAAE;AAC1E,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,SAAS,aAAa,QAAQ;AAClC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,KAAc,IAAI,WAAW,UAAU,MAAM,WAAW;AACpF,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ;AAChC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,KAAc,IAAI,WAAW,UAAU,MAAM,SAAS;AAClF,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ;AAChC,cAAM,KAAK,OAAO,IAAI,WAAW,UAAU,MAAM,EAAE;AAAA,MACrD;AAAA,IACF;AAAA,IAEA,SAAS;AAAA,MACP,MAAM,IAAI,aAAa,QAAQ;AAC7B,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,IAAgB,IAAI,WAAW,UAAU,MAAM,UAAU;AACrF,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ,SAAS;AACzC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM;AAAA,UAC/B;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,MAAM,aAAa,QAAQ,SAAS;AACxC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM;AAAA,UAC/B;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,SAAS;AAAA,MACP,MAAM,KAAK,aAAa,QAAQ;AAC9B,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM;AAAA,QACjC;AACA,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ,UAAU;AAC1C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM;AAAA,UAC/B;AAAA,UACA;AAAA,QACF;AACA,YAAI,CAAC,KAAK,QAAQ;AAChB,gBAAM,IAAI,MAAM,8CAA8C;AAAA,QAChE;AACA,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,IAEA,QAAQ;AAAA,MACN,MAAM,KAAK,aAAa,QAAQ;AAC9B,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM;AAAA,QACjC;AACA,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,MAAM,IAAI,aAAa,QAAQ,OAAO;AACpC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,IAAW,IAAI,WAAW,UAAU,MAAM,WAAW,KAAK,EAAE;AACxF,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ,OAAO,SAAS;AAChD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,IAAW,IAAI,WAAW,UAAU,MAAM,WAAW,KAAK,IAAI;AAAA,UACxF;AAAA,UACA,UAAU,CAAC,OAAO;AAAA,QACpB,CAAC;AACD,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,UAAU;AAAA,MACR,MAAM,KAAK,aAAa,QAAQ;AAC9B,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM;AAAA,QACjC;AACA,eAAO,KAAK,YAAY,CAAC;AAAA,MAC3B;AAAA,MAEA,MAAM,IAAI,aAAa,QAAQ,UAAU;AACvC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,aAAa,QAAQ;AAAA,QACtD;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ,UAAU,SAAS;AACnD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,aAAa,QAAQ;AAAA,UACpD;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,MAAM,aAAa,QAAQ,UAAU,SAAS;AAClD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,aAAa,QAAQ;AAAA,UACpD;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ,UAAU;AAC1C,cAAM,KAAK,OAAO,IAAI,WAAW,UAAU,MAAM,aAAa,QAAQ,EAAE;AAAA,MAC1E;AAAA,MAEA,MAAM,UAAU,aAAa,QAAQ;AACnC,cAAM,KAAK,OAAO,IAAI,WAAW,UAAU,MAAM,WAAW;AAAA,MAC9D;AAAA,IACF;AAAA,IAEA,QAAQ;AAAA,MACN,MAAM,KAAK,aAAa,QAAQ,UAAU,WAAW;AACnD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,aAAa,QAAQ,IAAI,SAAS;AAAA,QACnE;AACA,eAAO,KAAK,UAAU,CAAC;AAAA,MACzB;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ,UAAU,WAAW,UAAU;AAC/D,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,aAAa,QAAQ,IAAI,SAAS;AAAA,UACjE;AAAA,UACA,SAAS,SAAS,MAAM,IAAI,cAAc;AAAA,QAC5C;AACA,YAAI,CAAC,KAAK,OAAO;AACf,gBAAM,IAAI,MAAM,6CAA6C;AAAA,QAC/D;AACA,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ,UAAU,WAAW,SAAS;AAC9D,cAAM,KAAK;AAAA,UACT,IAAI,WAAW,UAAU,MAAM,aAAa,QAAQ,IAAI,SAAS,IAAI,OAAO;AAAA,QAC9E;AAAA,MACF;AAAA,MAEA,MAAM,UAAU,aAAa,QAAQ,UAAU,WAAW;AACxD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,aAAa,QAAQ,IAAI,SAAS;AAAA,QACnE;AACA,eAAO,KAAK,WAAW,CAAC;AAAA,MAC1B;AAAA,IACF;AAAA,IAEA,qBAAqB;AAAA,MACnB,MAAM,IAAI,aAAa,QAAQ,OAAO;AACpC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,wBAAwB,KAAK;AAAA,QAC9D;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,SAAS;AAAA,MACP,MAAM,KAAK,aAAaA,UAAU;AAChC,cAAM,UAAU,SAAS,YAAY;AACrC,cAAM,SAAiC,CAAC;AACxC,YAAIA,UAAS,MAAO,QAAO,OAAO,IAAIA,SAAQ;AAC9C,YAAIA,UAAS,WAAY,QAAO,YAAY,IAAI,OAAOA,SAAQ,UAAU;AACzE,YAAIA,UAAS;AACX,iBAAO,qBAAqB,IAAIA,SAAQ;AAC1C,cAAM,YAAY,OAAO,KAAK,MAAM,EAAE,SAAS;AAC/C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW;AAAA,UACf,YAAY,SAAS;AAAA,QACvB;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,IAAI,aAAa,UAAU,qBAAsB;AACrD,cAAM,UAAU,SAAS,YAAY;AACrC,cAAM,SAAiC,CAAC;AACxC,YAAI,oBAAqB,QAAO,qBAAqB,IAAI;AACzD,cAAM,YAAY,OAAO,KAAK,MAAM,EAAE,SAAS;AAC/C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,YAAY,QAAQ;AAAA,UACnC,YAAY,SAAS;AAAA,QACvB;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,MAAM,aAAa,UAAU,WAAW;AAC5C,cAAM,UAAU,SAAS,aAAa;AACtC,cAAM,OAA2B,EAAE,UAAU;AAC7C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,YAAY,QAAQ;AAAA,UACnC;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,eAAe;AAAA,MACb,MAAM,KAAK,aAAaA,UAAU;AAChC,cAAM,SAAiC,CAAC;AACxC,YAAIA,UAAS,UAAW,QAAO,WAAW,IAAIA,SAAQ;AACtD,YAAIA,UAAS,SAAU,QAAO,UAAU,IAAI,OAAOA,SAAQ,QAAQ;AACnE,cAAM,YAAY,OAAO,KAAK,MAAM,EAAE,SAAS;AAC/C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW;AAAA,UACf,YAAY,SAAS;AAAA,QACvB;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,IAAI,aAAa,WAAW;AAChC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS;AAAA,QACzD;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,MAAM;AAC9B,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW;AAAA,UACf;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,WAAW,MAAM,YAAa;AACtD,YAAI,OAAO,IAAI,WAAW,+BAA+B,SAAS;AAClE,YAAI,YAAY;AACd,kBAAQ,IAAI,IAAI,gBAAgB,EAAE,WAAW,CAAC,EAAE,SAAS,CAAC;AAAA,QAC5D;AACA,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,MAAoB,MAAM,IAAI;AAC1D,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,WAAW;AACnC,cAAM,KAAK,OAAO,IAAI,WAAW,+BAA+B,SAAS,EAAE;AAAA,MAC7E;AAAA,MAEA,MAAM,iBAAiB,aAAa,WAAW,YAAY;AACzD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU;AAAA,QACjF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,mBAAmB,aAAa,WAAW,YAAY;AAC3D,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU;AAAA,QACjF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,eAAe,aAAa,WAAW,YAAY;AACvD,cAAM,KAAK;AAAA,UACT,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU;AAAA,QACjF;AAAA,MACF;AAAA,MAEA,MAAM,cAAc,aAAa,WAAW,YAAY,MAAM;AAC5D,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU;AAAA,UAC/E;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,WAAW,aAAa,WAAW,YAAY;AACnD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU;AAAA,QACjF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,SAAS,aAAa,WAAW,YAAY,SAAS;AAC1D,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU,WAAW,OAAO;AAAA,QACnG;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,YAAY,aAAa,WAAW,YAAY,MAAM;AAC1D,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU;AAAA,UAC/E;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,YAAY,aAAa,WAAW,YAAY,SAAS,MAAM,YAAa;AAChF,YAAI,OAAO,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU,WAAW,OAAO;AAC5G,YAAI,YAAY;AACd,kBAAQ,IAAI,IAAI,gBAAgB,EAAE,WAAW,CAAC,EAAE,SAAS,CAAC;AAAA,QAC5D;AACA,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,MAAyB,MAAM,IAAI;AAC/D,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,YAAY,aAAa,WAAW,YAAY,SAAS;AAC7D,cAAM,KAAK;AAAA,UACT,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU,WAAW,OAAO;AAAA,QACnG;AAAA,MACF;AAAA,MAEA,MAAM,cAAc,aAAa,WAAW,YAAY,SAAS;AAC/D,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU,WAAW,OAAO;AAAA,QACnG;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,gBAAgB,aAAa,WAAW,YAAY,SAAS;AACjE,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,+BAA+B,SAAS,cAAc,UAAU,WAAW,OAAO;AAAA,QACnG;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,eAAe;AAAA,MACb,MAAM,KAAK,aAAaA,UAAU;AAChC,cAAM,SAAiC,CAAC;AACxC,YAAIA,UAAS,MAAO,QAAO,OAAO,IAAIA,SAAQ;AAC9C,YAAIA,UAAS,WAAY,QAAO,YAAY,IAAI,OAAOA,SAAQ,UAAU;AACzE,cAAM,YAAY,OAAO,KAAK,MAAM,EAAE,SAAS;AAC/C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW;AAAA,UACf,YAAY,SAAS;AAAA,QACvB;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,IAAI,aAAa,KAAK;AAC1B,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,IAAkB,IAAI,WAAW,kBAAkB,GAAG,EAAE;AACpF,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,MAAM;AAC9B,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,KAAmB,IAAI,WAAW,kBAAkB,IAAI;AACpF,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,KAAK,MAAM;AACnC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,IAAkB,IAAI,WAAW,kBAAkB,GAAG,IAAI,IAAI;AAC1F,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,KAAK;AAC7B,cAAM,KAAK,OAAO,IAAI,WAAW,kBAAkB,GAAG,EAAE;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,WAAW;AAAA,MACT,MAAM,WAAW,aAAa,WAAW,OAAO;AAC9C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,uBAAuB,SAAS,WAAW,KAAK;AAAA,QACjE;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,mBAAmB,aAAa,WAAW,OAAO,MAAO;AAC7D,cAAM,KAAK;AAAA,UACT,IAAI,WAAW,uBAAuB,SAAS,WAAW,KAAK;AAAA,UAC/D;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,eAAe,aAAa,WAAW,OAAO;AAClD,cAAM,KAAK,KAAK,IAAI,WAAW,uBAAuB,SAAS,WAAW,KAAK,UAAU;AAAA,MAC3F;AAAA,MAEA,MAAM,kBAAkB,aAAa,OAAO;AAC1C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,qCAAqC,KAAK;AAAA,QAC3D;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,kBAAkB,aAAa,gBAAgB,OAAO;AAC1D,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,4BAA4B,cAAc,WAAW,KAAK;AAAA,QAC3E;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,mBAAmB,aAAa,gBAAgB,OAAO;AAC3D,cAAM,KAAK;AAAA,UACT,IAAI,WAAW,4BAA4B,cAAc,WAAW,KAAK;AAAA,QAC3E;AAAA,MACF;AAAA,MAEA,MAAM,kBAAkB,aAAa,gBAAgB,OAAO,MAAM;AAChE,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,4BAA4B,cAAc,WAAW,KAAK;AAAA,UACzE;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,qBAAqB,aAAa,OAAO;AAC7C,cAAM,KAAK,KAAK,IAAI,WAAW,qCAAqC,KAAK,SAAS;AAAA,MACpF;AAAA,MAEA,MAAM,WAAW,aAAaA,UAAU;AACtC,cAAM,UAAU,SAAS,aAAa;AACtC,cAAM,UAAU,SAAS,aAAa;AACtC,cAAM,SAAiC,CAAC;AACxC,YAAIA,UAAS,UAAW,QAAO,WAAW,IAAIA,SAAQ;AACtD,YAAIA,UAAS,QAAS,QAAO,SAAS,IAAIA,SAAQ;AAClD,YAAIA,UAAS,WAAY,QAAO,YAAY,IAAI,OAAOA,SAAQ,UAAU;AACzE,YAAIA,UAAS,MAAO,QAAO,OAAO,IAAIA,SAAQ;AAC9C,cAAM,YAAY,OAAO,KAAK,MAAM,EAAE,SAAS;AAC/C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW;AAAA,UACf,YAAY,SAAS;AAAA,QACvB;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,QAAQ;AAAA,MACN,MAAM,OAAO,aAAa,SAAS,MAAO;AACxC,cAAM,KAAK,KAAK,IAAI,WAAW,WAAW,OAAO,WAAW,IAAI;AAAA,MAClE;AAAA,IACF;AAAA,IAEA,cAAc;AAAA,MACZ,MAAM,oBAAoB,aAAa,OAAO;AAC5C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW;AAAA,UACf;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,SAAS;AAAA,MACP,MAAM,KAAK,aAAa,YAAY,MAAM,OAAO;AAC/C,cAAM,WAAW,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AAC9C,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,YAAY,UAAU,IAAI,IAAI,IAAI,QAAQ;AAAA,QAC3D;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,SAAS;AAAA,MACP,MAAM,IAAI,aAAa,QAAQ,OAAO;AACpC,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,YAAY,KAAK;AAAA,QAClD;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,aAAa,QAAQ,OAAO,aAAa;AACpD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,YAAY,KAAK;AAAA,UAChD;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,eAAe;AAAA,MACb,MAAM,OAAO,aAAa,QAAQ,aAAa,UAAU;AACvD,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,UAC1B,IAAI,WAAW,UAAU,MAAM,SAAS,WAAW;AAAA,UACnD;AAAA,UACA;AAAA,QACF;AACA,YAAI,CAAC,KAAK,mBAAmB;AAC3B,gBAAM,IAAI,MAAM,0DAA0D;AAAA,QAC5E;AACA,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;;;ACzwBA,IAAM,qBAAqB;AA0BpB,SAAS,sBAAsB,SAA+C;AACnF,QAAM,OAAO,iBAAiB,EAAE,GAAG,SAAS,SAAS,mBAAmB,CAAC;AAEzE,SAAO;AAAA,IACL,MAAM,eAAe,aAAa,WAAW,OAAO;AAClD,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,QAC1B,SAAS,WAAW,IAAI,SAAS;AAAA,QACjC;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,aAAa,aAAa;AAC9B,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK,IAA8B,SAAS,WAAW,YAAY;AAC1F,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,kBAAkB,aAAa,QAAS,UAAW,WAAY;AACnE,YAAM,SAAiC,CAAC;AACxC,UAAI,OAAQ,QAAO,QAAQ,IAAI;AAC/B,UAAI,SAAU,QAAO,UAAU,IAAI,OAAO,QAAQ;AAClD,UAAI,UAAW,QAAO,WAAW,IAAI;AACrC,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,QAC1B,SAAS,WAAW;AAAA,QACpB;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,mBAAmB,aAAa,WAAW,UAAW,WAAY;AACtE,YAAM,SAAiC,CAAC;AACxC,UAAI,SAAU,QAAO,UAAU,IAAI,OAAO,QAAQ;AAClD,UAAI,UAAW,QAAO,WAAW,IAAI;AACrC,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,QAC1B,SAAS,WAAW,gBAAgB,SAAS;AAAA,QAC7C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AC1EA,IAAM,iBAAiB;AAsBhB,SAAS,kBAAkB,SAA2C;AAC3E,QAAM,OAAO,iBAAiB,EAAE,GAAG,SAAS,SAAS,eAAe,CAAC;AAErE,SAAO;AAAA,IACL,MAAM,KAAK,aAAa,aAAc;AACpC,YAAM,SAAiC,CAAC;AACxC,UAAI,aAAa,UAAW,QAAO,WAAW,IAAI,YAAY;AAC9D,UAAI,aAAa,SAAU,QAAO,UAAU,IAAI,OAAO,YAAY,QAAQ;AAC3E,YAAM,YAAY,OAAO,KAAK,MAAM,EAAE,SAAS;AAC/C,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,QAC1B,IAAI,WAAW;AAAA,QACf,YAAY,SAAS;AAAA,MACvB;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,IAAI,aAAa,QAAQ;AAC7B,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK,IAAU,IAAI,WAAW,UAAU,MAAM,EAAE;AACvE,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,OAAO,aAAa,MAAM;AAC9B,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK,KAAW,IAAI,WAAW,UAAU,IAAI;AACpE,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,OAAO,aAAa,QAAQ,MAAM,YAAa;AACnD,UAAI,OAAO,IAAI,WAAW,UAAU,MAAM;AAC1C,UAAI,YAAY;AACd,gBAAQ,eAAe,mBAAmB,UAAU,EAAE,QAAQ,SAAS,GAAG,CAAC;AAAA,MAC7E;AACA,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK,MAAY,MAAM,IAAI;AAClD,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,OAAO,aAAa,QAAQ;AAChC,YAAM,KAAK,OAAO,IAAI,WAAW,UAAU,MAAM,EAAE;AAAA,IACrD;AAAA,EACF;AACF;;;AC/CO,IAAM,qBAAsD;AAAA,EACjE,SAAS,EAAE,MAAM,WAAW,WAAW,KAAK,YAAY,KAAK,kBAAkB,IAAM;AAAA,EACrF,YAAY,EAAE,MAAM,cAAc,WAAW,KAAK,YAAY,KAAK,kBAAkB,KAAU;AAAA,EAC/F,aAAa;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,kBAAkB;AAAA,EACpB;AAAA,EACA,aAAa,EAAE,MAAM,eAAe,WAAW,IAAI,YAAY,IAAI,kBAAkB,IAAO;AAAA,EAC5F,aAAa;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,kBAAkB;AAAA,EACpB;AACF;AAEO,SAAS,kBAAkB,SAA0C;AAC1E,QAAM,SAAS,oBAAI,IAAyB;AAE5C,MAAI,SAAS;AACX,eAAW,UAAU,SAAS;AAC5B,aAAO,IAAI,OAAO,MAAM;AAAA,QACtB,QAAQ,OAAO;AAAA,QACf,gBAAgB,KAAK,IAAI;AAAA,QACzB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,QAAQ,QAA+B;AAC3C,YAAM,QAAQ,OAAO,IAAI,MAAM;AAC/B,UAAI,CAAC,MAAO;AAEZ,YAAM,MAAM,KAAK,IAAI;AACrB,YAAM,UAAU,MAAM,MAAM;AAC5B,YAAM,SAAS,KAAK;AAAA,QACjB,UAAU,MAAM,OAAO,mBAAoB,MAAM,OAAO;AAAA,MAC3D;AAEA,UAAI,SAAS,GAAG;AACd,cAAM,SAAS,KAAK,IAAI,MAAM,OAAO,WAAW,MAAM,SAAS,MAAM;AACrE,cAAM,iBAAiB;AAAA,MACzB;AAEA,UAAI,MAAM,SAAS,GAAG;AACpB,cAAM;AACN;AAAA,MACF;AAEA,YAAM,eAAe;AACrB,YAAM,SAAS,KAAK;AAAA,QACjB,eAAe,MAAM,OAAO,aAAc,MAAM,OAAO;AAAA,MAC1D;AACA,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC;AAG9C,YAAM,YAAY,KAAK,IAAI;AAC3B,YAAM,eAAe,YAAY,MAAM;AACvC,YAAM,YAAY,KAAK;AAAA,QACpB,eAAe,MAAM,OAAO,mBAAoB,MAAM,OAAO;AAAA,MAChE;AACA,YAAM,SAAS,KAAK,IAAI,MAAM,OAAO,WAAW,SAAS,IAAI;AAC7D,YAAM,iBAAiB;AAAA,IACzB;AAAA,EACF;AACF;;;AChFA,gBAAuB,SACrB,WACA,SACwC;AACxC,MAAI,YAAY,SAAS;AACzB,MAAI,YAAY;AAChB,QAAM,QAAQ,SAAS;AAEvB,aAAS;AACP,QAAI,UAAU,UAAa,aAAa,MAAO;AAE/C,UAAM,OAAO,MAAM,UAAU,SAAS;AACtC,UAAM,QAAQ,KAAK;AAEnB,QAAI,MAAM,WAAW,EAAG;AAExB,QAAI,UAAU,QAAW;AACvB,YAAM,YAAY,QAAQ;AAC1B,UAAI,MAAM,SAAS,WAAW;AAC5B,cAAM,MAAM,MAAM,GAAG,SAAS;AAC9B;AAAA,MACF;AAAA,IACF;AAEA,UAAM;AACN,iBAAa,MAAM;AACnB,gBAAY,KAAK;AAEjB,QAAI,CAAC,UAAW;AAAA,EAClB;AACF;AAEA,eAAsB,YACpB,WACA,SACqD;AACrD,QAAM,WAAoB,CAAC;AAC3B,MAAI;AACJ,QAAM,QAAQ,SAAS;AAEvB,mBAAiB,SAAS,SAAS,WAAW,OAAO,GAAG;AACtD,aAAS,KAAK,GAAG,KAAK;AACtB,QAAI,UAAU,UAAa,SAAS,UAAU,MAAO;AAAA,EACvD;AAGA,MAAI,UAAU,UAAa,SAAS,UAAU,OAAO;AACnD,oBAAgB;AAAA,EAClB;AAEA,SAAO,EAAE,OAAO,UAAU,eAAe,cAAc;AACzD;AAWA,eAAsB,iBACpB,WACA,YACA,cAAc,GACuC;AACrD,QAAM,WAAoB,CAAC;AAC3B,MAAI;AAGJ,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,aAAa;AACvD,UAAM,QAAQ,WAAW,MAAM,GAAG,IAAI,WAAW;AACjD,UAAM,UAAU,MAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,UAAU,UAAU,KAAK,CAAC,CAAC;AAExE,eAAW,UAAU,SAAS;AAC5B,eAAS,KAAK,GAAG,OAAO,KAAK;AAC7B,UAAI,OAAO,eAAe;AACxB,4BAAoB,OAAO;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,UAAU,eAAe,kBAAkB;AAC7D;","names":["options"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gpc-cli/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Typed client for Google Play Developer API v3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@gpc-cli/auth": "0.
|
|
18
|
+
"@gpc-cli/auth": "0.9.6"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"google-play",
|