From 3265f4bbe15e9cbcd0f0230a4c0bcd8119b63983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Thu, 27 Aug 2026 13:19:59 +0200 Subject: [PATCH 1/2] feat(kilo-pass): add Google Play publisher SDK --- ENVIRONMENT.md | 2 + apps/web/package.json | 1 + .../src/lib/kilo-pass/google-play-sdk.test.ts | 101 ++++++++++++++++++ apps/web/src/lib/kilo-pass/google-play-sdk.ts | 58 ++++++++++ .../kilo-pass/mobile-store-products.test.ts | 27 +++++ .../lib/kilo-pass/mobile-store-products.ts | 10 ++ pnpm-lock.yaml | 81 ++++++++++++++ 7 files changed, 280 insertions(+) create mode 100644 apps/web/src/lib/kilo-pass/google-play-sdk.test.ts create mode 100644 apps/web/src/lib/kilo-pass/google-play-sdk.ts create mode 100644 apps/web/src/lib/kilo-pass/mobile-store-products.test.ts diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 2b843cc7b2..fcbcfe3b7c 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -164,6 +164,8 @@ Manage shared web env var additions and rotations with `pnpm web:env set ({ + args, + type: 'google-auth', +})); + +const mockSubscriptionsV2Get = jest.fn().mockResolvedValue({ + data: { subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE' }, +}); + +const mockAndroidPublisher = jest.fn().mockImplementation((...args: unknown[]) => ({ + args, + purchases: { + subscriptionsv2: { + get: mockSubscriptionsV2Get, + }, + }, +})); + +jest.mock('google-auth-library', () => ({ + GoogleAuth: mockGoogleAuth, +})); + +jest.mock('@googleapis/androidpublisher', () => ({ + androidpublisher: mockAndroidPublisher, +})); + +function loadGooglePlaySdk(): typeof GooglePlaySdk { + return jest.requireActual('./google-play-sdk'); +} + +describe('google-play-sdk', () => { + beforeEach(() => { + jest.resetModules(); + process.env.GOOGLE_PLAY_PUBLISHER_SERVICE_ACCOUNT_JSON = JSON.stringify({ + client_email: 'publisher@example.com', + private_key: 'private-key', + }); + jest.clearAllMocks(); + }); + + it('reuses the Android Publisher client for unchanged JSON', () => { + const { createGooglePlayAndroidPublisherClient } = loadGooglePlaySdk(); + + const first = createGooglePlayAndroidPublisherClient(); + const second = createGooglePlayAndroidPublisherClient(); + + expect(second).toBe(first); + expect(mockAndroidPublisher).toHaveBeenCalledTimes(1); + }); + + it('constructs GoogleAuth with the androidpublisher scope', () => { + const { createGooglePlayAndroidPublisherClient } = loadGooglePlaySdk(); + + createGooglePlayAndroidPublisherClient(); + + expect(mockGoogleAuth).toHaveBeenCalledWith({ + credentials: expect.objectContaining({ + client_email: 'publisher@example.com', + private_key: 'private-key', + }), + scopes: ['https://www.googleapis.com/auth/androidpublisher'], + }); + }); + + it('calls subscriptionsv2.get with the package name and token', async () => { + const { getGooglePlaySubscriptionPurchase } = loadGooglePlaySdk(); + + const data = await getGooglePlaySubscriptionPurchase('purchase-token'); + + expect(mockSubscriptionsV2Get).toHaveBeenCalledWith({ + packageName: 'com.kilocode.kiloapp', + token: 'purchase-token', + }); + expect(data).toEqual({ subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE' }); + }); + + it('throws when the service account JSON is not set', () => { + delete process.env.GOOGLE_PLAY_PUBLISHER_SERVICE_ACCOUNT_JSON; + + const { createGooglePlayAndroidPublisherClient } = loadGooglePlaySdk(); + + expect(() => createGooglePlayAndroidPublisherClient()).toThrow( + 'GOOGLE_PLAY_PUBLISHER_SERVICE_ACCOUNT_JSON is not set' + ); + }); + + it('throws when the service account JSON is invalid', () => { + process.env.GOOGLE_PLAY_PUBLISHER_SERVICE_ACCOUNT_JSON = JSON.stringify({ + client_email: 'publisher@example.com', + }); + + const { createGooglePlayAndroidPublisherClient } = loadGooglePlaySdk(); + + expect(() => createGooglePlayAndroidPublisherClient()).toThrow( + 'GOOGLE_PLAY_PUBLISHER_SERVICE_ACCOUNT_JSON is invalid' + ); + }); +}); diff --git a/apps/web/src/lib/kilo-pass/google-play-sdk.ts b/apps/web/src/lib/kilo-pass/google-play-sdk.ts new file mode 100644 index 0000000000..2b6ac2cc4f --- /dev/null +++ b/apps/web/src/lib/kilo-pass/google-play-sdk.ts @@ -0,0 +1,58 @@ +import { androidpublisher } from '@googleapis/androidpublisher'; +import type { androidpublisher_v3 } from '@googleapis/androidpublisher'; +import { GoogleAuth } from 'google-auth-library'; +import type { JWTInput } from 'google-auth-library'; + +import { getEnvVariable } from '@/lib/dotenvx'; + +export const GOOGLE_PLAY_PACKAGE_NAME = 'com.kilocode.kiloapp'; + +const ANDROID_PUBLISHER_SCOPE = 'https://www.googleapis.com/auth/androidpublisher'; + +type CachedValue = { + key: string; + value: T; +}; + +let cachedPublisherClient: CachedValue | null = null; + +function requiredEnv(name: string): string { + const value = getEnvVariable(name); + if (!value) throw new Error(`${name} is not set`); + return value; +} + +function parseGooglePlayServiceAccountCredentials(json: string): JWTInput { + const parsed = JSON.parse(json) as JWTInput; + if (!parsed.client_email || !parsed.private_key) { + throw new Error('GOOGLE_PLAY_PUBLISHER_SERVICE_ACCOUNT_JSON is invalid'); + } + return parsed; +} + +export function createGooglePlayAndroidPublisherClient(): androidpublisher_v3.Androidpublisher { + const serviceAccountJson = requiredEnv('GOOGLE_PLAY_PUBLISHER_SERVICE_ACCOUNT_JSON'); + if (cachedPublisherClient?.key === serviceAccountJson) { + return cachedPublisherClient.value; + } + + const credentials = parseGooglePlayServiceAccountCredentials(serviceAccountJson); + const auth = new GoogleAuth({ + credentials, + scopes: [ANDROID_PUBLISHER_SCOPE], + }); + const client = androidpublisher({ version: 'v3', auth }); + cachedPublisherClient = { key: serviceAccountJson, value: client }; + return client; +} + +export async function getGooglePlaySubscriptionPurchase( + purchaseToken: string +): Promise { + const client = createGooglePlayAndroidPublisherClient(); + const response = await client.purchases.subscriptionsv2.get({ + packageName: GOOGLE_PLAY_PACKAGE_NAME, + token: purchaseToken, + }); + return response.data; +} diff --git a/apps/web/src/lib/kilo-pass/mobile-store-products.test.ts b/apps/web/src/lib/kilo-pass/mobile-store-products.test.ts new file mode 100644 index 0000000000..b3f506986b --- /dev/null +++ b/apps/web/src/lib/kilo-pass/mobile-store-products.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from '@jest/globals'; + +import { KiloPassCadence, KiloPassTier } from './enums'; +import { + getMobileStoreKiloPassProductByAppleProductId, + getMobileStoreKiloPassProductByGoogleProductId, +} from './mobile-store-products'; + +describe('mobile-store-products', () => { + it('looks up a product by Google product id', () => { + const product = getMobileStoreKiloPassProductByGoogleProductId('kilopass_tier19'); + + expect(product?.tier).toBe(KiloPassTier.Tier19); + expect(product?.cadence).toBe(KiloPassCadence.Monthly); + }); + + it('returns null for an unknown Google product id', () => { + expect(getMobileStoreKiloPassProductByGoogleProductId('unknown_id')).toBeNull(); + }); + + it('still looks up a product by Apple product id', () => { + const product = getMobileStoreKiloPassProductByAppleProductId('kilopass.tier19.monthly.v1'); + + expect(product?.tier).toBe(KiloPassTier.Tier19); + expect(product?.cadence).toBe(KiloPassCadence.Monthly); + }); +}); diff --git a/apps/web/src/lib/kilo-pass/mobile-store-products.ts b/apps/web/src/lib/kilo-pass/mobile-store-products.ts index fce53267ba..5725da9f0f 100644 --- a/apps/web/src/lib/kilo-pass/mobile-store-products.ts +++ b/apps/web/src/lib/kilo-pass/mobile-store-products.ts @@ -75,3 +75,13 @@ export function getMobileStoreKiloPassProductByAppleProductId( ) ?? null ); } + +export function getMobileStoreKiloPassProductByGoogleProductId( + googleProductId: string +): MobileStoreKiloPassProduct | null { + return ( + getAllMobileStoreKiloPassProducts().find( + product => product.googleProductId === googleProductId + ) ?? null + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a773bd0d9..5a724c183b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -779,6 +779,9 @@ importers: '@emoji-mart/react': specifier: 1.1.1 version: 1.1.1(emoji-mart@5.6.0)(react@19.2.6) + '@googleapis/androidpublisher': + specifier: 37.0.0 + version: 37.0.0 '@kilocode/app-shared': specifier: workspace:* version: link:../../packages/app-shared @@ -5268,6 +5271,10 @@ packages: '@modelcontextprotocol/sdk': optional: true + '@googleapis/androidpublisher@37.0.0': + resolution: {integrity: sha512-54v9hNzvq8qoZs/P2wMcfslrL1aXBUcCektbyNemWulORgX4PNDx8TTzEoOEzEiyTHKLNnmMhiTGG5NIdrndHA==} + engines: {node: '>=12.0.0'} + '@grammyjs/runner@2.0.3': resolution: {integrity: sha512-nckmTs1dPWfVQteK9cxqxzE+0m1VRvluLWB8UgFzsjg62w3qthPJt0TYtJBEdG7OedvfQq4vnFAyE6iaMkR42A==} engines: {node: '>=12.20.0 || >=14.13.1'} @@ -13242,6 +13249,10 @@ packages: resolution: {integrity: sha512-EstfdRQu04tM+SXR3pBmc0+GYKZj9FMHAvA8XAbKPzTvUeHP0v1/F3aQ10bG7EluR6phvFqsvn5Z7SvYJsEgNw==} hasBin: true + gaxios@7.1.3: + resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} + engines: {node: '>=18'} + gaxios@7.1.4: resolution: {integrity: sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==} engines: {node: '>=18'} @@ -13362,6 +13373,10 @@ packages: engines: {node: '>=0.6.0'} hasBin: true + google-auth-library@10.5.0: + resolution: {integrity: sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==} + engines: {node: '>=18'} + google-auth-library@10.6.2: resolution: {integrity: sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==} engines: {node: '>=18'} @@ -13370,6 +13385,10 @@ packages: resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} engines: {node: '>=14'} + googleapis-common@8.0.3: + resolution: {integrity: sha512-7g1yzQKx0mmNTjiK0H9dJ8eqKqDBveES9vLHeg5neb3BMQy/d1oQefIMhIpOVT8a+f+LOcixMEdRbFIW/cQUJw==} + engines: {node: '>=18'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -13400,6 +13419,10 @@ packages: growly@1.3.0: resolution: {integrity: sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==} + gtoken@8.0.0: + resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==} + engines: {node: '>=18'} + gzip-size@6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} @@ -16869,6 +16892,10 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + hasBin: true + rimraf@6.1.3: resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} engines: {node: 20 || >=22} @@ -18098,6 +18125,9 @@ packages: url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + url-template@2.0.8: + resolution: {integrity: sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==} + url@0.11.4: resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} engines: {node: '>= 0.4'} @@ -21943,6 +21973,12 @@ snapshots: - supports-color - utf-8-validate + '@googleapis/androidpublisher@37.0.0': + dependencies: + googleapis-common: 8.0.3 + transitivePeerDependencies: + - supports-color + '@grammyjs/runner@2.0.3(grammy@1.44.0)': dependencies: abort-controller: 3.0.0 @@ -30924,6 +30960,15 @@ snapshots: which: 4.0.0 winreg: 0.0.12 + gaxios@7.1.3: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + rimraf: 5.0.10 + transitivePeerDependencies: + - supports-color + gaxios@7.1.4: dependencies: extend: 3.0.2 @@ -31048,6 +31093,18 @@ snapshots: dependencies: minimist: 1.2.8 + google-auth-library@10.5.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.4 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + gtoken: 8.0.0 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + google-auth-library@10.6.2: dependencies: base64-js: 1.5.1 @@ -31061,6 +31118,17 @@ snapshots: google-logging-utils@1.1.3: {} + googleapis-common@8.0.3: + dependencies: + extend: 3.0.2 + gaxios: 7.1.3 + google-auth-library: 10.5.0 + google-logging-utils: 1.1.3 + qs: 6.15.2 + url-template: 2.0.8 + transitivePeerDependencies: + - supports-color + gopd@1.2.0: {} graceful-fs@4.2.10: {} @@ -31088,6 +31156,13 @@ snapshots: growly@1.3.0: {} + gtoken@8.0.0: + dependencies: + gaxios: 7.1.4 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + gzip-size@6.0.0: dependencies: duplexer: 0.1.2 @@ -36034,6 +36109,10 @@ snapshots: dependencies: glob: 13.0.6 + rimraf@5.0.10: + dependencies: + glob: 13.0.6 + rimraf@6.1.3: dependencies: glob: 13.0.6 @@ -37466,6 +37545,8 @@ snapshots: url-join@4.0.1: {} + url-template@2.0.8: {} + url@0.11.4: dependencies: punycode: 1.4.1 From 45648d57e7c5e0c92853d12ab85bcf1612f8b6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Thu, 27 Aug 2026 18:23:01 +0200 Subject: [PATCH 2/2] fix(kilo-pass): dedupe google-auth-library for Play SDK --- .../src/lib/kilo-pass/google-play-sdk.test.ts | 4 +- pnpm-lock.yaml | 116 ++++++++++++------ pnpm-workspace.yaml | 1 + 3 files changed, 81 insertions(+), 40 deletions(-) diff --git a/apps/web/src/lib/kilo-pass/google-play-sdk.test.ts b/apps/web/src/lib/kilo-pass/google-play-sdk.test.ts index 184143a0ef..a898e5045e 100644 --- a/apps/web/src/lib/kilo-pass/google-play-sdk.test.ts +++ b/apps/web/src/lib/kilo-pass/google-play-sdk.test.ts @@ -6,9 +6,9 @@ const mockGoogleAuth = jest.fn().mockImplementation((...args: unknown[]) => ({ type: 'google-auth', })); -const mockSubscriptionsV2Get = jest.fn().mockResolvedValue({ +const mockSubscriptionsV2Get = jest.fn().mockImplementation((...args: unknown[]) => ({ data: { subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE' }, -}); +})); const mockAndroidPublisher = jest.fn().mockImplementation((...args: unknown[]) => ({ args, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a724c183b..370554ae0f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,6 +102,7 @@ overrides: next: 16.2.11 preact: 10.28.4 glob: '>=13.0.1' + google-auth-library: 10.6.2 esbuild: '>=0.28.1' lodash: '>=4.18.1' diff: '>=8.0.3' @@ -1368,7 +1369,7 @@ importers: version: 7.0.0-dev.20260514.1 jest: specifier: 30.3.0 - version: 30.3.0(@types/node@25.5.2)(node-notifier@10.0.1) + version: 30.3.0(@types/node@24.12.4)(node-notifier@10.0.1) typescript: specifier: 'catalog:' version: 5.9.3 @@ -2024,7 +2025,7 @@ importers: version: 0.3.7 '@cloudflare/vitest-pool-workers': specifier: 'catalog:' - version: 0.16.13(@cloudflare/workers-types@4.20260605.1)(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) + version: 0.16.13(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) '@kilocode/sdk': specifier: 7.4.20 version: 7.4.20 @@ -2175,7 +2176,7 @@ importers: devDependencies: '@cloudflare/vitest-pool-workers': specifier: 'catalog:' - version: 0.16.13(@cloudflare/workers-types@4.20260605.1)(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) + version: 0.16.13(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) '@types/jest': specifier: 30.0.0 version: 30.0.0 @@ -2337,7 +2338,7 @@ importers: devDependencies: '@cloudflare/vitest-pool-workers': specifier: 'catalog:' - version: 0.16.13(@cloudflare/workers-types@4.20260605.1)(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) + version: 0.16.13(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) '@types/node': specifier: 'catalog:' version: 24.12.4 @@ -2512,7 +2513,7 @@ importers: devDependencies: '@cloudflare/vitest-pool-workers': specifier: 'catalog:' - version: 0.16.13(@cloudflare/workers-types@4.20260605.1)(@types/node@25.5.2)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) + version: 0.16.13(@types/node@25.5.2)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) '@typescript/native-preview': specifier: 'catalog:' version: 7.0.0-dev.20260514.1 @@ -2619,7 +2620,7 @@ importers: devDependencies: '@cloudflare/vitest-pool-workers': specifier: 'catalog:' - version: 0.16.13(@cloudflare/workers-types@4.20260605.1)(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) + version: 0.16.13(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) '@types/content-disposition': specifier: 0.5.9 version: 0.5.9 @@ -2976,7 +2977,7 @@ importers: devDependencies: '@cloudflare/vitest-pool-workers': specifier: 'catalog:' - version: 0.16.13(@cloudflare/workers-types@4.20260605.1)(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) + version: 0.16.13(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) '@types/node': specifier: 'catalog:' version: 24.12.4 @@ -3013,7 +3014,7 @@ importers: devDependencies: '@cloudflare/vitest-pool-workers': specifier: 'catalog:' - version: 0.16.13(@cloudflare/workers-types@4.20260605.1)(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) + version: 0.16.13(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) '@types/node': specifier: 'catalog:' version: 24.12.4 @@ -3280,7 +3281,7 @@ importers: devDependencies: '@cloudflare/vitest-pool-workers': specifier: 'catalog:' - version: 0.16.13(@cloudflare/workers-types@4.20260605.1)(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) + version: 0.16.13(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6) '@types/node': specifier: 'catalog:' version: 24.12.4 @@ -13373,10 +13374,6 @@ packages: engines: {node: '>=0.6.0'} hasBin: true - google-auth-library@10.5.0: - resolution: {integrity: sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==} - engines: {node: '>=18'} - google-auth-library@10.6.2: resolution: {integrity: sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==} engines: {node: '>=18'} @@ -13419,10 +13416,6 @@ packages: growly@1.3.0: resolution: {integrity: sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==} - gtoken@8.0.0: - resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==} - engines: {node: '>=18'} - gzip-size@6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} @@ -20542,6 +20535,38 @@ snapshots: - bufferutil - utf-8-validate + '@cloudflare/vitest-pool-workers@0.16.13(@types/node@24.12.4)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6)': + dependencies: + '@vitest/runner': 4.1.6 + '@vitest/snapshot': 4.1.6 + cjs-module-lexer: 1.2.3 + esbuild: 0.28.1 + miniflare: 4.20260603.0(@types/node@24.12.4)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + wrangler: 4.98.0(@types/node@24.12.4)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + zod: 3.25.76 + transitivePeerDependencies: + - '@cloudflare/workers-types' + - '@types/node' + - bufferutil + - utf-8-validate + + '@cloudflare/vitest-pool-workers@0.16.13(@types/node@25.5.2)(@vitest/runner@4.1.6)(@vitest/snapshot@4.1.6)(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vitest@4.1.6)': + dependencies: + '@vitest/runner': 4.1.6 + '@vitest/snapshot': 4.1.6 + cjs-module-lexer: 1.2.3 + esbuild: 0.28.1 + miniflare: 4.20260603.0(@types/node@25.5.2)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + wrangler: 4.98.0(@types/node@25.5.2)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + zod: 3.25.76 + transitivePeerDependencies: + - '@cloudflare/workers-types' + - '@types/node' + - bufferutil + - utf-8-validate + '@cloudflare/workerd-darwin-64@1.20260603.1': optional: true @@ -28134,7 +28159,7 @@ snapshots: react-refresh: 0.14.2 optionalDependencies: '@babel/runtime': 7.29.7 - expo: 57.0.10(@babel/core@7.29.7)(@expo/metro-runtime@57.0.8)(bufferutil@4.1.0)(expo-router@57.0.10)(react-dom@19.2.6(react@19.2.3))(react-native-worklets@0.10.1(@babel/core@7.29.7)(react-native@0.86.2(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.2(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3)(utf-8-validate@6.0.6) + expo: 57.0.10(@babel/core@7.29.7)(@expo/metro-runtime@57.0.8)(bufferutil@4.1.0)(expo-router@57.0.10)(react-dom@19.2.6(react@19.2.6))(react-native-worklets@0.10.1(@babel/core@7.29.7)(react-native@0.86.2(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(react-native@0.86.2(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)(typescript@5.9.3)(utf-8-validate@6.0.6) transitivePeerDependencies: - '@babel/core' - supports-color @@ -31093,18 +31118,6 @@ snapshots: dependencies: minimist: 1.2.8 - google-auth-library@10.5.0: - dependencies: - base64-js: 1.5.1 - ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.4 - gcp-metadata: 8.1.2 - google-logging-utils: 1.1.3 - gtoken: 8.0.0 - jws: 4.0.1 - transitivePeerDependencies: - - supports-color - google-auth-library@10.6.2: dependencies: base64-js: 1.5.1 @@ -31122,7 +31135,7 @@ snapshots: dependencies: extend: 3.0.2 gaxios: 7.1.3 - google-auth-library: 10.5.0 + google-auth-library: 10.6.2 google-logging-utils: 1.1.3 qs: 6.15.2 url-template: 2.0.8 @@ -31156,13 +31169,6 @@ snapshots: growly@1.3.0: {} - gtoken@8.0.0: - dependencies: - gaxios: 7.1.4 - jws: 4.0.1 - transitivePeerDependencies: - - supports-color - gzip-size@6.0.0: dependencies: duplexer: 0.1.2 @@ -38371,6 +38377,40 @@ snapshots: - bufferutil - utf-8-validate + wrangler@4.98.0(@types/node@24.12.4)(bufferutil@4.1.0)(utf-8-validate@6.0.6): + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1) + blake3-wasm: 2.1.5 + esbuild: 0.28.1 + miniflare: 4.20260603.0(@types/node@24.12.4)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + path-to-regexp: 8.4.2 + unenv: 2.0.0-rc.24 + workerd: 1.20260603.1 + optionalDependencies: + fsevents: 2.3.3 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate + + wrangler@4.98.0(@types/node@25.5.2)(bufferutil@4.1.0)(utf-8-validate@6.0.6): + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1) + blake3-wasm: 2.1.5 + esbuild: 0.28.1 + miniflare: 4.20260603.0(@types/node@25.5.2)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + path-to-regexp: 8.4.2 + unenv: 2.0.0-rc.24 + workerd: 1.20260603.1 + optionalDependencies: + fsevents: 2.3.3 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate + wrap-ansi@10.0.0: dependencies: ansi-styles: 6.2.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5379f5a334..2c0808cd75 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -85,6 +85,7 @@ overrides: next: 16.2.11 preact: 10.28.4 glob: '>=13.0.1' + google-auth-library: 10.6.2 esbuild: '>=0.28.1' lodash: '>=4.18.1' diff: '>=8.0.3'