From 27907f66dceb597851016d386a378e50eb0acaf3 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Thu, 9 Apr 2026 12:11:45 +0100 Subject: [PATCH 01/19] feat: add chomp-api-service --- .github/CODEOWNERS | 3 + README.md | 5 + packages/chomp-api-service/CHANGELOG.md | 14 ++ packages/chomp-api-service/LICENSE | 20 ++ packages/chomp-api-service/README.md | 15 ++ packages/chomp-api-service/jest.config.js | 26 +++ packages/chomp-api-service/package.json | 76 ++++++++ .../chomp-api-service-method-action-types.ts | 19 ++ .../src/chomp-api-service.test.ts | 136 ++++++++++++++ .../src/chomp-api-service.ts | 174 ++++++++++++++++++ packages/chomp-api-service/src/index.ts | 13 ++ .../chomp-api-service/tsconfig.build.json | 14 ++ packages/chomp-api-service/tsconfig.json | 12 ++ packages/chomp-api-service/typedoc.json | 7 + yarn.lock | 23 +++ 15 files changed, 557 insertions(+) create mode 100644 packages/chomp-api-service/CHANGELOG.md create mode 100644 packages/chomp-api-service/LICENSE create mode 100644 packages/chomp-api-service/README.md create mode 100644 packages/chomp-api-service/jest.config.js create mode 100644 packages/chomp-api-service/package.json create mode 100644 packages/chomp-api-service/src/chomp-api-service-method-action-types.ts create mode 100644 packages/chomp-api-service/src/chomp-api-service.test.ts create mode 100644 packages/chomp-api-service/src/chomp-api-service.ts create mode 100644 packages/chomp-api-service/src/index.ts create mode 100644 packages/chomp-api-service/tsconfig.build.json create mode 100644 packages/chomp-api-service/tsconfig.json create mode 100644 packages/chomp-api-service/typedoc.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 91c61401f6..5a53d12117 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -40,6 +40,7 @@ ## Earn Team /packages/earn-controller @MetaMask/earn /packages/money-account-balance-service @MetaMask/earn +/packages/chomp-api-service @MetaMask/earn ## Social AI Team /packages/ai-controllers @MetaMask/social-ai @@ -229,3 +230,5 @@ /packages/social-controllers/CHANGELOG.md @MetaMask/social-ai @MetaMask/core-platform /packages/money-account-controller/package.json @MetaMask/accounts-engineers @MetaMask/core-platform /packages/money-account-controller/CHANGELOG.md @MetaMask/accounts-engineers @MetaMask/core-platform +/packages/chomp-api-service/package.json @MetaMask/accounts-engineers @MetaMask/core-platform +/packages/chomp-api-service/CHANGELOG.md @MetaMask/accounts-engineers @MetaMask/core-platform diff --git a/README.md b/README.md index 83f276c0a0..98c5599b03 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Each package in this repository has its own README where you can find installati - [`@metamask/bridge-status-controller`](packages/bridge-status-controller) - [`@metamask/build-utils`](packages/build-utils) - [`@metamask/chain-agnostic-permission`](packages/chain-agnostic-permission) +- [`@metamask/chomp-api-service`](packages/chomp-api-service) - [`@metamask/claims-controller`](packages/claims-controller) - [`@metamask/client-controller`](packages/client-controller) - [`@metamask/compliance-controller`](packages/compliance-controller) @@ -124,6 +125,7 @@ linkStyle default opacity:0.5 bridge_status_controller(["@metamask/bridge-status-controller"]); build_utils(["@metamask/build-utils"]); chain_agnostic_permission(["@metamask/chain-agnostic-permission"]); + chomp_api_service(["@metamask/chomp-api-service"]); claims_controller(["@metamask/claims-controller"]); client_controller(["@metamask/client-controller"]); compliance_controller(["@metamask/compliance-controller"]); @@ -277,6 +279,9 @@ linkStyle default opacity:0.5 bridge_status_controller --> transaction_controller; chain_agnostic_permission --> controller_utils; chain_agnostic_permission --> permission_controller; + chomp_api_service --> base_data_service; + chomp_api_service --> controller_utils; + chomp_api_service --> messenger; claims_controller --> base_controller; claims_controller --> controller_utils; claims_controller --> keyring_controller; diff --git a/packages/chomp-api-service/CHANGELOG.md b/packages/chomp-api-service/CHANGELOG.md new file mode 100644 index 0000000000..0a6ede27d2 --- /dev/null +++ b/packages/chomp-api-service/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- Add `ChompApiService` ([#8361](TODO)) + +[Unreleased]: https://github.com/MetaMask/core/ diff --git a/packages/chomp-api-service/LICENSE b/packages/chomp-api-service/LICENSE new file mode 100644 index 0000000000..c8a0ff6be3 --- /dev/null +++ b/packages/chomp-api-service/LICENSE @@ -0,0 +1,20 @@ +MIT License + +Copyright (c) 2026 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE diff --git a/packages/chomp-api-service/README.md b/packages/chomp-api-service/README.md new file mode 100644 index 0000000000..a12245d8d5 --- /dev/null +++ b/packages/chomp-api-service/README.md @@ -0,0 +1,15 @@ +# `@metamask/chom-api-service` + +Chomp API data service. + +## Installation + +`yarn add @metamask/chom-api-service` + +or + +`npm install @metamask/chom-api-service` + +## Contributing + +This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme). diff --git a/packages/chomp-api-service/jest.config.js b/packages/chomp-api-service/jest.config.js new file mode 100644 index 0000000000..ca08413339 --- /dev/null +++ b/packages/chomp-api-service/jest.config.js @@ -0,0 +1,26 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ + +const merge = require('deepmerge'); +const path = require('path'); + +const baseConfig = require('../../jest.config.packages'); + +const displayName = path.basename(__dirname); + +module.exports = merge(baseConfig, { + // The display name when running multiple projects + displayName, + + // An object that configures minimum threshold enforcement for coverage results + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}); diff --git a/packages/chomp-api-service/package.json b/packages/chomp-api-service/package.json new file mode 100644 index 0000000000..203f007a60 --- /dev/null +++ b/packages/chomp-api-service/package.json @@ -0,0 +1,76 @@ +{ + "name": "@metamask/chomp-api-service", + "version": "0.0.0", + "description": "Data service for the Chomp API", + "keywords": [ + "MetaMask", + "Ethereum" + ], + "homepage": "https://github.com/MetaMask/core/tree/main/packages/chomp-api-service#readme", + "bugs": { + "url": "https://github.com/MetaMask/core/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/core.git" + }, + "license": "MIT", + "sideEffects": false, + "exports": { + ".": { + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + }, + "./package.json": "./package.json" + }, + "main": "./dist/index.cjs", + "types": "./dist/index.d.cts", + "files": [ + "dist/" + ], + "scripts": { + "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references", + "build:all": "ts-bridge --project tsconfig.build.json --verbose --clean", + "build:docs": "typedoc", + "changelog:update": "../../scripts/update-changelog.sh @metamask/chomp-api-service", + "changelog:validate": "../../scripts/validate-changelog.sh @metamask/chomp-api-service", + "since-latest-release": "../../scripts/since-latest-release.sh", + "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", + "test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache", + "test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose", + "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch" + }, + "dependencies": { + "@metamask/base-data-service": "^0.1.1", + "@metamask/controller-utils": "^11.20.0", + "@metamask/messenger": "^1.1.1", + "@metamask/superstruct": "^3.1.0", + "@metamask/utils": "^11.9.0", + "@tanstack/query-core": "^4.43.0" + }, + "devDependencies": { + "@metamask/auto-changelog": "^3.4.4", + "@ts-bridge/cli": "^0.6.4", + "@types/jest": "^29.5.14", + "deepmerge": "^4.2.2", + "jest": "^29.7.0", + "nock": "^13.3.1", + "ts-jest": "^29.2.5", + "typedoc": "^0.25.13", + "typedoc-plugin-missing-exports": "^2.0.0", + "typescript": "~5.3.3" + }, + "engines": { + "node": "^18.18 || >=20" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + } +} diff --git a/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts b/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts new file mode 100644 index 0000000000..f08d633099 --- /dev/null +++ b/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts @@ -0,0 +1,19 @@ +/** + * This file is auto generated. + * Do not edit manually. + */ + +import type { ChompApiService } from './chomp-api-service'; + +/** + * TODO: Add JSDoc description for this action. + */ +export type ChompApiServiceFetchAction = { + type: `ChompApiService:fetch`; + handler: ChompApiService['fetch']; +}; + +/** + * Union of all ChompApiService action types. + */ +export type ChompApiServiceMethodActions = ChompApiServiceFetchAction; diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts new file mode 100644 index 0000000000..663c7b7fad --- /dev/null +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -0,0 +1,136 @@ +import { DEFAULT_MAX_RETRIES } from '@metamask/controller-utils'; +import { Messenger, MOCK_ANY_NAMESPACE } from '@metamask/messenger'; +import type { + MockAnyNamespace, + MessengerActions, + MessengerEvents, +} from '@metamask/messenger'; +import nock from 'nock'; + +import type { ChompApiServiceMessenger } from './chomp-api-service'; +import { ChompApiService } from './chomp-api-service'; + +describe('ChompApiService', () => { + describe('ChompApiService:fetch', () => { + it('returns the response from the API', async () => { + nock('https://api.chomp.example.com') + .get('/items/abc') + .reply(200, { id: 'abc' }); + const { rootMessenger } = createService(); + + const response = await rootMessenger.call( + 'ChompApiService:fetch', + 'abc', + ); + + expect(response).toStrictEqual({ id: 'abc' }); + }); + + it('throws if the API returns a non-200 status', async () => { + nock('https://api.chomp.example.com') + .get('/items/abc') + .times(DEFAULT_MAX_RETRIES + 1) + .reply(500); + const { rootMessenger } = createService(); + + await expect( + rootMessenger.call('ChompApiService:fetch', 'abc'), + ).rejects.toThrow("Chomp API failed with status '500'"); + }); + + it.each([ + 'not an object', + { missing: 'id' }, + { id: 123 }, + ])( + 'throws if the API returns a malformed response %o', + async (response) => { + nock('https://api.chomp.example.com') + .get('/items/abc') + .reply(200, JSON.stringify(response)); + const { rootMessenger } = createService(); + + await expect( + rootMessenger.call('ChompApiService:fetch', 'abc'), + ).rejects.toThrow('Malformed response received from Chomp API'); + }, + ); + }); + + describe('fetch', () => { + it('does the same thing as the messenger action', async () => { + nock('https://api.chomp.example.com') + .get('/items/abc') + .reply(200, { id: 'abc' }); + const { service } = createService(); + + const response = await service.fetch('abc'); + + expect(response).toStrictEqual({ id: 'abc' }); + }); + }); +}); + +/** + * The type of the messenger populated with all external actions and events + * required by the service under test. + */ +type RootMessenger = Messenger< + MockAnyNamespace, + MessengerActions, + MessengerEvents +>; + +/** + * Constructs the messenger populated with all external actions and events + * required by the service under test. + * + * @returns The root messenger. + */ +function createRootMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); +} + +/** + * Constructs the messenger for the service under test. + * + * @param rootMessenger - The root messenger, with all external actions and + * events required by the controller's messenger. + * @returns The service-specific messenger. + */ +function createServiceMessenger( + rootMessenger: RootMessenger, +): ChompApiServiceMessenger { + return new Messenger({ + namespace: 'ChompApiService', + parent: rootMessenger, + }); +} + +/** + * Constructs the service under test. + * + * @param args - The arguments to this function. + * @param args.options - The options that the service constructor takes. All are + * optional and will be filled in with defaults as needed (including + * `messenger`). + * @returns The new service, root messenger, and service messenger. + */ +function createService({ + options = {}, +}: { + options?: Partial[0]>; +} = {}): { + service: ChompApiService; + rootMessenger: RootMessenger; + messenger: ChompApiServiceMessenger; +} { + const rootMessenger = createRootMessenger(); + const messenger = createServiceMessenger(rootMessenger); + const service = new ChompApiService({ + messenger, + ...options, + }); + + return { service, rootMessenger, messenger }; +} diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts new file mode 100644 index 0000000000..b262ea5171 --- /dev/null +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -0,0 +1,174 @@ +import { BaseDataService } from '@metamask/base-data-service'; +import type { + DataServiceCacheUpdatedEvent, + DataServiceGranularCacheUpdatedEvent, + DataServiceInvalidateQueriesAction, +} from '@metamask/base-data-service'; +import type { CreateServicePolicyOptions } from '@metamask/controller-utils'; +import { HttpError } from '@metamask/controller-utils'; +import type { Messenger } from '@metamask/messenger'; +import type { Infer } from '@metamask/superstruct'; +import { is, object, string } from '@metamask/superstruct'; +import type { QueryClientConfig } from '@tanstack/query-core'; + +import type { ChompApiServiceMethodActions } from './chomp-api-service-method-action-types'; + +// === GENERAL === + +/** + * The name of the {@link ChompApiService}, used to namespace the service's + * actions and events. + */ +export const serviceName = 'ChompApiService'; + +// === MESSENGER === + +/** + * All of the methods within {@link ChompApiService} that are exposed via the + * messenger. + */ +const MESSENGER_EXPOSED_METHODS = ['fetch'] as const; + +/** + * Invalidates cached queries for {@link ChompApiService}. + */ +export type ChompApiServiceInvalidateQueriesAction = + DataServiceInvalidateQueriesAction; + +/** + * Actions that {@link ChompApiService} exposes to other consumers. + */ +export type ChompApiServiceActions = + | ChompApiServiceMethodActions + | ChompApiServiceInvalidateQueriesAction; + +/** + * Actions from other messengers that {@link ChompApiService} calls. + */ +type AllowedActions = never; + +/** + * Published when {@link ChompApiService}'s cache is updated. + */ +export type ChompApiServiceCacheUpdatedEvent = + DataServiceCacheUpdatedEvent; + +/** + * Published when a key within {@link ChompApiService}'s cache is updated. + */ +export type ChompApiServiceGranularCacheUpdatedEvent = + DataServiceGranularCacheUpdatedEvent; + +/** + * Events that {@link ChompApiService} exposes to other consumers. + */ +export type ChompApiServiceEvents = + | ChompApiServiceCacheUpdatedEvent + | ChompApiServiceGranularCacheUpdatedEvent; + +/** + * Events from other messengers that {@link ChompApiService} subscribes to. + */ +type AllowedEvents = never; + +/** + * The messenger which is restricted to actions and events accessed by + * {@link ChompApiService}. + */ +export type ChompApiServiceMessenger = Messenger< + typeof serviceName, + ChompApiServiceActions | AllowedActions, + ChompApiServiceEvents | AllowedEvents +>; + +// === SERVICE DEFINITION === + +// TODO: Define the response struct to match the actual Chomp API response shape. +const ChompResponseStruct = object({ + // TODO: Replace with real fields. + id: string(), +}); + +/** + * What the API endpoint returns. + */ +type ChompResponse = Infer; + +/** + * The base URL of the Chomp API. + */ +// TODO: Replace with the real Chomp API base URL. +const BASE_URL = 'https://api.chomp.example.com'; + +/** + * This service object is responsible for fetching data from the Chomp API. + */ +export class ChompApiService extends BaseDataService< + typeof serviceName, + ChompApiServiceMessenger +> { + /** + * Constructs a new ChompApiService object. + * + * @param args - The constructor arguments. + * @param args.messenger - The messenger suited for this service. + * @param args.queryClientConfig - Configuration for the underlying TanStack + * Query client. + * @param args.policyOptions - Options to pass to `createServicePolicy`, which + * is used to wrap each request. See {@link CreateServicePolicyOptions}. + */ + constructor({ + messenger, + queryClientConfig = {}, + policyOptions = {}, + }: { + messenger: ChompApiServiceMessenger; + queryClientConfig?: QueryClientConfig; + policyOptions?: CreateServicePolicyOptions; + }) { + super({ + name: serviceName, + messenger, + queryClientConfig, + policyOptions, + }); + + this.messenger.registerMethodActionHandlers( + this, + MESSENGER_EXPOSED_METHODS, + ); + } + + /** + * TODO: Replace with a real description of the endpoint this method calls. + * + * @param id - TODO: Describe the parameter. + * @returns TODO: Describe the return value. + */ + async fetch(id: string): Promise { + // TODO: Build the real URL for the Chomp API endpoint. + const url = new URL(`/items/${id}`, BASE_URL); + + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:fetch`, id], + queryFn: async () => { + const response = await fetch(url); + + if (!response.ok) { + throw new HttpError( + response.status, + `Chomp API failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + if (!is(jsonResponse, ChompResponseStruct)) { + throw new Error('Malformed response received from Chomp API'); + } + + return jsonResponse; + } +} diff --git a/packages/chomp-api-service/src/index.ts b/packages/chomp-api-service/src/index.ts new file mode 100644 index 0000000000..4b30fc4773 --- /dev/null +++ b/packages/chomp-api-service/src/index.ts @@ -0,0 +1,13 @@ +export { ChompApiService } from './chomp-api-service'; +export type { + ChompApiServiceMessenger, + ChompApiServiceActions, + ChompApiServiceEvents, + ChompApiServiceInvalidateQueriesAction, + ChompApiServiceCacheUpdatedEvent, + ChompApiServiceGranularCacheUpdatedEvent, +} from './chomp-api-service'; +export type { + ChompApiServiceMethodActions, + ChompApiServiceFetchAction, +} from './chomp-api-service-method-action-types'; diff --git a/packages/chomp-api-service/tsconfig.build.json b/packages/chomp-api-service/tsconfig.build.json new file mode 100644 index 0000000000..c468e8dd1f --- /dev/null +++ b/packages/chomp-api-service/tsconfig.build.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.packages.build.json", + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist", + "rootDir": "./src" + }, + "references": [ + { "path": "../messenger/tsconfig.build.json" }, + { "path": "../controller-utils/tsconfig.build.json" }, + { "path": "../base-data-service/tsconfig.build.json" } + ], + "include": ["../../types", "./src"] +} diff --git a/packages/chomp-api-service/tsconfig.json b/packages/chomp-api-service/tsconfig.json new file mode 100644 index 0000000000..203994e1c3 --- /dev/null +++ b/packages/chomp-api-service/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "baseUrl": "./" + }, + "references": [ + { "path": "../messenger" }, + { "path": "../controller-utils" }, + { "path": "../base-data-service" } + ], + "include": ["../../types", "./src"] +} diff --git a/packages/chomp-api-service/typedoc.json b/packages/chomp-api-service/typedoc.json new file mode 100644 index 0000000000..c9da015dbf --- /dev/null +++ b/packages/chomp-api-service/typedoc.json @@ -0,0 +1,7 @@ +{ + "entryPoints": ["./src/index.ts"], + "excludePrivate": true, + "hideGenerator": true, + "out": "docs", + "tsconfig": "./tsconfig.build.json" +} diff --git a/yarn.lock b/yarn.lock index 1d50842898..4d61d220e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3119,6 +3119,29 @@ __metadata: languageName: unknown linkType: soft +"@metamask/chomp-api-service@workspace:packages/chomp-api-service": + version: 0.0.0-use.local + resolution: "@metamask/chomp-api-service@workspace:packages/chomp-api-service" + dependencies: + "@metamask/auto-changelog": "npm:^3.4.4" + "@metamask/base-data-service": "npm:^0.1.1" + "@metamask/controller-utils": "npm:^11.20.0" + "@metamask/messenger": "npm:^1.1.1" + "@metamask/superstruct": "npm:^3.1.0" + "@metamask/utils": "npm:^11.9.0" + "@tanstack/query-core": "npm:^4.43.0" + "@ts-bridge/cli": "npm:^0.6.4" + "@types/jest": "npm:^29.5.14" + deepmerge: "npm:^4.2.2" + jest: "npm:^29.7.0" + nock: "npm:^13.3.1" + ts-jest: "npm:^29.2.5" + typedoc: "npm:^0.25.13" + typedoc-plugin-missing-exports: "npm:^2.0.0" + typescript: "npm:~5.3.3" + languageName: unknown + linkType: soft + "@metamask/claims-controller@workspace:packages/claims-controller": version: 0.0.0-use.local resolution: "@metamask/claims-controller@workspace:packages/claims-controller" From 052c7817a3f6d9ff77b560e41c96cb38e27854f3 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Thu, 9 Apr 2026 12:30:40 +0100 Subject: [PATCH 02/19] feat: add stubs for all API methods --- packages/chomp-api-service/CHANGELOG.md | 2 +- .../chomp-api-service-method-action-types.ts | 65 ++++- .../src/chomp-api-service.test.ts | 163 +++++++---- .../src/chomp-api-service.ts | 266 ++++++++++++++---- packages/chomp-api-service/src/index.ts | 21 +- packages/chomp-api-service/src/types.ts | 76 +++++ 6 files changed, 488 insertions(+), 105 deletions(-) create mode 100644 packages/chomp-api-service/src/types.ts diff --git a/packages/chomp-api-service/CHANGELOG.md b/packages/chomp-api-service/CHANGELOG.md index 0a6ede27d2..c050ac9419 100644 --- a/packages/chomp-api-service/CHANGELOG.md +++ b/packages/chomp-api-service/CHANGELOG.md @@ -9,6 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `ChompApiService` ([#8361](TODO)) +- Add `ChompApiService` ([#8361](https://github.com/MetaMask/core/pull/8413)) [Unreleased]: https://github.com/MetaMask/core/ diff --git a/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts b/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts index f08d633099..87454e3759 100644 --- a/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts +++ b/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts @@ -6,14 +6,69 @@ import type { ChompApiService } from './chomp-api-service'; /** - * TODO: Add JSDoc description for this action. + * Associates an address with a CHOMP profile via POST /v1/auth/address. */ -export type ChompApiServiceFetchAction = { - type: `ChompApiService:fetch`; - handler: ChompApiService['fetch']; +export type ChompApiServiceAssociateAddressAction = { + type: `ChompApiService:associateAddress`; + handler: ChompApiService['associateAddress']; +}; + +/** + * Creates an account upgrade via POST /v1/account-upgrade. + */ +export type ChompApiServiceCreateUpgradeAction = { + type: `ChompApiService:createUpgrade`; + handler: ChompApiService['createUpgrade']; +}; + +/** + * Fetches the upgrade record for an address via GET /v1/account-upgrade/:address. + */ +export type ChompApiServiceGetUpgradeAction = { + type: `ChompApiService:getUpgrade`; + handler: ChompApiService['getUpgrade']; +}; + +/** + * Verifies a delegation via POST /v1/intent/verify-delegation. + */ +export type ChompApiServiceVerifyDelegationAction = { + type: `ChompApiService:verifyDelegation`; + handler: ChompApiService['verifyDelegation']; +}; + +/** + * Submits intents via POST /v1/intent. + */ +export type ChompApiServiceCreateIntentsAction = { + type: `ChompApiService:createIntents`; + handler: ChompApiService['createIntents']; +}; + +/** + * Fetches intents by address via GET /v1/intent/account/:address. + */ +export type ChompApiServiceGetIntentsByAddressAction = { + type: `ChompApiService:getIntentsByAddress`; + handler: ChompApiService['getIntentsByAddress']; +}; + +/** + * Creates a withdrawal for card spend flows. + */ +export type ChompApiServiceCreateWithdrawalAction = { + type: `ChompApiService:createWithdrawal`; + handler: ChompApiService['createWithdrawal']; }; /** * Union of all ChompApiService action types. */ -export type ChompApiServiceMethodActions = ChompApiServiceFetchAction; +export type ChompApiServiceMethodActions = + | ChompApiServiceAssociateAddressAction + | ChompApiServiceCreateUpgradeAction + | ChompApiServiceGetUpgradeAction + | ChompApiServiceVerifyDelegationAction + | ChompApiServiceCreateIntentsAction + | ChompApiServiceGetIntentsByAddressAction + | ChompApiServiceCreateWithdrawalAction; diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index 663c7b7fad..dec0bab315 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -1,72 +1,139 @@ -import { DEFAULT_MAX_RETRIES } from '@metamask/controller-utils'; import { Messenger, MOCK_ANY_NAMESPACE } from '@metamask/messenger'; import type { MockAnyNamespace, MessengerActions, MessengerEvents, } from '@metamask/messenger'; -import nock from 'nock'; import type { ChompApiServiceMessenger } from './chomp-api-service'; import { ChompApiService } from './chomp-api-service'; +const BASE_URL = 'https://api.chomp.example.com'; +const MOCK_TOKEN = 'mock-jwt-token'; + describe('ChompApiService', () => { - describe('ChompApiService:fetch', () => { - it('returns the response from the API', async () => { - nock('https://api.chomp.example.com') - .get('/items/abc') - .reply(200, { id: 'abc' }); - const { rootMessenger } = createService(); - - const response = await rootMessenger.call( - 'ChompApiService:fetch', - 'abc', - ); + describe('constructor', () => { + it('can be constructed with baseUrl, getAccessToken, and messenger', () => { + const { service } = createService(); + expect(service).toBeInstanceOf(ChompApiService); + }); - expect(response).toStrictEqual({ id: 'abc' }); + it('accepts a custom fetch implementation', () => { + const customFetch = jest.fn(); + const { service } = createService({ + options: { fetchFn: customFetch as unknown as typeof globalThis.fetch }, + }); + expect(service).toBeInstanceOf(ChompApiService); }); + }); - it('throws if the API returns a non-200 status', async () => { - nock('https://api.chomp.example.com') - .get('/items/abc') - .times(DEFAULT_MAX_RETRIES + 1) - .reply(500); - const { rootMessenger } = createService(); + describe('associateAddress', () => { + // TODO: Test POST /v1/auth/address with correct URL, method, headers + // (Authorization: Bearer ), and JSON body { signature, timestamp, address }. + // TODO: Test that 200 returns { profileId, address, status }. + // TODO: Test that 409 returns the response body (not throws). + // TODO: Test that other non-OK statuses throw. + // TODO: Test response validation rejects malformed responses. + it('is registered as a messenger action', async () => { + const { service } = createService(); + await expect(service.associateAddress({ + signature: '0x123', + timestamp: '2026-01-01T00:00:00Z', + address: '0xabc', + })).rejects.toThrow('Not implemented'); + }); + }); + + describe('createUpgrade', () => { + // TODO: Test POST /v1/account-upgrade with correct URL, method, headers + // (Authorization: Bearer ), and JSON body { r, s, v, yParity, address, chainId, nonce }. + // TODO: Test that 200 returns { signerAddress, status, createdAt }. + // TODO: Test that non-OK statuses throw. + // TODO: Test response validation rejects malformed responses. + it('is registered as a messenger action', async () => { + const { service } = createService(); + await expect(service.createUpgrade({ + r: '0x1', + s: '0x2', + v: 27, + yParity: 0, + address: '0xabc', + chainId: '1', + nonce: '0', + })).rejects.toThrow('Not implemented'); + }); + }); - await expect( - rootMessenger.call('ChompApiService:fetch', 'abc'), - ).rejects.toThrow("Chomp API failed with status '500'"); + describe('getUpgrade', () => { + // TODO: Test GET /v1/account-upgrade/:address with correct URL, method, + // and headers (Authorization: Bearer ). + // TODO: Test that 200 returns the upgrade record. + // TODO: Test that 404 returns null. + // TODO: Test that other non-OK statuses throw. + // TODO: Test response validation rejects malformed responses. + it('is registered as a messenger action', async () => { + const { service } = createService(); + await expect(service.getUpgrade('0xabc')).rejects.toThrow( + 'Not implemented', + ); }); + }); - it.each([ - 'not an object', - { missing: 'id' }, - { id: 123 }, - ])( - 'throws if the API returns a malformed response %o', - async (response) => { - nock('https://api.chomp.example.com') - .get('/items/abc') - .reply(200, JSON.stringify(response)); - const { rootMessenger } = createService(); - - await expect( - rootMessenger.call('ChompApiService:fetch', 'abc'), - ).rejects.toThrow('Malformed response received from Chomp API'); - }, - ); + describe('verifyDelegation', () => { + // TODO: Test POST /v1/intent/verify-delegation with correct URL, method, + // headers (Authorization: Bearer ), and JSON body { signedDelegation, chainId }. + // TODO: Test that 200 returns { valid, delegationHash?, errors? }. + // TODO: Test that non-OK statuses throw. + // TODO: Test response validation rejects malformed responses. + it('is registered as a messenger action', async () => { + const { service } = createService(); + await expect(service.verifyDelegation({ + signedDelegation: '0x123', + chainId: '1', + })).rejects.toThrow('Not implemented'); + }); }); - describe('fetch', () => { - it('does the same thing as the messenger action', async () => { - nock('https://api.chomp.example.com') - .get('/items/abc') - .reply(200, { id: 'abc' }); + describe('createIntents', () => { + // TODO: Test POST /v1/intent with correct URL, method, headers + // (Authorization: Bearer ), and JSON body (array of intents). + // TODO: Test that 200 returns SendIntentResponse[]. + // TODO: Test that non-OK statuses throw. + // TODO: Test response validation rejects malformed responses. + it('is registered as a messenger action', async () => { const { service } = createService(); + await expect(service.createIntents([{ foo: 'bar' }])).rejects.toThrow( + 'Not implemented', + ); + }); + }); - const response = await service.fetch('abc'); + describe('getIntentsByAddress', () => { + // TODO: Test GET /v1/intent/account/:address with correct URL, method, + // and headers (Authorization: Bearer ). + // TODO: Test that 200 returns an array of intents. + // TODO: Test that non-OK statuses throw. + // TODO: Test response validation rejects malformed responses. + it('is registered as a messenger action', async () => { + const { service } = createService(); + await expect(service.getIntentsByAddress('0xabc')).rejects.toThrow( + 'Not implemented', + ); + }); + }); - expect(response).toStrictEqual({ id: 'abc' }); + describe('createWithdrawal', () => { + // TODO: Confirm endpoint path against CHOMP API docs. + // TODO: Test POST to the withdrawal endpoint with correct URL, method, + // headers (Authorization: Bearer ), and JSON body. + // TODO: Test that 200 returns the withdrawal result. + // TODO: Test that non-OK statuses throw. + // TODO: Test response validation rejects malformed responses. + it('is registered as a messenger action', async () => { + const { service } = createService(); + await expect(service.createWithdrawal({})).rejects.toThrow( + 'Not implemented', + ); }); }); }); @@ -128,6 +195,8 @@ function createService({ const rootMessenger = createRootMessenger(); const messenger = createServiceMessenger(rootMessenger); const service = new ChompApiService({ + baseUrl: BASE_URL, + getAccessToken: async () => MOCK_TOKEN, messenger, ...options, }); diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index b262ea5171..25b4d2d7d1 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -5,13 +5,23 @@ import type { DataServiceInvalidateQueriesAction, } from '@metamask/base-data-service'; import type { CreateServicePolicyOptions } from '@metamask/controller-utils'; -import { HttpError } from '@metamask/controller-utils'; import type { Messenger } from '@metamask/messenger'; -import type { Infer } from '@metamask/superstruct'; -import { is, object, string } from '@metamask/superstruct'; import type { QueryClientConfig } from '@tanstack/query-core'; import type { ChompApiServiceMethodActions } from './chomp-api-service-method-action-types'; +import type { + AssociateAddressRequest, + AssociateAddressResponse, + CreateUpgradeRequest, + CreateUpgradeResponse, + CreateWithdrawalRequest, + CreateWithdrawalResponse, + GetUpgradeResponse, + SendIntentRequest, + SendIntentResponse, + VerifyDelegationRequest, + VerifyDelegationResponse, +} from './types'; // === GENERAL === @@ -27,7 +37,15 @@ export const serviceName = 'ChompApiService'; * All of the methods within {@link ChompApiService} that are exposed via the * messenger. */ -const MESSENGER_EXPOSED_METHODS = ['fetch'] as const; +const MESSENGER_EXPOSED_METHODS = [ + 'associateAddress', + 'createUpgrade', + 'getUpgrade', + 'verifyDelegation', + 'createIntents', + 'getIntentsByAddress', + 'createWithdrawal', +] as const; /** * Invalidates cached queries for {@link ChompApiService}. @@ -83,46 +101,48 @@ export type ChompApiServiceMessenger = Messenger< // === SERVICE DEFINITION === -// TODO: Define the response struct to match the actual Chomp API response shape. -const ChompResponseStruct = object({ - // TODO: Replace with real fields. - id: string(), -}); - -/** - * What the API endpoint returns. - */ -type ChompResponse = Infer; - -/** - * The base URL of the Chomp API. - */ -// TODO: Replace with the real Chomp API base URL. -const BASE_URL = 'https://api.chomp.example.com'; - /** - * This service object is responsible for fetching data from the Chomp API. + * This service is responsible for communicating with the CHOMP API. + * + * All requests are authenticated via JWT Bearer tokens obtained from the + * `getAccessToken` callback provided at construction time. */ export class ChompApiService extends BaseDataService< typeof serviceName, ChompApiServiceMessenger > { + readonly #baseUrl: string; + + readonly #getAccessToken: () => Promise; + + readonly #fetch: typeof globalThis.fetch; + /** - * Constructs a new ChompApiService object. + * Constructs a new ChompApiService. * * @param args - The constructor arguments. * @param args.messenger - The messenger suited for this service. + * @param args.baseUrl - The base URL of the CHOMP API. + * @param args.getAccessToken - An async callback that returns a valid JWT + * access token for authenticating requests. + * @param args.fetchFn - An optional custom fetch implementation. Defaults to + * the global `fetch`. * @param args.queryClientConfig - Configuration for the underlying TanStack * Query client. - * @param args.policyOptions - Options to pass to `createServicePolicy`, which - * is used to wrap each request. See {@link CreateServicePolicyOptions}. + * @param args.policyOptions - Options to pass to `createServicePolicy`. */ constructor({ messenger, + baseUrl, + getAccessToken, + fetchFn = globalThis.fetch, queryClientConfig = {}, policyOptions = {}, }: { messenger: ChompApiServiceMessenger; + baseUrl: string; + getAccessToken: () => Promise; + fetchFn?: typeof globalThis.fetch; queryClientConfig?: QueryClientConfig; policyOptions?: CreateServicePolicyOptions; }) { @@ -133,6 +153,10 @@ export class ChompApiService extends BaseDataService< policyOptions, }); + this.#baseUrl = baseUrl; + this.#getAccessToken = getAccessToken; + this.#fetch = fetchFn; + this.messenger.registerMethodActionHandlers( this, MESSENGER_EXPOSED_METHODS, @@ -140,35 +164,175 @@ export class ChompApiService extends BaseDataService< } /** - * TODO: Replace with a real description of the endpoint this method calls. + * Builds the standard headers for an authenticated CHOMP API request. * - * @param id - TODO: Describe the parameter. - * @returns TODO: Describe the return value. + * @returns Headers including Authorization and Content-Type. */ - async fetch(id: string): Promise { - // TODO: Build the real URL for the Chomp API endpoint. - const url = new URL(`/items/${id}`, BASE_URL); - - const jsonResponse = await this.fetchQuery({ - queryKey: [`${this.name}:fetch`, id], - queryFn: async () => { - const response = await fetch(url); - - if (!response.ok) { - throw new HttpError( - response.status, - `Chomp API failed with status '${response.status}'`, - ); - } - - return response.json(); - }, - }); + async #authHeaders(): Promise> { + const token = await this.#getAccessToken(); + return { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }; + } + + /** + * Associates an address with a CHOMP profile. + * + * POST /v1/auth/address + * + * TODO: Implement the request using this.fetchQuery or direct POST via + * this.#fetch. Validate the response with a superstruct. Note that a 409 + * response is valid and should be returned (not thrown). + * + * @param request - The association request containing signature, timestamp, + * and address. + * @returns The profile association result. + */ + async associateAddress( + request: AssociateAddressRequest, + ): Promise { + // TODO: POST to `${this.#baseUrl}/v1/auth/address` with JSON body. + // TODO: Include Authorization header via this.#authHeaders(). + // TODO: Return response body on 200 or 409; throw on other non-OK statuses. + // TODO: Validate response shape with superstruct before returning. + const _headers = await this.#authHeaders(); + void request; + throw new Error('Not implemented'); + } - if (!is(jsonResponse, ChompResponseStruct)) { - throw new Error('Malformed response received from Chomp API'); - } + /** + * Creates an account upgrade request. + * + * POST /v1/account-upgrade + * + * TODO: Implement the POST request. Validate the response with a superstruct. + * + * @param request - The upgrade request containing signature components and + * chain details. + * @returns The upgrade result. + */ + async createUpgrade( + request: CreateUpgradeRequest, + ): Promise { + // TODO: POST to `${this.#baseUrl}/v1/account-upgrade` with JSON body. + // TODO: Include Authorization header via this.#authHeaders(). + // TODO: Throw on non-OK responses. + // TODO: Validate response shape with superstruct before returning. + const _headers = await this.#authHeaders(); + void request; + throw new Error('Not implemented'); + } - return jsonResponse; + /** + * Fetches the upgrade record for a given address. + * + * GET /v1/account-upgrade/:address + * + * TODO: Implement the GET request. Return null on 404. Validate the response + * with a superstruct for non-404 responses. + * + * @param address - The address to look up. + * @returns The upgrade record, or null if not found. + */ + async getUpgrade(address: string): Promise { + // TODO: GET `${this.#baseUrl}/v1/account-upgrade/${address}`. + // TODO: Include Authorization header via this.#authHeaders(). + // TODO: Return null on 404, throw on other non-OK statuses. + // TODO: Validate response shape with superstruct before returning. + // TODO: Consider using this.fetchQuery with a queryKey for caching. + const _headers = await this.#authHeaders(); + void address; + throw new Error('Not implemented'); + } + + /** + * Verifies a delegation signature. + * + * POST /v1/intent/verify-delegation + * + * TODO: Implement the POST request. Validate the response with a superstruct. + * + * @param request - The delegation verification request. + * @returns The verification result including validity and optional errors. + */ + async verifyDelegation( + request: VerifyDelegationRequest, + ): Promise { + // TODO: POST to `${this.#baseUrl}/v1/intent/verify-delegation` with JSON body. + // TODO: Include Authorization header via this.#authHeaders(). + // TODO: Throw on non-OK responses. + // TODO: Validate response shape with superstruct before returning. + const _headers = await this.#authHeaders(); + void request; + throw new Error('Not implemented'); + } + + /** + * Submits one or more intents to the CHOMP API. + * + * POST /v1/intent + * + * TODO: Implement the POST request. Validate the response array with a + * superstruct. + * + * @param intents - The array of intents to submit. + * @returns The array of intent responses. + */ + async createIntents( + intents: SendIntentRequest[], + ): Promise { + // TODO: POST to `${this.#baseUrl}/v1/intent` with JSON body. + // TODO: Include Authorization header via this.#authHeaders(). + // TODO: Throw on non-OK responses. + // TODO: Validate response shape with superstruct before returning. + const _headers = await this.#authHeaders(); + void intents; + throw new Error('Not implemented'); + } + + /** + * Fetches intents associated with a given address. + * + * GET /v1/intent/account/:address + * + * TODO: Implement the GET request. Validate the response array with a + * superstruct. + * + * @param address - The address to look up intents for. + * @returns The array of intents for the address. + */ + async getIntentsByAddress( + address: string, + ): Promise { + // TODO: GET `${this.#baseUrl}/v1/intent/account/${address}`. + // TODO: Include Authorization header via this.#authHeaders(). + // TODO: Throw on non-OK responses. + // TODO: Validate response shape with superstruct before returning. + // TODO: Consider using this.fetchQuery with a queryKey for caching. + const _headers = await this.#authHeaders(); + void address; + throw new Error('Not implemented'); + } + + /** + * Creates a withdrawal for card spend flows. + * + * TODO: Confirm the endpoint path against CHOMP API docs. + * TODO: Implement the POST request. Validate the response with a superstruct. + * + * @param request - The withdrawal request. + * @returns The withdrawal result. + */ + async createWithdrawal( + request: CreateWithdrawalRequest, + ): Promise { + // TODO: Confirm endpoint path (e.g. POST `${this.#baseUrl}/v1/withdrawal`). + // TODO: Include Authorization header via this.#authHeaders(). + // TODO: Throw on non-OK responses. + // TODO: Validate response shape with superstruct before returning. + const _headers = await this.#authHeaders(); + void request; + throw new Error('Not implemented'); } } diff --git a/packages/chomp-api-service/src/index.ts b/packages/chomp-api-service/src/index.ts index 4b30fc4773..bcc77031af 100644 --- a/packages/chomp-api-service/src/index.ts +++ b/packages/chomp-api-service/src/index.ts @@ -9,5 +9,24 @@ export type { } from './chomp-api-service'; export type { ChompApiServiceMethodActions, - ChompApiServiceFetchAction, + ChompApiServiceAssociateAddressAction, + ChompApiServiceCreateUpgradeAction, + ChompApiServiceGetUpgradeAction, + ChompApiServiceVerifyDelegationAction, + ChompApiServiceCreateIntentsAction, + ChompApiServiceGetIntentsByAddressAction, + ChompApiServiceCreateWithdrawalAction, } from './chomp-api-service-method-action-types'; +export type { + AssociateAddressRequest, + AssociateAddressResponse, + CreateUpgradeRequest, + CreateUpgradeResponse, + GetUpgradeResponse, + VerifyDelegationRequest, + VerifyDelegationResponse, + SendIntentRequest, + SendIntentResponse, + CreateWithdrawalRequest, + CreateWithdrawalResponse, +} from './types'; diff --git a/packages/chomp-api-service/src/types.ts b/packages/chomp-api-service/src/types.ts new file mode 100644 index 0000000000..b3a253cce5 --- /dev/null +++ b/packages/chomp-api-service/src/types.ts @@ -0,0 +1,76 @@ +// === REQUEST TYPES === + +export type AssociateAddressRequest = { + signature: string; + timestamp: string; + address: string; +}; + +export type CreateUpgradeRequest = { + r: string; + s: string; + v: number; + yParity: number; + address: string; + chainId: string; + nonce: string; +}; + +export type VerifyDelegationRequest = { + signedDelegation: string; + chainId: string; +}; + +/** + * A single intent to be submitted to the Chomp API. + * TODO: Define the full shape of an intent once the API schema is confirmed. + */ +export type SendIntentRequest = Record; + +/** + * TODO: Define request shape once the withdrawal endpoint path and schema are + * confirmed against CHOMP API docs. + */ +export type CreateWithdrawalRequest = Record; + +// === RESPONSE TYPES === + +export type AssociateAddressResponse = { + profileId: string; + address: string; + status: string; +}; + +export type CreateUpgradeResponse = { + signerAddress: string; + status: string; + createdAt: string; +}; + +/** + * The upgrade record returned by GET /v1/account-upgrade/:address. + * TODO: Confirm full shape against CHOMP API docs. + */ +export type GetUpgradeResponse = { + signerAddress: string; + status: string; + createdAt: string; +}; + +export type VerifyDelegationResponse = { + valid: boolean; + delegationHash?: string; + errors?: string[]; +}; + +/** + * A single intent response. + * TODO: Define the full shape once the API schema is confirmed. + */ +export type SendIntentResponse = Record; + +/** + * TODO: Define response shape once the withdrawal endpoint path and schema are + * confirmed against CHOMP API docs. + */ +export type CreateWithdrawalResponse = Record; From 2b636cce7316c4616c30023b81bb598dfb0a18cc Mon Sep 17 00:00:00 2001 From: John Whiles Date: Fri, 10 Apr 2026 11:05:17 +0100 Subject: [PATCH 03/19] feat: add implementation of chomp-api --- .../src/chomp-api-service.test.ts | 484 +++++++++++++++--- .../src/chomp-api-service.ts | 263 +++++++--- packages/chomp-api-service/src/index.ts | 14 +- packages/chomp-api-service/src/types.ts | 93 +++- 4 files changed, 662 insertions(+), 192 deletions(-) diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index dec0bab315..0c79cc6307 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -1,9 +1,11 @@ +import { DEFAULT_MAX_RETRIES } from '@metamask/controller-utils'; import { Messenger, MOCK_ANY_NAMESPACE } from '@metamask/messenger'; import type { MockAnyNamespace, MessengerActions, MessengerEvents, } from '@metamask/messenger'; +import nock from 'nock'; import type { ChompApiServiceMessenger } from './chomp-api-service'; import { ChompApiService } from './chomp-api-service'; @@ -12,127 +14,445 @@ const BASE_URL = 'https://api.chomp.example.com'; const MOCK_TOKEN = 'mock-jwt-token'; describe('ChompApiService', () => { - describe('constructor', () => { - it('can be constructed with baseUrl, getAccessToken, and messenger', () => { - const { service } = createService(); - expect(service).toBeInstanceOf(ChompApiService); - }); + describe('associateAddress', () => { + it('sends a POST with auth headers and returns the response on 201', async () => { + nock(BASE_URL) + .post('/v1/auth/address', { + signature: '0x123', + timestamp: '2026-01-01T00:00:00Z', + address: '0xabc', + }) + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .matchHeader('Content-Type', 'application/json') + .reply(201, { + profileId: 'p1', + address: '0xabc', + status: 'created', + }); + const { rootMessenger } = createService(); + + const result = await rootMessenger.call( + 'ChompApiService:associateAddress', + { + signature: '0x123', + timestamp: '2026-01-01T00:00:00Z', + address: '0xabc', + }, + ); - it('accepts a custom fetch implementation', () => { - const customFetch = jest.fn(); - const { service } = createService({ - options: { fetchFn: customFetch as unknown as typeof globalThis.fetch }, + expect(result).toStrictEqual({ + profileId: 'p1', + address: '0xabc', + status: 'created', }); - expect(service).toBeInstanceOf(ChompApiService); }); - }); - describe('associateAddress', () => { - // TODO: Test POST /v1/auth/address with correct URL, method, headers - // (Authorization: Bearer ), and JSON body { signature, timestamp, address }. - // TODO: Test that 200 returns { profileId, address, status }. - // TODO: Test that 409 returns the response body (not throws). - // TODO: Test that other non-OK statuses throw. - // TODO: Test response validation rejects malformed responses. - it('is registered as a messenger action', async () => { - const { service } = createService(); - await expect(service.associateAddress({ + it('returns the response on 409 without throwing', async () => { + nock(BASE_URL).post('/v1/auth/address').reply(409, { + profileId: 'p1', + address: '0xabc', + status: 'already_associated', + }); + const { service } = createService(); + + const result = await service.associateAddress({ signature: '0x123', timestamp: '2026-01-01T00:00:00Z', address: '0xabc', - })).rejects.toThrow('Not implemented'); + }); + + expect(result).toStrictEqual({ + profileId: 'p1', + address: '0xabc', + status: 'already_associated', + }); + }); + + it('throws on non-201/409 status', async () => { + nock(BASE_URL) + .post('/v1/auth/address') + .times(DEFAULT_MAX_RETRIES + 1) + .reply(500); + const { service } = createService(); + + await expect( + service.associateAddress({ + signature: '0x123', + timestamp: '2026-01-01T00:00:00Z', + address: '0xabc', + }), + ).rejects.toThrow("POST /v1/auth/address failed with status '500'"); + }); + + it('throws on malformed response', async () => { + nock(BASE_URL) + .post('/v1/auth/address') + .reply(201, JSON.stringify({ missing: 'fields' })); + const { service } = createService(); + + await expect( + service.associateAddress({ + signature: '0x123', + timestamp: '2026-01-01T00:00:00Z', + address: '0xabc', + }), + ).rejects.toThrow('At path: profileId -- Expected a string'); }); }); describe('createUpgrade', () => { - // TODO: Test POST /v1/account-upgrade with correct URL, method, headers - // (Authorization: Bearer ), and JSON body { r, s, v, yParity, address, chainId, nonce }. - // TODO: Test that 200 returns { signerAddress, status, createdAt }. - // TODO: Test that non-OK statuses throw. - // TODO: Test response validation rejects malformed responses. - it('is registered as a messenger action', async () => { - const { service } = createService(); - await expect(service.createUpgrade({ - r: '0x1', - s: '0x2', - v: 27, - yParity: 0, - address: '0xabc', - chainId: '1', - nonce: '0', - })).rejects.toThrow('Not implemented'); + const upgradeRequest = { + r: '0x1', + s: '0x2', + v: 27, + yParity: 0, + address: '0xabc', + chainId: '1', + nonce: '0', + }; + + const upgradeResponse = { + signerAddress: '0xdef', + status: 'pending', + createdAt: '2026-01-01T00:00:00Z', + }; + + it('sends a POST with auth headers and returns the response', async () => { + nock(BASE_URL) + .post('/v1/account-upgrade', upgradeRequest) + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .reply(200, upgradeResponse); + const { rootMessenger } = createService(); + + const result = await rootMessenger.call( + 'ChompApiService:createUpgrade', + upgradeRequest, + ); + + expect(result).toStrictEqual(upgradeResponse); + }); + + it('throws on non-OK status', async () => { + nock(BASE_URL) + .post('/v1/account-upgrade') + .times(DEFAULT_MAX_RETRIES + 1) + .reply(500); + const { service } = createService(); + + await expect(service.createUpgrade(upgradeRequest)).rejects.toThrow( + "POST /v1/account-upgrade failed with status '500'", + ); + }); + + it('throws on malformed response', async () => { + nock(BASE_URL) + .post('/v1/account-upgrade') + .reply(200, JSON.stringify({ bad: 'data' })); + const { service } = createService(); + + await expect(service.createUpgrade(upgradeRequest)).rejects.toThrow( + 'At path: signerAddress -- Expected a string', + ); }); }); describe('getUpgrade', () => { - // TODO: Test GET /v1/account-upgrade/:address with correct URL, method, - // and headers (Authorization: Bearer ). - // TODO: Test that 200 returns the upgrade record. - // TODO: Test that 404 returns null. - // TODO: Test that other non-OK statuses throw. - // TODO: Test response validation rejects malformed responses. - it('is registered as a messenger action', async () => { + const upgradeRecord = { + signerAddress: '0xdef', + status: 'pending', + createdAt: '2026-01-01T00:00:00Z', + }; + + it('sends a GET with auth headers and returns the upgrade record', async () => { + nock(BASE_URL) + .get('/v1/account-upgrade/0xabc') + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .reply(200, upgradeRecord); + const { rootMessenger } = createService(); + + const result = await rootMessenger.call( + 'ChompApiService:getUpgrade', + '0xabc', + ); + + expect(result).toStrictEqual(upgradeRecord); + }); + + it('returns null on 404', async () => { + nock(BASE_URL).get('/v1/account-upgrade/0xabc').reply(404); const { service } = createService(); + + const result = await service.getUpgrade('0xabc'); + + expect(result).toBeNull(); + }); + + it('throws on non-OK/non-404 status', async () => { + nock(BASE_URL) + .get('/v1/account-upgrade/0xabc') + .times(DEFAULT_MAX_RETRIES + 1) + .reply(500); + const { service } = createService(); + await expect(service.getUpgrade('0xabc')).rejects.toThrow( - 'Not implemented', + "Get upgrade request failed with status '500'", + ); + }); + + it('throws on malformed response', async () => { + nock(BASE_URL) + .get('/v1/account-upgrade/0xabc') + .reply(200, JSON.stringify({ bad: 'data' })); + const { service } = createService(); + + await expect(service.getUpgrade('0xabc')).rejects.toThrow( + 'At path: signerAddress -- Expected a string', ); }); }); describe('verifyDelegation', () => { - // TODO: Test POST /v1/intent/verify-delegation with correct URL, method, - // headers (Authorization: Bearer ), and JSON body { signedDelegation, chainId }. - // TODO: Test that 200 returns { valid, delegationHash?, errors? }. - // TODO: Test that non-OK statuses throw. - // TODO: Test response validation rejects malformed responses. - it('is registered as a messenger action', async () => { - const { service } = createService(); - await expect(service.verifyDelegation({ - signedDelegation: '0x123', - chainId: '1', - })).rejects.toThrow('Not implemented'); + const delegationRequest = { + signedDelegation: { + delegate: '0x1' as const, + delegator: '0x2' as const, + authority: '0x3' as const, + caveats: [], + salt: '0x4' as const, + signature: '0x5' as const, + }, + chainId: '0x1' as const, + }; + + it('sends a POST with auth headers and returns the response', async () => { + nock(BASE_URL) + .post('/v1/intent/verify-delegation', delegationRequest) + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .reply(200, { valid: true, delegationHash: '0xhash123' }); + const { rootMessenger } = createService(); + + const result = await rootMessenger.call( + 'ChompApiService:verifyDelegation', + delegationRequest, + ); + + expect(result).toStrictEqual({ + valid: true, + delegationHash: '0xhash123', + }); + }); + + it('returns errors when delegation is invalid', async () => { + nock(BASE_URL) + .post('/v1/intent/verify-delegation') + .reply(200, { valid: false, errors: ['bad signature'] }); + const { service } = createService(); + + const result = await service.verifyDelegation(delegationRequest); + + expect(result).toStrictEqual({ + valid: false, + errors: ['bad signature'], + }); + }); + + it('throws on non-OK status', async () => { + nock(BASE_URL) + .post('/v1/intent/verify-delegation') + .times(DEFAULT_MAX_RETRIES + 1) + .reply(400); + const { service } = createService(); + + await expect(service.verifyDelegation(delegationRequest)).rejects.toThrow( + "POST /v1/intent/verify-delegation failed with status '400'", + ); + }); + + it('throws on malformed response', async () => { + nock(BASE_URL) + .post('/v1/intent/verify-delegation') + .reply(200, JSON.stringify({ bad: 'data' })); + const { service } = createService(); + + await expect(service.verifyDelegation(delegationRequest)).rejects.toThrow( + 'At path: valid -- Expected a value of type `boolean`', + ); }); }); describe('createIntents', () => { - // TODO: Test POST /v1/intent with correct URL, method, headers - // (Authorization: Bearer ), and JSON body (array of intents). - // TODO: Test that 200 returns SendIntentResponse[]. - // TODO: Test that non-OK statuses throw. - // TODO: Test response validation rejects malformed responses. - it('is registered as a messenger action', async () => { + const intentRequest = [ + { + account: '0xabc' as const, + delegationHash: '0xdef' as const, + chainId: '0x1' as const, + metadata: { + allowance: '0xff' as const, + tokenSymbol: 'USDC', + tokenAddress: '0x123' as const, + type: 'cash-deposit' as const, + }, + }, + ]; + + const intentResponse = [ + { + delegationHash: '0xdef', + metadata: { + allowance: '0xff', + tokenSymbol: 'USDC', + tokenAddress: '0x123', + type: 'cash-deposit', + }, + createdAt: '2026-01-01T00:00:00Z', + }, + ]; + + it('sends a POST with auth headers and returns the response array', async () => { + nock(BASE_URL) + .post('/v1/intent', intentRequest) + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .reply(201, intentResponse); + const { rootMessenger } = createService(); + + const result = await rootMessenger.call( + 'ChompApiService:createIntents', + intentRequest, + ); + + expect(result).toStrictEqual(intentResponse); + }); + + it('throws on non-OK status', async () => { + nock(BASE_URL) + .post('/v1/intent') + .times(DEFAULT_MAX_RETRIES + 1) + .reply(409); const { service } = createService(); - await expect(service.createIntents([{ foo: 'bar' }])).rejects.toThrow( - 'Not implemented', + + await expect(service.createIntents(intentRequest)).rejects.toThrow( + "POST /v1/intent failed with status '409'", + ); + }); + + it('throws on malformed response', async () => { + nock(BASE_URL) + .post('/v1/intent') + .reply(201, JSON.stringify([{ bad: 'data' }])); + const { service } = createService(); + + await expect(service.createIntents(intentRequest)).rejects.toThrow( + 'At path: 0.delegationHash -- Expected a string', ); }); }); describe('getIntentsByAddress', () => { - // TODO: Test GET /v1/intent/account/:address with correct URL, method, - // and headers (Authorization: Bearer ). - // TODO: Test that 200 returns an array of intents. - // TODO: Test that non-OK statuses throw. - // TODO: Test response validation rejects malformed responses. - it('is registered as a messenger action', async () => { + const intentsResponse = [ + { + account: '0xabc', + delegationHash: '0xdef', + chainId: '0x1', + status: 'active', + metadata: { + allowance: '0xff', + tokenAddress: '0x123', + tokenSymbol: 'USDC', + type: 'deposit', + }, + }, + ]; + + it('sends a GET with auth headers and returns the intents array', async () => { + nock(BASE_URL) + .get('/v1/intent/account/0xabc') + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .reply(200, intentsResponse); + const { rootMessenger } = createService(); + + const result = await rootMessenger.call( + 'ChompApiService:getIntentsByAddress', + '0xabc', + ); + + expect(result).toStrictEqual(intentsResponse); + }); + + it('returns an empty array when no intents exist', async () => { + nock(BASE_URL).get('/v1/intent/account/0xabc').reply(200, []); + const { service } = createService(); + + const result = await service.getIntentsByAddress('0xabc'); + + expect(result).toStrictEqual([]); + }); + + it('throws on non-OK status', async () => { + nock(BASE_URL) + .get('/v1/intent/account/0xabc') + .times(DEFAULT_MAX_RETRIES + 1) + .reply(500); + const { service } = createService(); + + await expect(service.getIntentsByAddress('0xabc')).rejects.toThrow( + "Get intents request failed with status '500'", + ); + }); + + it('throws on malformed response', async () => { + nock(BASE_URL) + .get('/v1/intent/account/0xabc') + .reply(200, JSON.stringify([{ bad: 'data' }])); const { service } = createService(); + await expect(service.getIntentsByAddress('0xabc')).rejects.toThrow( - 'Not implemented', + 'At path: 0.account -- Expected a string', ); }); }); describe('createWithdrawal', () => { - // TODO: Confirm endpoint path against CHOMP API docs. - // TODO: Test POST to the withdrawal endpoint with correct URL, method, - // headers (Authorization: Bearer ), and JSON body. - // TODO: Test that 200 returns the withdrawal result. - // TODO: Test that non-OK statuses throw. - // TODO: Test response validation rejects malformed responses. - it('is registered as a messenger action', async () => { + const withdrawalRequest = { + chainId: '0x1' as const, + amount: '1000000', + account: '0xabc' as const, + }; + + it('sends a POST with auth headers and returns the response', async () => { + nock(BASE_URL) + .post('/v1/withdrawal', withdrawalRequest) + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .reply(200, { success: true }); + const { rootMessenger } = createService(); + + const result = await rootMessenger.call( + 'ChompApiService:createWithdrawal', + withdrawalRequest, + ); + + expect(result).toStrictEqual({ success: true }); + }); + + it('throws on non-OK status', async () => { + nock(BASE_URL) + .post('/v1/withdrawal') + .times(DEFAULT_MAX_RETRIES + 1) + .reply(400); const { service } = createService(); - await expect(service.createWithdrawal({})).rejects.toThrow( - 'Not implemented', + + await expect(service.createWithdrawal(withdrawalRequest)).rejects.toThrow( + "POST /v1/withdrawal failed with status '400'", + ); + }); + + it('throws on malformed response', async () => { + nock(BASE_URL) + .post('/v1/withdrawal') + .reply(200, JSON.stringify({ success: false })); + const { service } = createService(); + + await expect(service.createWithdrawal(withdrawalRequest)).rejects.toThrow( + 'At path: success -- Expected the literal `true`', ); }); }); @@ -196,7 +516,7 @@ function createService({ const messenger = createServiceMessenger(rootMessenger); const service = new ChompApiService({ baseUrl: BASE_URL, - getAccessToken: async () => MOCK_TOKEN, + getAccessToken: async (): Promise => MOCK_TOKEN, messenger, ...options, }); diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index 25b4d2d7d1..ffe34f79e0 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -4,8 +4,22 @@ import type { DataServiceGranularCacheUpdatedEvent, DataServiceInvalidateQueriesAction, } from '@metamask/base-data-service'; -import type { CreateServicePolicyOptions } from '@metamask/controller-utils'; +import type { + CreateServicePolicyOptions, + ServicePolicy, +} from '@metamask/controller-utils'; +import { createServicePolicy, HttpError } from '@metamask/controller-utils'; import type { Messenger } from '@metamask/messenger'; +import { + array, + boolean, + create, + enums, + literal, + optional, + string, + type, +} from '@metamask/superstruct'; import type { QueryClientConfig } from '@tanstack/query-core'; import type { ChompApiServiceMethodActions } from './chomp-api-service-method-action-types'; @@ -17,6 +31,7 @@ import type { CreateWithdrawalRequest, CreateWithdrawalResponse, GetUpgradeResponse, + IntentEntry, SendIntentRequest, SendIntentResponse, VerifyDelegationRequest, @@ -68,8 +83,9 @@ type AllowedActions = never; /** * Published when {@link ChompApiService}'s cache is updated. */ -export type ChompApiServiceCacheUpdatedEvent = - DataServiceCacheUpdatedEvent; +export type ChompApiServiceCacheUpdatedEvent = DataServiceCacheUpdatedEvent< + typeof serviceName +>; /** * Published when a key within {@link ChompApiService}'s cache is updated. @@ -99,6 +115,58 @@ export type ChompApiServiceMessenger = Messenger< ChompApiServiceEvents | AllowedEvents >; +// === RESPONSE VALIDATION === + +const AssociateAddressResponseStruct = type({ + profileId: string(), + address: string(), + status: string(), +}); + +const UpgradeResponseStruct = type({ + signerAddress: string(), + status: string(), + createdAt: string(), +}); + +const VerifyDelegationResponseStruct = type({ + valid: boolean(), + delegationHash: optional(string()), + errors: optional(array(string())), +}); + +const SendIntentResponseArrayStruct = array( + type({ + delegationHash: string(), + metadata: type({ + allowance: string(), + tokenSymbol: string(), + tokenAddress: string(), + type: enums(['cash-deposit', 'cash-withdrawal']), + }), + createdAt: string(), + }), +); + +const IntentEntryArrayStruct = array( + type({ + account: string(), + delegationHash: string(), + chainId: string(), + status: enums(['active', 'revoked']), + metadata: type({ + allowance: string(), + tokenAddress: string(), + tokenSymbol: string(), + type: enums(['deposit', 'withdraw']), + }), + }), +); + +const CreateWithdrawalResponseStruct = type({ + success: literal(true), +}); + // === SERVICE DEFINITION === /** @@ -115,7 +183,7 @@ export class ChompApiService extends BaseDataService< readonly #getAccessToken: () => Promise; - readonly #fetch: typeof globalThis.fetch; + readonly #mutationPolicy: ServicePolicy; /** * Constructs a new ChompApiService. @@ -125,8 +193,6 @@ export class ChompApiService extends BaseDataService< * @param args.baseUrl - The base URL of the CHOMP API. * @param args.getAccessToken - An async callback that returns a valid JWT * access token for authenticating requests. - * @param args.fetchFn - An optional custom fetch implementation. Defaults to - * the global `fetch`. * @param args.queryClientConfig - Configuration for the underlying TanStack * Query client. * @param args.policyOptions - Options to pass to `createServicePolicy`. @@ -135,14 +201,12 @@ export class ChompApiService extends BaseDataService< messenger, baseUrl, getAccessToken, - fetchFn = globalThis.fetch, queryClientConfig = {}, policyOptions = {}, }: { messenger: ChompApiServiceMessenger; baseUrl: string; getAccessToken: () => Promise; - fetchFn?: typeof globalThis.fetch; queryClientConfig?: QueryClientConfig; policyOptions?: CreateServicePolicyOptions; }) { @@ -155,7 +219,7 @@ export class ChompApiService extends BaseDataService< this.#baseUrl = baseUrl; this.#getAccessToken = getAccessToken; - this.#fetch = fetchFn; + this.#mutationPolicy = createServicePolicy(policyOptions); this.messenger.registerMethodActionHandlers( this, @@ -176,29 +240,54 @@ export class ChompApiService extends BaseDataService< }; } + /** + * Makes an authenticated POST request to the CHOMP API. + * + * @param path - The URL path relative to the base URL. + * @param body - The request body to serialize as JSON. + * @param acceptedStatuses - HTTP status codes that should be returned rather + * than treated as errors (e.g. 409 for conflict). + * @returns The raw fetch Response. + */ + async #postJson( + path: string, + body: unknown, + acceptedStatuses: number[] = [], + ): Promise { + const headers = await this.#authHeaders(); + return this.#mutationPolicy.execute(async () => { + const response = await fetch(new URL(path, this.#baseUrl), { + method: 'POST', + headers, + body: JSON.stringify(body), + }); + + if (!response.ok && !acceptedStatuses.includes(response.status)) { + throw new HttpError( + response.status, + `POST ${path} failed with status '${response.status}'`, + ); + } + + return response; + }); + } + /** * Associates an address with a CHOMP profile. * * POST /v1/auth/address * - * TODO: Implement the request using this.fetchQuery or direct POST via - * this.#fetch. Validate the response with a superstruct. Note that a 409 - * response is valid and should be returned (not thrown). - * * @param request - The association request containing signature, timestamp, * and address. - * @returns The profile association result. + * @returns The profile association result. Returns on both 201 and 409. */ async associateAddress( request: AssociateAddressRequest, ): Promise { - // TODO: POST to `${this.#baseUrl}/v1/auth/address` with JSON body. - // TODO: Include Authorization header via this.#authHeaders(). - // TODO: Return response body on 200 or 409; throw on other non-OK statuses. - // TODO: Validate response shape with superstruct before returning. - const _headers = await this.#authHeaders(); - void request; - throw new Error('Not implemented'); + const response = await this.#postJson('/v1/auth/address', request, [409]); + const json = await response.json(); + return create(json, AssociateAddressResponseStruct); } /** @@ -206,8 +295,6 @@ export class ChompApiService extends BaseDataService< * * POST /v1/account-upgrade * - * TODO: Implement the POST request. Validate the response with a superstruct. - * * @param request - The upgrade request containing signature components and * chain details. * @returns The upgrade result. @@ -215,13 +302,9 @@ export class ChompApiService extends BaseDataService< async createUpgrade( request: CreateUpgradeRequest, ): Promise { - // TODO: POST to `${this.#baseUrl}/v1/account-upgrade` with JSON body. - // TODO: Include Authorization header via this.#authHeaders(). - // TODO: Throw on non-OK responses. - // TODO: Validate response shape with superstruct before returning. - const _headers = await this.#authHeaders(); - void request; - throw new Error('Not implemented'); + const response = await this.#postJson('/v1/account-upgrade', request); + const json = await response.json(); + return create(json, UpgradeResponseStruct); } /** @@ -229,21 +312,39 @@ export class ChompApiService extends BaseDataService< * * GET /v1/account-upgrade/:address * - * TODO: Implement the GET request. Return null on 404. Validate the response - * with a superstruct for non-404 responses. - * * @param address - The address to look up. * @returns The upgrade record, or null if not found. */ async getUpgrade(address: string): Promise { - // TODO: GET `${this.#baseUrl}/v1/account-upgrade/${address}`. - // TODO: Include Authorization header via this.#authHeaders(). - // TODO: Return null on 404, throw on other non-OK statuses. - // TODO: Validate response shape with superstruct before returning. - // TODO: Consider using this.fetchQuery with a queryKey for caching. - const _headers = await this.#authHeaders(); - void address; - throw new Error('Not implemented'); + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:getUpgrade`, address], + queryFn: async () => { + const headers = await this.#authHeaders(); + const response = await fetch( + new URL(`/v1/account-upgrade/${address}`, this.#baseUrl), + { headers }, + ); + + if (response.status === 404) { + return null; + } + + if (!response.ok) { + throw new HttpError( + response.status, + `Get upgrade request failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + if (jsonResponse === null) { + return null; + } + + return create(jsonResponse, UpgradeResponseStruct); } /** @@ -251,21 +352,18 @@ export class ChompApiService extends BaseDataService< * * POST /v1/intent/verify-delegation * - * TODO: Implement the POST request. Validate the response with a superstruct. - * * @param request - The delegation verification request. * @returns The verification result including validity and optional errors. */ async verifyDelegation( request: VerifyDelegationRequest, ): Promise { - // TODO: POST to `${this.#baseUrl}/v1/intent/verify-delegation` with JSON body. - // TODO: Include Authorization header via this.#authHeaders(). - // TODO: Throw on non-OK responses. - // TODO: Validate response shape with superstruct before returning. - const _headers = await this.#authHeaders(); - void request; - throw new Error('Not implemented'); + const response = await this.#postJson( + '/v1/intent/verify-delegation', + request, + ); + const json = await response.json(); + return create(json, VerifyDelegationResponseStruct); } /** @@ -273,22 +371,15 @@ export class ChompApiService extends BaseDataService< * * POST /v1/intent * - * TODO: Implement the POST request. Validate the response array with a - * superstruct. - * * @param intents - The array of intents to submit. * @returns The array of intent responses. */ async createIntents( intents: SendIntentRequest[], ): Promise { - // TODO: POST to `${this.#baseUrl}/v1/intent` with JSON body. - // TODO: Include Authorization header via this.#authHeaders(). - // TODO: Throw on non-OK responses. - // TODO: Validate response shape with superstruct before returning. - const _headers = await this.#authHeaders(); - void intents; - throw new Error('Not implemented'); + const response = await this.#postJson('/v1/intent', intents); + const json = await response.json(); + return create(json, SendIntentResponseArrayStruct) as SendIntentResponse[]; } /** @@ -296,43 +387,47 @@ export class ChompApiService extends BaseDataService< * * GET /v1/intent/account/:address * - * TODO: Implement the GET request. Validate the response array with a - * superstruct. - * * @param address - The address to look up intents for. * @returns The array of intents for the address. */ - async getIntentsByAddress( - address: string, - ): Promise { - // TODO: GET `${this.#baseUrl}/v1/intent/account/${address}`. - // TODO: Include Authorization header via this.#authHeaders(). - // TODO: Throw on non-OK responses. - // TODO: Validate response shape with superstruct before returning. - // TODO: Consider using this.fetchQuery with a queryKey for caching. - const _headers = await this.#authHeaders(); - void address; - throw new Error('Not implemented'); + async getIntentsByAddress(address: string): Promise { + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:getIntentsByAddress`, address], + queryFn: async () => { + const headers = await this.#authHeaders(); + const response = await fetch( + new URL(`/v1/intent/account/${address}`, this.#baseUrl), + { headers }, + ); + + if (!response.ok) { + throw new HttpError( + response.status, + `Get intents request failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + return create(jsonResponse, IntentEntryArrayStruct) as IntentEntry[]; } /** * Creates a withdrawal for card spend flows. * - * TODO: Confirm the endpoint path against CHOMP API docs. - * TODO: Implement the POST request. Validate the response with a superstruct. + * POST /v1/withdrawal * - * @param request - The withdrawal request. + * @param request - The withdrawal request containing chainId, amount + * (decimal or hex string), and account address. * @returns The withdrawal result. */ async createWithdrawal( request: CreateWithdrawalRequest, ): Promise { - // TODO: Confirm endpoint path (e.g. POST `${this.#baseUrl}/v1/withdrawal`). - // TODO: Include Authorization header via this.#authHeaders(). - // TODO: Throw on non-OK responses. - // TODO: Validate response shape with superstruct before returning. - const _headers = await this.#authHeaders(); - void request; - throw new Error('Not implemented'); + const response = await this.#postJson('/v1/withdrawal', request); + const json = await response.json(); + return create(json, CreateWithdrawalResponseStruct); } } diff --git a/packages/chomp-api-service/src/index.ts b/packages/chomp-api-service/src/index.ts index bcc77031af..f38958ca3c 100644 --- a/packages/chomp-api-service/src/index.ts +++ b/packages/chomp-api-service/src/index.ts @@ -8,7 +8,6 @@ export type { ChompApiServiceGranularCacheUpdatedEvent, } from './chomp-api-service'; export type { - ChompApiServiceMethodActions, ChompApiServiceAssociateAddressAction, ChompApiServiceCreateUpgradeAction, ChompApiServiceGetUpgradeAction, @@ -22,11 +21,16 @@ export type { AssociateAddressResponse, CreateUpgradeRequest, CreateUpgradeResponse, + CreateWithdrawalRequest, + CreateWithdrawalResponse, + DelegationCaveat, GetUpgradeResponse, - VerifyDelegationRequest, - VerifyDelegationResponse, + IntentEntry, + IntentMetadataRequest, + IntentMetadataResponse, SendIntentRequest, SendIntentResponse, - CreateWithdrawalRequest, - CreateWithdrawalResponse, + SignedDelegation, + VerifyDelegationRequest, + VerifyDelegationResponse, } from './types'; diff --git a/packages/chomp-api-service/src/types.ts b/packages/chomp-api-service/src/types.ts index b3a253cce5..382e7bc528 100644 --- a/packages/chomp-api-service/src/types.ts +++ b/packages/chomp-api-service/src/types.ts @@ -1,3 +1,22 @@ +import type { Hex } from '@metamask/utils'; + +// === COMMON TYPES === + +export type DelegationCaveat = { + enforcer: Hex; + terms: Hex; + args: Hex; +}; + +export type SignedDelegation = { + delegate: Hex; + delegator: Hex; + authority: Hex; + caveats: DelegationCaveat[]; + salt: Hex; + signature: Hex; +}; + // === REQUEST TYPES === export type AssociateAddressRequest = { @@ -17,21 +36,30 @@ export type CreateUpgradeRequest = { }; export type VerifyDelegationRequest = { - signedDelegation: string; - chainId: string; + signedDelegation: SignedDelegation; + chainId: Hex; }; -/** - * A single intent to be submitted to the Chomp API. - * TODO: Define the full shape of an intent once the API schema is confirmed. - */ -export type SendIntentRequest = Record; +export type IntentMetadataRequest = { + allowance: Hex; + tokenSymbol: string; + tokenAddress: Hex; + type: 'cash-deposit' | 'cash-withdrawal'; +}; -/** - * TODO: Define request shape once the withdrawal endpoint path and schema are - * confirmed against CHOMP API docs. - */ -export type CreateWithdrawalRequest = Record; +export type SendIntentRequest = { + account: Hex; + delegationHash: Hex; + chainId: Hex; + metadata: IntentMetadataRequest; +}; + +export type CreateWithdrawalRequest = { + chainId: Hex; + /** Decimal integer or 0x-prefixed hex string representing the amount. */ + amount: string; + account: Hex; +}; // === RESPONSE TYPES === @@ -49,7 +77,6 @@ export type CreateUpgradeResponse = { /** * The upgrade record returned by GET /v1/account-upgrade/:address. - * TODO: Confirm full shape against CHOMP API docs. */ export type GetUpgradeResponse = { signerAddress: string; @@ -63,14 +90,38 @@ export type VerifyDelegationResponse = { errors?: string[]; }; -/** - * A single intent response. - * TODO: Define the full shape once the API schema is confirmed. - */ -export type SendIntentResponse = Record; +export type IntentMetadataResponse = { + allowance: Hex; + tokenSymbol: string; + tokenAddress: Hex; + type: 'cash-deposit' | 'cash-withdrawal'; +}; + +export type SendIntentResponse = { + delegationHash: string; + metadata: IntentMetadataResponse; + createdAt: string; +}; /** - * TODO: Define response shape once the withdrawal endpoint path and schema are - * confirmed against CHOMP API docs. + * The shape returned by GET /v1/intent/account/:address for each intent. + * + * Note: the metadata `type` uses 'deposit' | 'withdraw' here, whereas the + * create-intent endpoint uses 'cash-deposit' | 'cash-withdrawal'. */ -export type CreateWithdrawalResponse = Record; +export type IntentEntry = { + account: Hex; + delegationHash: Hex; + chainId: Hex; + status: 'active' | 'revoked'; + metadata: { + allowance: Hex; + tokenAddress: Hex; + tokenSymbol: string; + type: 'deposit' | 'withdraw'; + }; +}; + +export type CreateWithdrawalResponse = { + success: true; +}; From d8d623ea947e5b1b2108c86bab4b18a518cb9fa0 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Mon, 13 Apr 2026 13:52:12 +0100 Subject: [PATCH 04/19] chore: fix spelling of chomp --- packages/chomp-api-service/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/chomp-api-service/README.md b/packages/chomp-api-service/README.md index a12245d8d5..d1b2943f48 100644 --- a/packages/chomp-api-service/README.md +++ b/packages/chomp-api-service/README.md @@ -1,14 +1,14 @@ -# `@metamask/chom-api-service` +# `@metamask/chomp-api-service` Chomp API data service. ## Installation -`yarn add @metamask/chom-api-service` +`yarn add @metamask/chomp-api-service` or -`npm install @metamask/chom-api-service` +`npm install @metamask/chomp-api-service` ## Contributing From 46b81b57f0ed0c4facd72ba42331cbe8a844a9cd Mon Sep 17 00:00:00 2001 From: John Whiles Date: Mon, 13 Apr 2026 13:53:36 +0100 Subject: [PATCH 05/19] feat: use the fetchQuery for non cached calls --- .../src/chomp-api-service.ts | 188 ++++++++++++------ yarn.lock | 17 +- 2 files changed, 145 insertions(+), 60 deletions(-) diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index ffe34f79e0..82c5de4bcb 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -4,11 +4,8 @@ import type { DataServiceGranularCacheUpdatedEvent, DataServiceInvalidateQueriesAction, } from '@metamask/base-data-service'; -import type { - CreateServicePolicyOptions, - ServicePolicy, -} from '@metamask/controller-utils'; -import { createServicePolicy, HttpError } from '@metamask/controller-utils'; +import type { CreateServicePolicyOptions } from '@metamask/controller-utils'; +import { HttpError } from '@metamask/controller-utils'; import type { Messenger } from '@metamask/messenger'; import { array, @@ -183,8 +180,6 @@ export class ChompApiService extends BaseDataService< readonly #getAccessToken: () => Promise; - readonly #mutationPolicy: ServicePolicy; - /** * Constructs a new ChompApiService. * @@ -219,7 +214,6 @@ export class ChompApiService extends BaseDataService< this.#baseUrl = baseUrl; this.#getAccessToken = getAccessToken; - this.#mutationPolicy = createServicePolicy(policyOptions); this.messenger.registerMethodActionHandlers( this, @@ -240,39 +234,6 @@ export class ChompApiService extends BaseDataService< }; } - /** - * Makes an authenticated POST request to the CHOMP API. - * - * @param path - The URL path relative to the base URL. - * @param body - The request body to serialize as JSON. - * @param acceptedStatuses - HTTP status codes that should be returned rather - * than treated as errors (e.g. 409 for conflict). - * @returns The raw fetch Response. - */ - async #postJson( - path: string, - body: unknown, - acceptedStatuses: number[] = [], - ): Promise { - const headers = await this.#authHeaders(); - return this.#mutationPolicy.execute(async () => { - const response = await fetch(new URL(path, this.#baseUrl), { - method: 'POST', - headers, - body: JSON.stringify(body), - }); - - if (!response.ok && !acceptedStatuses.includes(response.status)) { - throw new HttpError( - response.status, - `POST ${path} failed with status '${response.status}'`, - ); - } - - return response; - }); - } - /** * Associates an address with a CHOMP profile. * @@ -285,9 +246,32 @@ export class ChompApiService extends BaseDataService< async associateAddress( request: AssociateAddressRequest, ): Promise { - const response = await this.#postJson('/v1/auth/address', request, [409]); - const json = await response.json(); - return create(json, AssociateAddressResponseStruct); + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:associateAddress`, request], + staleTime: 0, + queryFn: async () => { + const headers = await this.#authHeaders(); + const response = await fetch( + new URL('/v1/auth/address', this.#baseUrl), + { + method: 'POST', + headers, + body: JSON.stringify(request), + }, + ); + + if (!response.ok && response.status !== 409) { + throw new HttpError( + response.status, + `POST /v1/auth/address failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + return create(jsonResponse, AssociateAddressResponseStruct); } /** @@ -302,9 +286,32 @@ export class ChompApiService extends BaseDataService< async createUpgrade( request: CreateUpgradeRequest, ): Promise { - const response = await this.#postJson('/v1/account-upgrade', request); - const json = await response.json(); - return create(json, UpgradeResponseStruct); + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:createUpgrade`, request], + staleTime: 0, + queryFn: async () => { + const headers = await this.#authHeaders(); + const response = await fetch( + new URL('/v1/account-upgrade', this.#baseUrl), + { + method: 'POST', + headers, + body: JSON.stringify(request), + }, + ); + + if (!response.ok) { + throw new HttpError( + response.status, + `POST /v1/account-upgrade failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + return create(jsonResponse, UpgradeResponseStruct); } /** @@ -358,12 +365,32 @@ export class ChompApiService extends BaseDataService< async verifyDelegation( request: VerifyDelegationRequest, ): Promise { - const response = await this.#postJson( - '/v1/intent/verify-delegation', - request, - ); - const json = await response.json(); - return create(json, VerifyDelegationResponseStruct); + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:verifyDelegation`, request], + staleTime: 0, + queryFn: async () => { + const headers = await this.#authHeaders(); + const response = await fetch( + new URL('/v1/intent/verify-delegation', this.#baseUrl), + { + method: 'POST', + headers, + body: JSON.stringify(request), + }, + ); + + if (!response.ok) { + throw new HttpError( + response.status, + `POST /v1/intent/verify-delegation failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + return create(jsonResponse, VerifyDelegationResponseStruct); } /** @@ -377,9 +404,32 @@ export class ChompApiService extends BaseDataService< async createIntents( intents: SendIntentRequest[], ): Promise { - const response = await this.#postJson('/v1/intent', intents); - const json = await response.json(); - return create(json, SendIntentResponseArrayStruct) as SendIntentResponse[]; + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:createIntents`, intents], + staleTime: 0, + queryFn: async () => { + const headers = await this.#authHeaders(); + const response = await fetch(new URL('/v1/intent', this.#baseUrl), { + method: 'POST', + headers, + body: JSON.stringify(intents), + }); + + if (!response.ok) { + throw new HttpError( + response.status, + `POST /v1/intent failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + return create( + jsonResponse, + SendIntentResponseArrayStruct, + ) as SendIntentResponse[]; } /** @@ -426,8 +476,28 @@ export class ChompApiService extends BaseDataService< async createWithdrawal( request: CreateWithdrawalRequest, ): Promise { - const response = await this.#postJson('/v1/withdrawal', request); - const json = await response.json(); - return create(json, CreateWithdrawalResponseStruct); + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:createWithdrawal`, request], + staleTime: 0, + queryFn: async () => { + const headers = await this.#authHeaders(); + const response = await fetch(new URL('/v1/withdrawal', this.#baseUrl), { + method: 'POST', + headers, + body: JSON.stringify(request), + }); + + if (!response.ok) { + throw new HttpError( + response.status, + `POST /v1/withdrawal failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + return create(jsonResponse, CreateWithdrawalResponseStruct); } } diff --git a/yarn.lock b/yarn.lock index 4d61d220e6..cd56195a15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2920,6 +2920,21 @@ __metadata: languageName: node linkType: hard +"@metamask/auto-changelog@npm:^3.4.4": + version: 3.4.4 + resolution: "@metamask/auto-changelog@npm:3.4.4" + dependencies: + diff: "npm:^5.0.0" + execa: "npm:^5.1.1" + prettier: "npm:^2.8.8" + semver: "npm:^7.3.5" + yargs: "npm:^17.0.1" + bin: + auto-changelog: dist/cli.js + checksum: 10/70e98529a153ebeab10410dbc3f567014999f77ed82f2b52f1b36501b28a4e3614c809a90c89600a739d7710595bfecc30e2260410e6afac7539f8db65a48f2c + languageName: node + linkType: hard + "@metamask/auto-changelog@npm:^6.1.0": version: 6.1.0 resolution: "@metamask/auto-changelog@npm:6.1.0" @@ -13118,7 +13133,7 @@ __metadata: languageName: node linkType: hard -"prettier-2@npm:prettier@^2.8.8": +"prettier-2@npm:prettier@^2.8.8, prettier@npm:^2.8.8": version: 2.8.8 resolution: "prettier@npm:2.8.8" bin: From 5d6ac2edc51f90edb065f7b79ce477b25c4b746a Mon Sep 17 00:00:00 2001 From: John Whiles Date: Mon, 13 Apr 2026 13:53:52 +0100 Subject: [PATCH 06/19] fix: small error in changelog --- packages/chomp-api-service/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/chomp-api-service/CHANGELOG.md b/packages/chomp-api-service/CHANGELOG.md index c050ac9419..77f2d8816a 100644 --- a/packages/chomp-api-service/CHANGELOG.md +++ b/packages/chomp-api-service/CHANGELOG.md @@ -9,6 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `ChompApiService` ([#8361](https://github.com/MetaMask/core/pull/8413)) +- Add `ChompApiService` ([#8413](https://github.com/MetaMask/core/pull/8413)) [Unreleased]: https://github.com/MetaMask/core/ From 82a5c12431af3aa13fe6b3604f3a361040c86706 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Mon, 13 Apr 2026 14:05:41 +0100 Subject: [PATCH 07/19] fix: update tsconfig files --- tsconfig.build.json | 3 +++ tsconfig.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tsconfig.build.json b/tsconfig.build.json index d741e37726..0abc4163fb 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -58,6 +58,9 @@ { "path": "./packages/chain-agnostic-permission/tsconfig.build.json" }, + { + "path": "./packages/chomp-api-service/tsconfig.build.json" + }, { "path": "./packages/claims-controller/tsconfig.build.json" }, diff --git a/tsconfig.json b/tsconfig.json index 74762bc7b6..9311cfcfeb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -59,6 +59,9 @@ { "path": "./packages/chain-agnostic-permission" }, + { + "path": "./packages/chomp-api-service" + }, { "path": "./packages/claims-controller" }, From a46abc0546a79b50cb7490a6821261f55528f616 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Mon, 13 Apr 2026 14:09:10 +0100 Subject: [PATCH 08/19] feat: validate hex strings and share upgrade reponse type --- .../src/chomp-api-service.test.ts | 2 +- .../src/chomp-api-service.ts | 29 ++++++++++--------- packages/chomp-api-service/src/index.ts | 3 +- packages/chomp-api-service/src/types.ts | 11 +------ 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index 0c79cc6307..03a101d55b 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -406,7 +406,7 @@ describe('ChompApiService', () => { const { service } = createService(); await expect(service.getIntentsByAddress('0xabc')).rejects.toThrow( - 'At path: 0.account -- Expected a string', + 'At path: 0.account -- Expected a value of type `Hex string`', ); }); }); diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index 82c5de4bcb..813833cb7a 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -11,12 +11,14 @@ import { array, boolean, create, + define, enums, literal, optional, string, type, } from '@metamask/superstruct'; +import { isStrictHexString } from '@metamask/utils'; import type { QueryClientConfig } from '@tanstack/query-core'; import type { ChompApiServiceMethodActions } from './chomp-api-service-method-action-types'; @@ -24,10 +26,9 @@ import type { AssociateAddressRequest, AssociateAddressResponse, CreateUpgradeRequest, - CreateUpgradeResponse, + UpgradeResponse, CreateWithdrawalRequest, CreateWithdrawalResponse, - GetUpgradeResponse, IntentEntry, SendIntentRequest, SendIntentResponse, @@ -114,6 +115,10 @@ export type ChompApiServiceMessenger = Messenger< // === RESPONSE VALIDATION === +const HexStringStruct = define('Hex string', (value) => + isStrictHexString(value), +); + const AssociateAddressResponseStruct = type({ profileId: string(), address: string(), @@ -136,9 +141,9 @@ const SendIntentResponseArrayStruct = array( type({ delegationHash: string(), metadata: type({ - allowance: string(), + allowance: HexStringStruct, tokenSymbol: string(), - tokenAddress: string(), + tokenAddress: HexStringStruct, type: enums(['cash-deposit', 'cash-withdrawal']), }), createdAt: string(), @@ -147,13 +152,13 @@ const SendIntentResponseArrayStruct = array( const IntentEntryArrayStruct = array( type({ - account: string(), - delegationHash: string(), - chainId: string(), + account: HexStringStruct, + delegationHash: HexStringStruct, + chainId: HexStringStruct, status: enums(['active', 'revoked']), metadata: type({ - allowance: string(), - tokenAddress: string(), + allowance: HexStringStruct, + tokenAddress: HexStringStruct, tokenSymbol: string(), type: enums(['deposit', 'withdraw']), }), @@ -283,9 +288,7 @@ export class ChompApiService extends BaseDataService< * chain details. * @returns The upgrade result. */ - async createUpgrade( - request: CreateUpgradeRequest, - ): Promise { + async createUpgrade(request: CreateUpgradeRequest): Promise { const jsonResponse = await this.fetchQuery({ queryKey: [`${this.name}:createUpgrade`, request], staleTime: 0, @@ -322,7 +325,7 @@ export class ChompApiService extends BaseDataService< * @param address - The address to look up. * @returns The upgrade record, or null if not found. */ - async getUpgrade(address: string): Promise { + async getUpgrade(address: string): Promise { const jsonResponse = await this.fetchQuery({ queryKey: [`${this.name}:getUpgrade`, address], queryFn: async () => { diff --git a/packages/chomp-api-service/src/index.ts b/packages/chomp-api-service/src/index.ts index f38958ca3c..0052e7f8dd 100644 --- a/packages/chomp-api-service/src/index.ts +++ b/packages/chomp-api-service/src/index.ts @@ -20,11 +20,10 @@ export type { AssociateAddressRequest, AssociateAddressResponse, CreateUpgradeRequest, - CreateUpgradeResponse, CreateWithdrawalRequest, CreateWithdrawalResponse, DelegationCaveat, - GetUpgradeResponse, + UpgradeResponse, IntentEntry, IntentMetadataRequest, IntentMetadataResponse, diff --git a/packages/chomp-api-service/src/types.ts b/packages/chomp-api-service/src/types.ts index 382e7bc528..e68092e22d 100644 --- a/packages/chomp-api-service/src/types.ts +++ b/packages/chomp-api-service/src/types.ts @@ -69,16 +69,7 @@ export type AssociateAddressResponse = { status: string; }; -export type CreateUpgradeResponse = { - signerAddress: string; - status: string; - createdAt: string; -}; - -/** - * The upgrade record returned by GET /v1/account-upgrade/:address. - */ -export type GetUpgradeResponse = { +export type UpgradeResponse = { signerAddress: string; status: string; createdAt: string; From 7d83ad30b84fd4d0ab3504f774addfffc0f79dec Mon Sep 17 00:00:00 2001 From: John Whiles Date: Tue, 14 Apr 2026 10:53:28 +0100 Subject: [PATCH 09/19] feat: use the messenger to get token --- packages/chomp-api-service/package.json | 1 + .../src/chomp-api-service.test.ts | 10 +- .../src/chomp-api-service.ts | 16 +- yarn.lock | 776 ++++++++++++++++-- 4 files changed, 745 insertions(+), 58 deletions(-) diff --git a/packages/chomp-api-service/package.json b/packages/chomp-api-service/package.json index 203f007a60..89309ab33e 100644 --- a/packages/chomp-api-service/package.json +++ b/packages/chomp-api-service/package.json @@ -50,6 +50,7 @@ "@metamask/base-data-service": "^0.1.1", "@metamask/controller-utils": "^11.20.0", "@metamask/messenger": "^1.1.1", + "@metamask/profile-sync-controller": "^28.0.2", "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^11.9.0", "@tanstack/query-core": "^4.43.0" diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index 03a101d55b..60e0fe8f8d 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -513,10 +513,18 @@ function createService({ messenger: ChompApiServiceMessenger; } { const rootMessenger = createRootMessenger(); + rootMessenger.registerActionHandler( + 'AuthenticationController:getBearerToken', + async () => MOCK_TOKEN, + ); const messenger = createServiceMessenger(rootMessenger); + rootMessenger.delegate({ + messenger, + actions: ['AuthenticationController:getBearerToken'], + events: [], + }); const service = new ChompApiService({ baseUrl: BASE_URL, - getAccessToken: async (): Promise => MOCK_TOKEN, messenger, ...options, }); diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index 813833cb7a..7cea914af7 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -7,6 +7,7 @@ import type { import type { CreateServicePolicyOptions } from '@metamask/controller-utils'; import { HttpError } from '@metamask/controller-utils'; import type { Messenger } from '@metamask/messenger'; +import type { AuthenticationControllerGetBearerTokenAction } from '@metamask/profile-sync-controller/auth'; import { array, boolean, @@ -76,7 +77,7 @@ export type ChompApiServiceActions = /** * Actions from other messengers that {@link ChompApiService} calls. */ -type AllowedActions = never; +type AllowedActions = AuthenticationControllerGetBearerTokenAction; /** * Published when {@link ChompApiService}'s cache is updated. @@ -175,7 +176,7 @@ const CreateWithdrawalResponseStruct = type({ * This service is responsible for communicating with the CHOMP API. * * All requests are authenticated via JWT Bearer tokens obtained from the - * `getAccessToken` callback provided at construction time. + * {@link AuthenticationControllerGetBearerTokenAction} messenger action. */ export class ChompApiService extends BaseDataService< typeof serviceName, @@ -183,16 +184,12 @@ export class ChompApiService extends BaseDataService< > { readonly #baseUrl: string; - readonly #getAccessToken: () => Promise; - /** * Constructs a new ChompApiService. * * @param args - The constructor arguments. * @param args.messenger - The messenger suited for this service. * @param args.baseUrl - The base URL of the CHOMP API. - * @param args.getAccessToken - An async callback that returns a valid JWT - * access token for authenticating requests. * @param args.queryClientConfig - Configuration for the underlying TanStack * Query client. * @param args.policyOptions - Options to pass to `createServicePolicy`. @@ -200,13 +197,11 @@ export class ChompApiService extends BaseDataService< constructor({ messenger, baseUrl, - getAccessToken, queryClientConfig = {}, policyOptions = {}, }: { messenger: ChompApiServiceMessenger; baseUrl: string; - getAccessToken: () => Promise; queryClientConfig?: QueryClientConfig; policyOptions?: CreateServicePolicyOptions; }) { @@ -218,7 +213,6 @@ export class ChompApiService extends BaseDataService< }); this.#baseUrl = baseUrl; - this.#getAccessToken = getAccessToken; this.messenger.registerMethodActionHandlers( this, @@ -232,7 +226,9 @@ export class ChompApiService extends BaseDataService< * @returns Headers including Authorization and Content-Type. */ async #authHeaders(): Promise> { - const token = await this.#getAccessToken(); + const token = await this.messenger.call( + 'AuthenticationController:getBearerToken', + ); return { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', diff --git a/yarn.lock b/yarn.lock index cd56195a15..41f666d343 100644 --- a/yarn.lock +++ b/yarn.lock @@ -154,7 +154,18 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0": + version: 7.29.2 + resolution: "@babel/parser@npm:7.29.2" + dependencies: + "@babel/types": "npm:^7.29.0" + bin: + parser: ./bin/babel-parser.js + checksum: 10/45d050bf75aa5194b3255f156173e8553d615ff5a2434674cc4a10cdc7c261931befb8618c996a1c449b87f0ef32a3407879af2ac967d95dc7b4fdbae7037efa + languageName: node + linkType: hard + +"@babel/parser@npm:^7.24.7": version: 7.29.0 resolution: "@babel/parser@npm:7.29.0" dependencies: @@ -709,13 +720,20 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.39.1, @eslint/js@npm:^9.11.0": +"@eslint/js@npm:9.39.1": version: 9.39.1 resolution: "@eslint/js@npm:9.39.1" checksum: 10/b10b9b953212c0f3ffca475159bbe519e9e98847200c7432d1637d444fddcd7b712d2b7710a7dc20510f9cfbe8db330039b2aad09cb55d9545b116d940dbeed2 languageName: node linkType: hard +"@eslint/js@npm:^9.11.0": + version: 9.39.4 + resolution: "@eslint/js@npm:9.39.4" + checksum: 10/0a7ab4c4108cf2cadf66849ebd20f5957cc53052b88d8807d0b54e489dbf6ffcaf741e144e7f9b187c395499ce2e6ddc565dbfa4f60c6df455cf2b30bcbdc5a3 + languageName: node + linkType: hard + "@eslint/object-schema@npm:^2.1.7": version: 2.1.7 resolution: "@eslint/object-schema@npm:2.1.7" @@ -1730,6 +1748,13 @@ __metadata: languageName: node linkType: hard +"@gar/promise-retry@npm:^1.0.0": + version: 1.0.3 + resolution: "@gar/promise-retry@npm:1.0.3" + checksum: 10/0d13ea3bb1025755e055648f6e290d2a7e0c87affaf552218f09f66b3fcd9ea9d5c9cc5fe2aa6e285e1530437768e40f9448fe9a86f4f3417b216dcf488d3d1a + languageName: node + linkType: hard + "@grpc/grpc-js@npm:~1.9.0": version: 1.9.15 resolution: "@grpc/grpc-js@npm:1.9.15" @@ -3142,6 +3167,7 @@ __metadata: "@metamask/base-data-service": "npm:^0.1.1" "@metamask/controller-utils": "npm:^11.20.0" "@metamask/messenger": "npm:^1.1.1" + "@metamask/profile-sync-controller": "npm:^28.0.2" "@metamask/superstruct": "npm:^3.1.0" "@metamask/utils": "npm:^11.9.0" "@tanstack/query-core": "npm:^4.43.0" @@ -5906,6 +5932,19 @@ __metadata: languageName: node linkType: hard +"@npmcli/agent@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/agent@npm:4.0.0" + dependencies: + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^11.2.1" + socks-proxy-agent: "npm:^8.0.3" + checksum: 10/1a81573becc60515031accc696e6405e9b894e65c12b98ef4aeee03b5617c41948633159dbf6caf5dde5b47367eeb749bdc7b7dfb21960930a9060a935c6f636 + languageName: node + linkType: hard + "@npmcli/fs@npm:^3.1.0": version: 3.1.1 resolution: "@npmcli/fs@npm:3.1.1" @@ -5915,6 +5954,15 @@ __metadata: languageName: node linkType: hard +"@npmcli/fs@npm:^5.0.0": + version: 5.0.0 + resolution: "@npmcli/fs@npm:5.0.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10/4935c7719d17830d0f9fa46c50be17b2a3c945cec61760f6d0909bce47677c42e1810ca673305890f9e84f008ec4d8e841182f371e42100a8159d15f22249208 + languageName: node + linkType: hard + "@npmcli/git@npm:^5.0.0": version: 5.0.8 resolution: "@npmcli/git@npm:5.0.8" @@ -5963,6 +6011,13 @@ __metadata: languageName: node linkType: hard +"@npmcli/redact@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/redact@npm:4.0.0" + checksum: 10/5d52df2b5267f4369c97a2b2f7c427e3d7aa4b6a83e7a1b522e196f6e9d50024c620bd0cb2052067c74d1aaa0c330d9bc04e1d335bfb46180e705bb33423e74c + languageName: node + linkType: hard + "@npmcli/run-script@npm:8.1.0": version: 8.1.0 resolution: "@npmcli/run-script@npm:8.1.0" @@ -6575,13 +6630,20 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-core@npm:4.43.0, @tanstack/query-core@npm:^4.43.0": +"@tanstack/query-core@npm:4.43.0": version: 4.43.0 resolution: "@tanstack/query-core@npm:4.43.0" checksum: 10/c2a5a151c7adaea8311e01a643255f31946ae3164a71567ba80048242821ae14043f13f5516b695baebe5ea7e4b2cf717fd60908a929d18a5c5125fee925ff67 languageName: node linkType: hard +"@tanstack/query-core@npm:^4.43.0": + version: 4.44.0 + resolution: "@tanstack/query-core@npm:4.44.0" + checksum: 10/f7f5c69cb2d44b58e1a9bfaa304a82724bb49f0ff63fd3abdfe377f15825ad910e1d31dd529d94e0650ff17229930eef2f54e281dbe99fa6cbd6a85e7c27bb9d + languageName: node + linkType: hard + "@tanstack/query-core@npm:^5.62.16": version: 5.90.20 resolution: "@tanstack/query-core@npm:5.90.20" @@ -6946,7 +7008,16 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:22.7.5, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": +"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": + version: 25.6.0 + resolution: "@types/node@npm:25.6.0" + dependencies: + undici-types: "npm:~7.19.0" + checksum: 10/99b18690a4be55904cbf8f6a6ac8eed5ec5b8d791fdd8ee2ae598b46c0fa9b83cda7b70dd7f00dbfb18189dcfc67648fdc7fdd3fcced2619a5a6453d9aec107d + languageName: node + linkType: hard + +"@types/node@npm:22.7.5": version: 22.7.5 resolution: "@types/node@npm:22.7.5" dependencies: @@ -7096,7 +7167,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.54.0, @typescript-eslint/eslint-plugin@npm:^8.48.0": +"@typescript-eslint/eslint-plugin@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/eslint-plugin@npm:8.54.0" dependencies: @@ -7116,7 +7187,27 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.54.0, @typescript-eslint/parser@npm:^8.48.0": +"@typescript-eslint/eslint-plugin@npm:^8.48.0": + version: 8.58.1 + resolution: "@typescript-eslint/eslint-plugin@npm:8.58.1" + dependencies: + "@eslint-community/regexpp": "npm:^4.12.2" + "@typescript-eslint/scope-manager": "npm:8.58.1" + "@typescript-eslint/type-utils": "npm:8.58.1" + "@typescript-eslint/utils": "npm:8.58.1" + "@typescript-eslint/visitor-keys": "npm:8.58.1" + ignore: "npm:^7.0.5" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + "@typescript-eslint/parser": ^8.58.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/0fcbe6faadb77313aa91c895c977a24fc72a79eed62f46f7b2d5804db52a9af99351b33b9c4d73fdabb0f69772d5d4a9acdef249a0d1526a44d3817fb51419b5 + languageName: node + linkType: hard + +"@typescript-eslint/parser@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/parser@npm:8.54.0" dependencies: @@ -7132,6 +7223,22 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/parser@npm:^8.48.0": + version: 8.58.1 + resolution: "@typescript-eslint/parser@npm:8.58.1" + dependencies: + "@typescript-eslint/scope-manager": "npm:8.58.1" + "@typescript-eslint/types": "npm:8.58.1" + "@typescript-eslint/typescript-estree": "npm:8.58.1" + "@typescript-eslint/visitor-keys": "npm:8.58.1" + debug: "npm:^4.4.3" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/062584d26609e82169459ebf0c59f4925ba6596f4ea1637a320c34a25c34117585c458b9c6c268f5eeaee1988f4c7257d34d4bd05a214a88de12110e71b48493 + languageName: node + linkType: hard + "@typescript-eslint/project-service@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/project-service@npm:8.54.0" @@ -7145,6 +7252,19 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/project-service@npm:8.58.1": + version: 8.58.1 + resolution: "@typescript-eslint/project-service@npm:8.58.1" + dependencies: + "@typescript-eslint/tsconfig-utils": "npm:^8.58.1" + "@typescript-eslint/types": "npm:^8.58.1" + debug: "npm:^4.4.3" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10/2f3136268fc262e77e8c8c14291e60c54e0228b63ccb022826b6def6d80b83ce9c3a92fef11c888889fb204343c845556868c49495c3aa0a115e9a861dd5fe99 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:8.54.0, @typescript-eslint/scope-manager@npm:^8.1.0": version: 8.54.0 resolution: "@typescript-eslint/scope-manager@npm:8.54.0" @@ -7155,6 +7275,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:8.58.1": + version: 8.58.1 + resolution: "@typescript-eslint/scope-manager@npm:8.58.1" + dependencies: + "@typescript-eslint/types": "npm:8.58.1" + "@typescript-eslint/visitor-keys": "npm:8.58.1" + checksum: 10/dc070fd73847807e32cb7dfc37512abd0b1a485b0037d8cfb6c593555a5b673d3ee9d19c61504ea71d067ad610c66f64d70d56f3a5db51895c0a25e45621cd08 + languageName: node + linkType: hard + "@typescript-eslint/tsconfig-utils@npm:8.54.0, @typescript-eslint/tsconfig-utils@npm:^8.54.0": version: 8.54.0 resolution: "@typescript-eslint/tsconfig-utils@npm:8.54.0" @@ -7164,6 +7294,15 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/tsconfig-utils@npm:8.58.1, @typescript-eslint/tsconfig-utils@npm:^8.58.1": + version: 8.58.1 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.58.1" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10/4a5cf9a5eb834d05f2d37f7d80319575cf4a75aa52807b96edc0db24349ba417b41cb6f5257ffb07b8b9b4c59c7438637e8c75ed7c2b513bcb07e259b49e058e + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/type-utils@npm:8.54.0" @@ -7180,6 +7319,22 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/type-utils@npm:8.58.1": + version: 8.58.1 + resolution: "@typescript-eslint/type-utils@npm:8.58.1" + dependencies: + "@typescript-eslint/types": "npm:8.58.1" + "@typescript-eslint/typescript-estree": "npm:8.58.1" + "@typescript-eslint/utils": "npm:8.58.1" + debug: "npm:^4.4.3" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/39d62d6711590e817cf9a36257c19ea18e201ceca42b900350e121ea8986c167fbdd9da385ced29c61e38a1b5c76b6c320d59e21d4dd7f32767520e31aef4654 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:8.54.0, @typescript-eslint/types@npm:^8.54.0": version: 8.54.0 resolution: "@typescript-eslint/types@npm:8.54.0" @@ -7187,6 +7342,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.58.1, @typescript-eslint/types@npm:^8.58.1": + version: 8.58.1 + resolution: "@typescript-eslint/types@npm:8.58.1" + checksum: 10/447e1351af8a47297096f063b327c69b1c986af89e39cb39e142bb35d7bec2ce8f34f31edcf62d1beb2e09a38e2029b12b50b335dae4e7c9ff49bd82f9127523 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/typescript-estree@npm:8.54.0" @@ -7206,7 +7368,26 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.54.0, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.1.0": +"@typescript-eslint/typescript-estree@npm:8.58.1": + version: 8.58.1 + resolution: "@typescript-eslint/typescript-estree@npm:8.58.1" + dependencies: + "@typescript-eslint/project-service": "npm:8.58.1" + "@typescript-eslint/tsconfig-utils": "npm:8.58.1" + "@typescript-eslint/types": "npm:8.58.1" + "@typescript-eslint/visitor-keys": "npm:8.58.1" + debug: "npm:^4.4.3" + minimatch: "npm:^10.2.2" + semver: "npm:^7.7.3" + tinyglobby: "npm:^0.2.15" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10/107510b484148a8a9a5874f5451b9a6649609607ee5e67de36cded786157987a5262b145398b1bd1935afab66134532369a4d6abb53c6f5b7744e3ace0b13f07 + languageName: node + linkType: hard + +"@typescript-eslint/utils@npm:8.54.0, @typescript-eslint/utils@npm:^8.1.0": version: 8.54.0 resolution: "@typescript-eslint/utils@npm:8.54.0" dependencies: @@ -7221,6 +7402,21 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:8.58.1, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0": + version: 8.58.1 + resolution: "@typescript-eslint/utils@npm:8.58.1" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.9.1" + "@typescript-eslint/scope-manager": "npm:8.58.1" + "@typescript-eslint/types": "npm:8.58.1" + "@typescript-eslint/typescript-estree": "npm:8.58.1" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/c51a5e116d1a09d0eb701c5884d5b9b8c22f79c427cb4c46357e4bcb7dfdfd9beba92e5d518572f42111b7335541a4ccefe3c05595fc3d666c1b62ddd1522e54 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/visitor-keys@npm:8.54.0" @@ -7231,6 +7427,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:8.58.1": + version: 8.58.1 + resolution: "@typescript-eslint/visitor-keys@npm:8.58.1" + dependencies: + "@typescript-eslint/types": "npm:8.58.1" + eslint-visitor-keys: "npm:^5.0.0" + checksum: 10/e9f34741da6fc0cb8e9eb67828ea4427ac2004a33ce8d1e1e9ba038471f9ed68405eca871651bb2efa793a467bc5233a4310c5571ad1497cb2a84a600e1733a8 + languageName: node + linkType: hard + "@vercel/stega@npm:^0.1.2": version: 0.1.2 resolution: "@vercel/stega@npm:0.1.2" @@ -7325,6 +7531,13 @@ __metadata: languageName: node linkType: hard +"abbrev@npm:^4.0.0": + version: 4.0.0 + resolution: "abbrev@npm:4.0.0" + checksum: 10/e2f0c6a6708ad738b3e8f50233f4800de31ad41a6cdc50e0cbe51b76fed69fd0213516d92c15ce1a9985fca71a14606a9be22bf00f8475a58987b9bfb671c582 + languageName: node + linkType: hard + "abitype@npm:1.2.3, abitype@npm:^1.2.3": version: 1.2.3 resolution: "abitype@npm:1.2.3" @@ -7426,7 +7639,7 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.1": version: 7.1.1 resolution: "agent-base@npm:7.1.1" dependencies: @@ -7435,6 +7648,13 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:^7.1.0": + version: 7.1.4 + resolution: "agent-base@npm:7.1.4" + checksum: 10/79bef167247789f955aaba113bae74bf64aa1e1acca4b1d6bb444bdf91d82c3e07e9451ef6a6e2e35e8f71a6f97ce33e3d855a5328eb9fad1bc3cc4cfd031ed8 + languageName: node + linkType: hard + "aggregate-error@npm:^3.0.0": version: 3.1.0 resolution: "aggregate-error@npm:3.1.0" @@ -7599,6 +7819,20 @@ __metadata: languageName: node linkType: hard +"async-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-function@npm:1.0.0" + checksum: 10/1a09379937d846f0ce7614e75071c12826945d4e417db634156bf0e4673c495989302f52186dfa9767a1d9181794554717badd193ca2bbab046ef1da741d8efd + languageName: node + linkType: hard + +"async-generator-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-generator-function@npm:1.0.0" + checksum: 10/3d49e7acbeee9e84537f4cb0e0f91893df8eba976759875ae8ee9e3d3c82f6ecdebdb347c2fad9926b92596d93cdfc78ecc988bcdf407e40433e8e8e6fe5d78e + languageName: node + linkType: hard + "async-mutex@npm:^0.3.1": version: 0.3.2 resolution: "async-mutex@npm:0.3.2" @@ -7624,6 +7858,15 @@ __metadata: languageName: node linkType: hard +"available-typed-arrays@npm:^1.0.7": + version: 1.0.7 + resolution: "available-typed-arrays@npm:1.0.7" + dependencies: + possible-typed-array-names: "npm:^1.0.0" + checksum: 10/6c9da3a66caddd83c875010a1ca8ef11eac02ba15fb592dc9418b2b5e7b77b645fa7729380a92d9835c2f05f2ca1b6251f39b993e0feb3f1517c74fa1af02cab + languageName: node + linkType: hard + "axios@npm:^1.7.4": version: 1.7.5 resolution: "axios@npm:1.7.5" @@ -7738,6 +7981,13 @@ __metadata: languageName: node linkType: hard +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10/fb07bb66a0959c2843fc055838047e2a95ccebb837c519614afb067ebfdf2fa967ca8d712c35ced07f2cd26fc6f07964230b094891315ad74f11eba3d53178a0 + languageName: node + linkType: hard + "bare-events@npm:^2.2.0": version: 2.4.2 resolution: "bare-events@npm:2.4.2" @@ -7900,6 +8150,15 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^5.0.5": + version: 5.0.5 + resolution: "brace-expansion@npm:5.0.5" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10/f259b2ddf04489da9512ad637ba6b4ef2d77abd4445d20f7f1714585f153435200a53fa6a2e4a5ee974df14ddad4cd16421f6f803e96e8b452bd48598878d0ee + languageName: node + linkType: hard + "braces@npm:^3.0.3": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -8042,6 +8301,24 @@ __metadata: languageName: node linkType: hard +"cacache@npm:^20.0.1": + version: 20.0.4 + resolution: "cacache@npm:20.0.4" + dependencies: + "@npmcli/fs": "npm:^5.0.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^13.0.0" + lru-cache: "npm:^11.1.0" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^7.0.2" + ssri: "npm:^13.0.0" + checksum: 10/02c1b4c57dc2473e6f4654220c9405b73ae5fcdb392f82a7cf535468a52b842690cdb3694861d13bbe4dc067d5f8abe9697b4f791ae5b65cd73d62abad1e3e54 + languageName: node + linkType: hard + "call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": version: 1.0.2 resolution: "call-bind-apply-helpers@npm:1.0.2" @@ -8064,6 +8341,28 @@ __metadata: languageName: node linkType: hard +"call-bind@npm:^1.0.8": + version: 1.0.9 + resolution: "call-bind@npm:1.0.9" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" + get-intrinsic: "npm:^1.3.0" + set-function-length: "npm:^1.2.2" + checksum: 10/25b1a98d6158f0adf9fface594ca82be4e3ed481d8ff7f36ad1fccb0c8377e38c6a04ff3248693723222d378677e93077c739defc8a6741c82b7e00bcee1245d + languageName: node + linkType: hard + +"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": + version: 1.0.4 + resolution: "call-bound@npm:1.0.4" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + get-intrinsic: "npm:^1.3.0" + checksum: 10/ef2b96e126ec0e58a7ff694db43f4d0d44f80e641370c21549ed911fecbdbc2df3ebc9bddad918d6bbdefeafb60bb3337902006d5176d72bcd2da74820991af7 + languageName: node + linkType: hard + "callsite@npm:^1.0.0": version: 1.0.0 resolution: "callsite@npm:1.0.0" @@ -8921,7 +9220,7 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.15.0, enhanced-resolve@npm:^5.17.1": +"enhanced-resolve@npm:^5.15.0": version: 5.18.0 resolution: "enhanced-resolve@npm:5.18.0" dependencies: @@ -8931,6 +9230,16 @@ __metadata: languageName: node linkType: hard +"enhanced-resolve@npm:^5.17.1": + version: 5.20.1 + resolution: "enhanced-resolve@npm:5.20.1" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.3.0" + checksum: 10/588afc56de97334e5742faebcf8177a504da08ea817d399f9901f35d8e9e5e6fa86b4c2ce95a99081f947764e09c9991cc0fc0ba5751bae455c329643a709187 + languageName: node + linkType: hard + "entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" @@ -9362,6 +9671,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^5.0.0": + version: 5.0.1 + resolution: "eslint-visitor-keys@npm:5.0.1" + checksum: 10/f9cc1a57b75e0ef949545cac33d01e8367e302de4c1483266ed4d8646ee5c306376660196bbb38b004e767b7043d1e661cb4336b49eff634a1bbe75c1db709ec + languageName: node + linkType: hard + "eslint@npm:^9.39.1": version: 9.39.1 resolution: "eslint@npm:9.39.1" @@ -10058,6 +10374,15 @@ __metadata: languageName: node linkType: hard +"for-each@npm:^0.3.5": + version: 0.3.5 + resolution: "for-each@npm:0.3.5" + dependencies: + is-callable: "npm:^1.2.7" + checksum: 10/330cc2439f85c94f4609de3ee1d32c5693ae15cdd7fe3d112c4fd9efd4ce7143f2c64ef6c2c9e0cfdb0058437f33ef05b5bdae5b98fcc903fb2143fbaf0fea0f + languageName: node + linkType: hard + "foreach@npm:^2.0.4": version: 2.0.6 resolution: "foreach@npm:2.0.6" @@ -10173,6 +10498,13 @@ __metadata: languageName: node linkType: hard +"generator-function@npm:^2.0.0": + version: 2.0.1 + resolution: "generator-function@npm:2.0.1" + checksum: 10/eb7e7eb896c5433f3d40982b2ccacdb3dd990dd3499f14040e002b5d54572476513be8a2e6f9609f6e41ab29f2c4469307611ddbfc37ff4e46b765c326663805 + languageName: node + linkType: hard + "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -10187,21 +10519,24 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.4": - version: 1.3.0 - resolution: "get-intrinsic@npm:1.3.0" +"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.3.0": + version: 1.3.1 + resolution: "get-intrinsic@npm:1.3.1" dependencies: + async-function: "npm:^1.0.0" + async-generator-function: "npm:^1.0.0" call-bind-apply-helpers: "npm:^1.0.2" es-define-property: "npm:^1.0.1" es-errors: "npm:^1.3.0" es-object-atoms: "npm:^1.1.1" function-bind: "npm:^1.1.2" + generator-function: "npm:^2.0.0" get-proto: "npm:^1.0.1" gopd: "npm:^1.2.0" has-symbols: "npm:^1.1.0" hasown: "npm:^2.0.2" math-intrinsics: "npm:^1.1.0" - checksum: 10/6e9dd920ff054147b6f44cb98104330e87caafae051b6d37b13384a45ba15e71af33c3baeac7cb630a0aaa23142718dcf25b45cfdd86c184c5dcb4e56d953a10 + checksum: 10/bb579dda84caa4a3a41611bdd483dade7f00f246f2a7992eb143c5861155290df3fdb48a8406efa3dfb0b434e2c8fafa4eebd469e409d0439247f85fc3fa2cc1 languageName: node linkType: hard @@ -10270,7 +10605,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -10286,6 +10621,33 @@ __metadata: languageName: node linkType: hard +"glob@npm:^10.3.7": + version: 10.5.0 + resolution: "glob@npm:10.5.0" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10/ab3bccfefcc0afaedbd1f480cd0c4a2c0e322eb3f0aa7ceaa31b3f00b825069f17cf0f1fc8b6f256795074b903f37c0ade37ddda6a176aa57f1c2bbfe7240653 + languageName: node + linkType: hard + +"glob@npm:^13.0.0": + version: 13.0.6 + resolution: "glob@npm:13.0.6" + dependencies: + minimatch: "npm:^10.2.2" + minipass: "npm:^7.1.3" + path-scurry: "npm:^2.0.2" + checksum: 10/201ad69e5f0aa74e1d8c00a481581f8b8c804b6a4fbfabeeb8541f5d756932800331daeba99b58fb9e4cd67e12ba5a7eba5b82fb476691588418060b84353214 + languageName: node + linkType: hard + "glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.7": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -10407,21 +10769,31 @@ __metadata: languageName: node linkType: hard -"has-symbols@npm:^1.1.0": +"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": version: 1.1.0 resolution: "has-symbols@npm:1.1.0" checksum: 10/959385c98696ebbca51e7534e0dc723ada325efa3475350951363cce216d27373e0259b63edb599f72eb94d6cde8577b4b2375f080b303947e560f85692834fa languageName: node linkType: hard +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: "npm:^1.0.3" + checksum: 10/c74c5f5ceee3c8a5b8bc37719840dc3749f5b0306d818974141dda2471a1a2ca6c8e46b9d6ac222c5345df7a901c9b6f350b1e6d62763fec877e26609a401bfe + languageName: node + linkType: hard + "hash-base@npm:^3.0.0": - version: 3.1.0 - resolution: "hash-base@npm:3.1.0" + version: 3.1.2 + resolution: "hash-base@npm:3.1.2" dependencies: inherits: "npm:^2.0.4" - readable-stream: "npm:^3.6.0" - safe-buffer: "npm:^5.2.0" - checksum: 10/26b7e97ac3de13cb23fc3145e7e3450b0530274a9562144fc2bf5c1e2983afd0e09ed7cc3b20974ba66039fad316db463da80eb452e7373e780cbee9a0d2f2dc + readable-stream: "npm:^2.3.8" + safe-buffer: "npm:^5.2.1" + to-buffer: "npm:^1.2.1" + checksum: 10/f2100420521ec77736ebd9279f2c0b3ab2820136a2fa408ea36f3201d3f6984cda166806e6a0287f92adf179430bedfbdd74348ac351e24a3eff9f01a8c406b0 languageName: node linkType: hard @@ -10785,6 +11157,13 @@ __metadata: languageName: node linkType: hard +"is-callable@npm:^1.2.7": + version: 1.2.7 + resolution: "is-callable@npm:1.2.7" + checksum: 10/48a9297fb92c99e9df48706241a189da362bff3003354aea4048bd5f7b2eb0d823cd16d0a383cece3d76166ba16d85d9659165ac6fcce1ac12e6c649d66dbdb9 + languageName: node + linkType: hard + "is-ci@npm:^2.0.0": version: 2.0.0 resolution: "is-ci@npm:2.0.0" @@ -10911,6 +11290,15 @@ __metadata: languageName: node linkType: hard +"is-typed-array@npm:^1.1.14": + version: 1.1.15 + resolution: "is-typed-array@npm:1.1.15" + dependencies: + which-typed-array: "npm:^1.1.16" + checksum: 10/e8cf60b9ea85667097a6ad68c209c9722cfe8c8edf04d6218366469e51944c5cc25bae45ffb845c23f811d262e4314d3b0168748eb16711aa34d12724cdf0735 + languageName: node + linkType: hard + "is-unicode-supported@npm:^0.1.0": version: 0.1.0 resolution: "is-unicode-supported@npm:0.1.0" @@ -10941,6 +11329,13 @@ __metadata: languageName: node linkType: hard +"isarray@npm:^2.0.5": + version: 2.0.5 + resolution: "isarray@npm:2.0.5" + checksum: 10/1d8bc7911e13bb9f105b1b3e0b396c787a9e63046af0b8fe0ab1414488ab06b2b099b87a2d8a9e31d21c9a6fad773c7fc8b257c4880f2d957274479d28ca3414 + languageName: node + linkType: hard + "isarray@npm:~1.0.0": version: 1.0.0 resolution: "isarray@npm:1.0.0" @@ -10962,6 +11357,13 @@ __metadata: languageName: node linkType: hard +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 10/2ead327ef596042ef9c9ec5f236b316acfaedb87f4bb61b3c3d574fb2e9c8a04b67305e04733bde52c24d9622fdebd3270aadb632adfbf9cadef88fe30f479e5 + languageName: node + linkType: hard + "isomorphic-fetch@npm:^3.0.0": version: 3.0.0 resolution: "isomorphic-fetch@npm:3.0.0" @@ -11943,6 +12345,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": + version: 11.3.3 + resolution: "lru-cache@npm:11.3.3" + checksum: 10/d45c1992232d0ab6ee5a9b93f62f43205ba5eeca51b2cfe6fa40a6aeb91b3cb0a318b273ab29ab36b66f779d4111df514c01bb7613ca4d4028953de49ecb82a9 + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -12020,6 +12429,26 @@ __metadata: languageName: node linkType: hard +"make-fetch-happen@npm:^15.0.0": + version: 15.0.5 + resolution: "make-fetch-happen@npm:15.0.5" + dependencies: + "@gar/promise-retry": "npm:^1.0.0" + "@npmcli/agent": "npm:^4.0.0" + "@npmcli/redact": "npm:^4.0.0" + cacache: "npm:^20.0.1" + http-cache-semantics: "npm:^4.1.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^5.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^1.0.0" + proc-log: "npm:^6.0.0" + ssri: "npm:^13.0.0" + checksum: 10/d2649effb06c00cb2b266057cb1c8c1e99cfc8d1378e7d9c26cc8f00be41bc63d59b77a5576ed28f8105acc57fb16220b64217f8d3a6a066a594c004aa163afa + languageName: node + linkType: hard + "makeerror@npm:1.0.12": version: 1.0.12 resolution: "makeerror@npm:1.0.12" @@ -12231,6 +12660,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.2.2": + version: 10.2.5 + resolution: "minimatch@npm:10.2.5" + dependencies: + brace-expansion: "npm:^5.0.5" + checksum: 10/19e87a931aff60ee7b9d80f39f817b8bfc54f61f8356ee3549fbf636dbccacacfec8d803eac73293955c4527cd085247dfc064bce4a5e349f8f3b85e2bf5da0f + languageName: node + linkType: hard + "minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -12300,6 +12738,21 @@ __metadata: languageName: node linkType: hard +"minipass-fetch@npm:^5.0.0": + version: 5.0.2 + resolution: "minipass-fetch@npm:5.0.2" + dependencies: + iconv-lite: "npm:^0.7.2" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^2.0.0" + minizlib: "npm:^3.0.1" + dependenciesMeta: + iconv-lite: + optional: true + checksum: 10/4f3f65ea5b20a3a287765ebf21cc73e62031f754944272df2a3039296cc75a8fc2dc50b8a3c4f39ce3ac6e5cc583e8dc664d12c6ab98e0883d263e49f344bc86 + languageName: node + linkType: hard + "minipass-flush@npm:^1.0.5": version: 1.0.5 resolution: "minipass-flush@npm:1.0.5" @@ -12327,6 +12780,15 @@ __metadata: languageName: node linkType: hard +"minipass-sized@npm:^2.0.0": + version: 2.0.0 + resolution: "minipass-sized@npm:2.0.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10/3b89adf64ca705662f77481e278eff5ec0a57aeffb5feba7cc8843722b1e7770efc880f2a17d1d4877b2d7bf227873cd46afb4da44c0fd18088b601ea50f96bb + languageName: node + linkType: hard + "minipass@npm:^3.0.0": version: 3.3.6 resolution: "minipass@npm:3.3.6" @@ -12343,10 +12805,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": - version: 7.1.2 - resolution: "minipass@npm:7.1.2" - checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 10/175e4d5e20980c3cd316ae82d2c031c42f6c746467d8b1905b51060a0ba4461441a0c25bb67c025fd9617f9a3873e152c7b543c6b5ac83a1846be8ade80dffd6 languageName: node linkType: hard @@ -12360,12 +12822,12 @@ __metadata: languageName: node linkType: hard -"minizlib@npm:^3.0.1": - version: 3.0.2 - resolution: "minizlib@npm:3.0.2" +"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" dependencies: minipass: "npm:^7.1.2" - checksum: 10/c075bed1594f68dcc8c35122333520112daefd4d070e5d0a228bd4cf5580e9eed3981b96c0ae1d62488e204e80fd27b2b9d0068ca9a5ef3993e9565faf63ca41 + checksum: 10/f47365cc2cb7f078cbe7e046eb52655e2e7e97f8c0a9a674f4da60d94fb0624edfcec9b5db32e8ba5a99a5f036f595680ae6fe02a262beaa73026e505cc52f99 languageName: node linkType: hard @@ -12385,15 +12847,6 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^3.0.1": - version: 3.0.1 - resolution: "mkdirp@npm:3.0.1" - bin: - mkdirp: dist/cjs/src/bin.js - checksum: 10/16fd79c28645759505914561e249b9a1f5fe3362279ad95487a4501e4467abeb714fd35b95307326b8fd03f3c7719065ef11a6f97b7285d7888306d1bd2232ba - languageName: node - linkType: hard - "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -12465,6 +12918,13 @@ __metadata: languageName: node linkType: hard +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10/b5734e87295324fabf868e36fb97c84b7d7f3156ec5f4ee5bf6e488079c11054f818290fc33804cef7b1ee21f55eeb14caea83e7dafae6492a409b3e573153e5 + languageName: node + linkType: hard + "neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" @@ -12526,7 +12986,7 @@ __metadata: languageName: node linkType: hard -"node-gyp@npm:^10.0.0, node-gyp@npm:latest": +"node-gyp@npm:^10.0.0": version: 10.2.0 resolution: "node-gyp@npm:10.2.0" dependencies: @@ -12546,6 +13006,26 @@ __metadata: languageName: node linkType: hard +"node-gyp@npm:latest": + version: 12.2.0 + resolution: "node-gyp@npm:12.2.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^15.0.0" + nopt: "npm:^9.0.0" + proc-log: "npm:^6.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.5.4" + tinyglobby: "npm:^0.2.12" + which: "npm:^6.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10/4ebab5b77585a637315e969c2274b5520562473fe75de850639a580c2599652fb9f33959ec782ea45a2e149d8f04b548030f472eeeb3dbdf19a7f2ccbc30b908 + languageName: node + linkType: hard + "node-int64@npm:^0.4.0": version: 0.4.0 resolution: "node-int64@npm:0.4.0" @@ -12571,6 +13051,17 @@ __metadata: languageName: node linkType: hard +"nopt@npm:^9.0.0": + version: 9.0.0 + resolution: "nopt@npm:9.0.0" + dependencies: + abbrev: "npm:^4.0.0" + bin: + nopt: bin/nopt.js + checksum: 10/56a1ccd2ad711fb5115918e2c96828703cddbe12ba2c3bd00591758f6fa30e6f47dd905c59dbfcf9b773f3a293b45996609fb6789ae29d6bfcc3cf3a6f7d9fda + languageName: node + linkType: hard + "normalize-package-data@npm:^2.5.0": version: 2.5.0 resolution: "normalize-package-data@npm:2.5.0" @@ -12695,6 +13186,13 @@ __metadata: languageName: node linkType: hard +"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": + version: 1.13.4 + resolution: "object-inspect@npm:1.13.4" + checksum: 10/aa13b1190ad3e366f6c83ad8a16ed37a19ed57d267385aa4bfdccda833d7b90465c057ff6c55d035a6b2e52c1a2295582b294217a0a3a1ae7abdd6877ef781fb + languageName: node + linkType: hard + "on-finished@npm:2.4.1": version: 2.4.1 resolution: "on-finished@npm:2.4.1" @@ -12892,6 +13390,13 @@ __metadata: languageName: node linkType: hard +"p-map@npm:^7.0.2": + version: 7.0.4 + resolution: "p-map@npm:7.0.4" + checksum: 10/ef48c3b2e488f31c693c9fcc0df0ef76518cf6426a495cf9486ebbb0fd7f31aef7f90e96f72e0070c0ff6e3177c9318f644b512e2c29e3feee8d7153fcb6782e + languageName: node + linkType: hard + "p-throttle@npm:^4.1.1": version: 4.1.1 resolution: "p-throttle@npm:4.1.1" @@ -13019,6 +13524,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^2.0.2": + version: 2.0.2 + resolution: "path-scurry@npm:2.0.2" + dependencies: + lru-cache: "npm:^11.0.0" + minipass: "npm:^7.1.2" + checksum: 10/2b4257422bcb870a4c2d205b3acdbb213a72f5e2250f61c80f79c9d014d010f82bdf8584441612c8e1fa4eb098678f5704a66fa8377d72646bad4be38e57a2c3 + languageName: node + linkType: hard + "path-to-regexp@npm:0.1.12": version: 0.1.12 resolution: "path-to-regexp@npm:0.1.12" @@ -13067,6 +13582,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.4": + version: 4.0.4 + resolution: "picomatch@npm:4.0.4" + checksum: 10/f6ef80a3590827ce20378ae110ac78209cc4f74d39236370f1780f957b7ee41c12acde0e4651b90f39983506fd2f5e449994716f516db2e9752924aff8de93ce + languageName: node + linkType: hard + "pify@npm:^5.0.0": version: 5.0.0 resolution: "pify@npm:5.0.0" @@ -13115,6 +13637,13 @@ __metadata: languageName: node linkType: hard +"possible-typed-array-names@npm:^1.0.0": + version: 1.1.0 + resolution: "possible-typed-array-names@npm:1.1.0" + checksum: 10/2f44137b8d3dd35f4a7ba7469eec1cd9cfbb46ec164b93a5bc1f4c3d68599c9910ee3b91da1d28b4560e9cc8414c3cd56fedc07259c67e52cc774476270d3302 + languageName: node + linkType: hard + "postcss@npm:^8.4.40": version: 8.4.41 resolution: "postcss@npm:8.4.41" @@ -13178,6 +13707,13 @@ __metadata: languageName: node linkType: hard +"proc-log@npm:^6.0.0": + version: 6.1.0 + resolution: "proc-log@npm:6.1.0" + checksum: 10/9033f30f168ed5a0991b773d0c50ff88384c4738e9a0a67d341de36bf7293771eed648ab6a0562f62276da12fde91f3bbfc75ffff6e71ad49aafd74fc646be66 + languageName: node + linkType: hard + "process-nextick-args@npm:~2.0.0": version: 2.0.1 resolution: "process-nextick-args@npm:2.0.1" @@ -13301,7 +13837,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.13.0, qs@npm:^6.11.2": +"qs@npm:6.13.0": version: 6.13.0 resolution: "qs@npm:6.13.0" dependencies: @@ -13310,6 +13846,15 @@ __metadata: languageName: node linkType: hard +"qs@npm:^6.11.2": + version: 6.15.1 + resolution: "qs@npm:6.15.1" + dependencies: + side-channel: "npm:^1.1.0" + checksum: 10/ec10b9957446b3f4a38000940f6374720b4e2985209b89df197066038c951472ea24cd98d6bc6df73a0cbec75bc056f638032e3fb447345017ff7e0f0a2693ac + languageName: node + linkType: hard + "querystringify@npm:^2.1.1": version: 2.2.0 resolution: "querystringify@npm:2.2.0" @@ -13414,7 +13959,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.2": +"readable-stream@npm:^2.0.2, readable-stream@npm:^2.3.8": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -13710,7 +14255,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 @@ -13926,6 +14471,41 @@ __metadata: languageName: node linkType: hard +"side-channel-list@npm:^1.0.0": + version: 1.0.1 + resolution: "side-channel-list@npm:1.0.1" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.4" + checksum: 10/3499671cd52adaee739eac1e14d07530b8e3530192741aeb05e7fe4ad1b51d1368ceea2cd3c21b0f62b05410a5c70a7c4d997ba4b143303ef73d0c65dfd1c252 + languageName: node + linkType: hard + +"side-channel-map@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-map@npm:1.0.1" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + checksum: 10/5771861f77feefe44f6195ed077a9e4f389acc188f895f570d56445e251b861754b547ea9ef73ecee4e01fdada6568bfe9020d2ec2dfc5571e9fa1bbc4a10615 + languageName: node + linkType: hard + +"side-channel-weakmap@npm:^1.0.2": + version: 1.0.2 + resolution: "side-channel-weakmap@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + side-channel-map: "npm:^1.0.1" + checksum: 10/a815c89bc78c5723c714ea1a77c938377ea710af20d4fb886d362b0d1f8ac73a17816a5f6640f354017d7e292a43da9c5e876c22145bac00b76cfb3468001736 + languageName: node + linkType: hard + "side-channel@npm:^1.0.6": version: 1.0.6 resolution: "side-channel@npm:1.0.6" @@ -13938,6 +14518,19 @@ __metadata: languageName: node linkType: hard +"side-channel@npm:^1.1.0": + version: 1.1.0 + resolution: "side-channel@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.3" + side-channel-list: "npm:^1.0.0" + side-channel-map: "npm:^1.0.1" + side-channel-weakmap: "npm:^1.0.2" + checksum: 10/7d53b9db292c6262f326b6ff3bc1611db84ece36c2c7dc0e937954c13c73185b0406c56589e2bb8d071d6fee468e14c39fb5d203ee39be66b7b8174f179afaba + languageName: node + linkType: hard + "signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -14122,6 +14715,15 @@ __metadata: languageName: node linkType: hard +"ssri@npm:^13.0.0": + version: 13.0.1 + resolution: "ssri@npm:13.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10/ae560d0378d074006a71b06af71bfbe84a3fe1ac6e16c1f07575f69e670d40170507fe52b21bcc23399429bc6a15f4bc3ea8d9bc88e9dfd7e87de564e6da6a72 + languageName: node + linkType: hard + "stable-hash@npm:^0.0.4": version: 0.0.4 resolution: "stable-hash@npm:0.0.4" @@ -14340,6 +14942,13 @@ __metadata: languageName: node linkType: hard +"tapable@npm:^2.3.0": + version: 2.3.2 + resolution: "tapable@npm:2.3.2" + checksum: 10/fd3affe2e34efb3970883f934b1828f10b48dffb1eb71a52b7f955bfdd88bf80e94ec388704d95334f72ddf77e34d813b19e1f4bf56897d20252fa025d44bede + languageName: node + linkType: hard + "tar-stream@npm:^3.1.7": version: 3.1.7 resolution: "tar-stream@npm:3.1.7" @@ -14365,17 +14974,16 @@ __metadata: languageName: node linkType: hard -"tar@npm:^7.4.3": - version: 7.4.3 - resolution: "tar@npm:7.4.3" +"tar@npm:^7.4.3, tar@npm:^7.5.4": + version: 7.5.13 + resolution: "tar@npm:7.5.13" dependencies: "@isaacs/fs-minipass": "npm:^4.0.0" chownr: "npm:^3.0.0" minipass: "npm:^7.1.2" - minizlib: "npm:^3.0.1" - mkdirp: "npm:^3.0.1" + minizlib: "npm:^3.1.0" yallist: "npm:^5.0.0" - checksum: 10/12a2a4fc6dee23e07cc47f1aeb3a14a1afd3f16397e1350036a8f4cdfee8dcac7ef5978337a4e7b2ac2c27a9a6d46388fc2088ea7c80cb6878c814b1425f8ecf + checksum: 10/2bc2b6f0349038a6621dbba1c4522d45752d5071b2994692257113c2050cd23fafc30308f820e5f8ad6fda3f7d7f92adc9a432aa733daa04c42af2061c021c3f languageName: node linkType: hard @@ -14399,6 +15007,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.12": + version: 0.2.16 + resolution: "tinyglobby@npm:0.2.16" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.4" + checksum: 10/5c2c41b572ada38449e7c86a5fe034f204a1dbba577225a761a14f29f48dc3f2fc0d81a6c56fcc67c5a742cc3aa9fb5e2ca18dbf22b610b0bc0e549b34d5a0f8 + languageName: node + linkType: hard + "tinyglobby@npm:^0.2.15": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" @@ -14423,6 +15041,17 @@ __metadata: languageName: node linkType: hard +"to-buffer@npm:^1.2.1": + version: 1.2.2 + resolution: "to-buffer@npm:1.2.2" + dependencies: + isarray: "npm:^2.0.5" + safe-buffer: "npm:^5.2.1" + typed-array-buffer: "npm:^1.0.3" + checksum: 10/69d806c20524ff1e4c44d49276bc96ff282dcae484780a3974e275dabeb75651ea430b074a2a4023701e63b3e1d87811cd82c0972f35280fe5461710e4872aba + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -14483,6 +15112,15 @@ __metadata: languageName: node linkType: hard +"ts-api-utils@npm:^2.5.0": + version: 2.5.0 + resolution: "ts-api-utils@npm:2.5.0" + peerDependencies: + typescript: ">=4.8.4" + checksum: 10/d5f1936f5618c6ab6942a97b78802217540ced00e7501862ae1f578d9a3aa189fc06050e64cb8951d21f7088e5fd35f53d2bf0d0370a883861c7b05e993ebc44 + languageName: node + linkType: hard + "ts-jest@npm:^29.2.5": version: 29.4.6 resolution: "ts-jest@npm:29.4.6" @@ -14638,6 +15276,17 @@ __metadata: languageName: node linkType: hard +"typed-array-buffer@npm:^1.0.3": + version: 1.0.3 + resolution: "typed-array-buffer@npm:1.0.3" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + is-typed-array: "npm:^1.1.14" + checksum: 10/3fb91f0735fb413b2bbaaca9fabe7b8fc14a3fa5a5a7546bab8a57e755be0e3788d893195ad9c2b842620592de0e68d4c077d4c2c41f04ec25b8b5bb82fa9a80 + languageName: node + linkType: hard + "typedarray@npm:^0.0.6": version: 0.0.6 resolution: "typedarray@npm:0.0.6" @@ -14730,6 +15379,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~7.19.0": + version: 7.19.2 + resolution: "undici-types@npm:7.19.2" + checksum: 10/05c34c63444c8caca7137f122b29ed50c1d7d05d1e0b2337f423575d3264054c4a0139e47e82e65723d09b97fcad6d8b0223b3550430a9006cc00e72a1e035bf + languageName: node + linkType: hard + "unique-filename@npm:^3.0.0": version: 3.0.0 resolution: "unique-filename@npm:3.0.0" @@ -15075,6 +15731,21 @@ __metadata: languageName: node linkType: hard +"which-typed-array@npm:^1.1.16": + version: 1.1.20 + resolution: "which-typed-array@npm:1.1.20" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + for-each: "npm:^0.3.5" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-tostringtag: "npm:^1.0.2" + checksum: 10/e56da3fc995d330ff012f682476f7883c16b12d36c6717c87c7ca23eb5a5ef957fa89115dacb389b11a9b4e99d5dbe2d12689b4d5d08c050b5aed0eae385b840 + languageName: node + linkType: hard + "which@npm:^1.2.14": version: 1.3.1 resolution: "which@npm:1.3.1" @@ -15119,6 +15790,17 @@ __metadata: languageName: node linkType: hard +"which@npm:^6.0.0": + version: 6.0.1 + resolution: "which@npm:6.0.1" + dependencies: + isexe: "npm:^4.0.0" + bin: + node-which: bin/which.js + checksum: 10/dbea77c7d3058bf6c78bf9659d2dce4d2b57d39a15b826b2af6ac2e5a219b99dc8a831b79fdbc453c0598adb4f3f84cf9c2491fd52beb9f5d2dececcad117f68 + languageName: node + linkType: hard + "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" From 25c0f58ea5e65837b97f6768dd7e44d5e63b94c7 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Tue, 14 Apr 2026 13:00:49 +0100 Subject: [PATCH 10/19] fix: re-generate lockfile --- packages/chomp-api-service/package.json | 7 +++---- .../src/chomp-api-service.ts | 8 +++++--- yarn.lock | 19 ++++++++++--------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/chomp-api-service/package.json b/packages/chomp-api-service/package.json index 89309ab33e..b368bb1e0f 100644 --- a/packages/chomp-api-service/package.json +++ b/packages/chomp-api-service/package.json @@ -3,8 +3,8 @@ "version": "0.0.0", "description": "Data service for the Chomp API", "keywords": [ - "MetaMask", - "Ethereum" + "Ethereum", + "MetaMask" ], "homepage": "https://github.com/MetaMask/core/tree/main/packages/chomp-api-service#readme", "bugs": { @@ -50,13 +50,12 @@ "@metamask/base-data-service": "^0.1.1", "@metamask/controller-utils": "^11.20.0", "@metamask/messenger": "^1.1.1", - "@metamask/profile-sync-controller": "^28.0.2", "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^11.9.0", "@tanstack/query-core": "^4.43.0" }, "devDependencies": { - "@metamask/auto-changelog": "^3.4.4", + "@metamask/auto-changelog": "^6.0.0", "@ts-bridge/cli": "^0.6.4", "@types/jest": "^29.5.14", "deepmerge": "^4.2.2", diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index 7cea914af7..631e80ae05 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -7,7 +7,6 @@ import type { import type { CreateServicePolicyOptions } from '@metamask/controller-utils'; import { HttpError } from '@metamask/controller-utils'; import type { Messenger } from '@metamask/messenger'; -import type { AuthenticationControllerGetBearerTokenAction } from '@metamask/profile-sync-controller/auth'; import { array, boolean, @@ -77,7 +76,10 @@ export type ChompApiServiceActions = /** * Actions from other messengers that {@link ChompApiService} calls. */ -type AllowedActions = AuthenticationControllerGetBearerTokenAction; +type AllowedActions = { + type: 'AuthenticationController:getBearerToken'; + handler: (entropySourceId?: string) => Promise; +}; /** * Published when {@link ChompApiService}'s cache is updated. @@ -176,7 +178,7 @@ const CreateWithdrawalResponseStruct = type({ * This service is responsible for communicating with the CHOMP API. * * All requests are authenticated via JWT Bearer tokens obtained from the - * {@link AuthenticationControllerGetBearerTokenAction} messenger action. + * `AuthenticationController:getBearerToken` messenger action. */ export class ChompApiService extends BaseDataService< typeof serviceName, diff --git a/yarn.lock b/yarn.lock index 41f666d343..7a110e9d5b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2945,18 +2945,20 @@ __metadata: languageName: node linkType: hard -"@metamask/auto-changelog@npm:^3.4.4": - version: 3.4.4 - resolution: "@metamask/auto-changelog@npm:3.4.4" +"@metamask/auto-changelog@npm:^6.0.0": + version: 6.0.0 + resolution: "@metamask/auto-changelog@npm:6.0.0" dependencies: + "@octokit/rest": "npm:^20.0.0" diff: "npm:^5.0.0" execa: "npm:^5.1.1" - prettier: "npm:^2.8.8" semver: "npm:^7.3.5" yargs: "npm:^17.0.1" + peerDependencies: + prettier: ">=3.0.0" bin: - auto-changelog: dist/cli.js - checksum: 10/70e98529a153ebeab10410dbc3f567014999f77ed82f2b52f1b36501b28a4e3614c809a90c89600a739d7710595bfecc30e2260410e6afac7539f8db65a48f2c + auto-changelog: dist/cli.mjs + checksum: 10/870dde1f24d3bc3d34238d7cda8a326ff3adb5709939159cd7ac8885fa5f17343789e72711e7cc2c4333999c5ac085a027b53e98d9475bf92f4a918db6ceaf7a languageName: node linkType: hard @@ -3163,11 +3165,10 @@ __metadata: version: 0.0.0-use.local resolution: "@metamask/chomp-api-service@workspace:packages/chomp-api-service" dependencies: - "@metamask/auto-changelog": "npm:^3.4.4" + "@metamask/auto-changelog": "npm:^6.0.0" "@metamask/base-data-service": "npm:^0.1.1" "@metamask/controller-utils": "npm:^11.20.0" "@metamask/messenger": "npm:^1.1.1" - "@metamask/profile-sync-controller": "npm:^28.0.2" "@metamask/superstruct": "npm:^3.1.0" "@metamask/utils": "npm:^11.9.0" "@tanstack/query-core": "npm:^4.43.0" @@ -13662,7 +13663,7 @@ __metadata: languageName: node linkType: hard -"prettier-2@npm:prettier@^2.8.8, prettier@npm:^2.8.8": +"prettier-2@npm:prettier@^2.8.8": version: 2.8.8 resolution: "prettier@npm:2.8.8" bin: From cd8cdd17679696c349bdbe315086916a4b2903dc Mon Sep 17 00:00:00 2001 From: John Whiles Date: Tue, 14 Apr 2026 18:56:36 +0100 Subject: [PATCH 11/19] chore: update teams.json to include new chomp service --- teams.json | 1 + 1 file changed, 1 insertion(+) diff --git a/teams.json b/teams.json index 775e450198..7ea11e2eab 100644 --- a/teams.json +++ b/teams.json @@ -34,6 +34,7 @@ "metamask/app-metadata-controller": "team-mobile-platform", "metamask/delegation-controller": "team-delegation", "metamask/chain-agnostic-permission": "team-wallet-integrations", + "metamask/chomp-api-service": "team-earn", "metamask/eip1193-permission-middleware": "team-wallet-integrations", "metamask/multichain-api-middleware": "team-wallet-integrations", "metamask/selected-network-controller": "team-wallet-integrations", From 6da38c6e231875bdb509067a2483974511509167 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Thu, 16 Apr 2026 11:45:50 +0100 Subject: [PATCH 12/19] feat: get service detail method to chomp client --- packages/chomp-api-service/CHANGELOG.md | 1 + .../chomp-api-service-method-action-types.ts | 11 ++- .../src/chomp-api-service.test.ts | 92 +++++++++++++++++++ .../src/chomp-api-service.ts | 72 +++++++++++++++ packages/chomp-api-service/src/index.ts | 5 + packages/chomp-api-service/src/types.ts | 25 +++++ 6 files changed, 205 insertions(+), 1 deletion(-) diff --git a/packages/chomp-api-service/CHANGELOG.md b/packages/chomp-api-service/CHANGELOG.md index 77f2d8816a..5731abfdac 100644 --- a/packages/chomp-api-service/CHANGELOG.md +++ b/packages/chomp-api-service/CHANGELOG.md @@ -10,5 +10,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `ChompApiService` ([#8413](https://github.com/MetaMask/core/pull/8413)) +- Add `getServiceDetails` method to retrieve delegation redeemer addresses and DeFi contract details for auto-deposit functionality [Unreleased]: https://github.com/MetaMask/core/ diff --git a/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts b/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts index 87454e3759..4d81b15a5a 100644 --- a/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts +++ b/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts @@ -61,6 +61,14 @@ export type ChompApiServiceCreateWithdrawalAction = { handler: ChompApiService['createWithdrawal']; }; +/** + * Retrieves service details via GET /v1/chomp. + */ +export type ChompApiServiceGetServiceDetailsAction = { + type: `ChompApiService:getServiceDetails`; + handler: ChompApiService['getServiceDetails']; +}; + /** * Union of all ChompApiService action types. */ @@ -71,4 +79,5 @@ export type ChompApiServiceMethodActions = | ChompApiServiceVerifyDelegationAction | ChompApiServiceCreateIntentsAction | ChompApiServiceGetIntentsByAddressAction - | ChompApiServiceCreateWithdrawalAction; + | ChompApiServiceCreateWithdrawalAction + | ChompApiServiceGetServiceDetailsAction; diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index 60e0fe8f8d..0379971bb7 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -456,6 +456,98 @@ describe('ChompApiService', () => { ); }); }); + + describe('getServiceDetails', () => { + const serviceDetailsResponse = { + auth: { + message: 'CHOMP Authentication ', + }, + chains: { + '0xa4b1': { + autoDepositDelegate: + '0xb4827a2a066cd2ef88560efdf063dd05c6c41cc7', + protocol: { + vedaProtocol: { + supportedTokens: [ + { + tokenAddress: + '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', + tokenDecimals: 6, + }, + ], + adapterAddress: + '0x4839b1BA117BdFFA986FCfA4E5fE6b9027b8f8B1', + intentTypes: ['cash-deposit', 'cash-withdrawal'], + }, + }, + }, + }, + }; + + it('sends a GET with auth headers and chainId query param and returns the response', async () => { + nock(BASE_URL) + .get('/v1/chomp') + .query({ chainId: '0xa4b1' }) + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .reply(200, serviceDetailsResponse); + const { rootMessenger } = createService(); + + const result = await rootMessenger.call( + 'ChompApiService:getServiceDetails', + ['0xa4b1'], + ); + + expect(result).toStrictEqual(serviceDetailsResponse); + }); + + it('supports multiple chain IDs as a comma-separated query param', async () => { + nock(BASE_URL) + .get('/v1/chomp') + .query({ chainId: '0xa4b1,0x1' }) + .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) + .reply(200, serviceDetailsResponse); + const { service } = createService(); + + const result = await service.getServiceDetails(['0xa4b1', '0x1']); + + expect(result).toStrictEqual(serviceDetailsResponse); + }); + + it('throws when a chainId is not a valid hex string', async () => { + const { service } = createService(); + + await expect( + service.getServiceDetails(['not-hex']), + ).rejects.toThrow( + "Invalid chainId: expected a 0x-prefixed hex string, got 'not-hex'", + ); + }); + + it('throws on non-OK status', async () => { + nock(BASE_URL) + .get('/v1/chomp') + .query({ chainId: '0xa4b1' }) + .times(DEFAULT_MAX_RETRIES + 1) + .reply(400); + const { service } = createService(); + + await expect( + service.getServiceDetails(['0xa4b1']), + ).rejects.toThrow("GET /v1/chomp failed with status '400'"); + }); + + it('throws on malformed response', async () => { + nock(BASE_URL) + .get('/v1/chomp') + .query({ chainId: '0xa4b1' }) + .reply(200, JSON.stringify({ bad: 'data' })); + const { service } = createService(); + + await expect( + service.getServiceDetails(['0xa4b1']), + ).rejects.toThrow('At path: auth -- Expected an object'); + }); + }); }); /** diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index 631e80ae05..deb0e4ad4e 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -14,7 +14,9 @@ import { define, enums, literal, + number, optional, + record, string, type, } from '@metamask/superstruct'; @@ -32,6 +34,7 @@ import type { IntentEntry, SendIntentRequest, SendIntentResponse, + ServiceDetailsResponse, VerifyDelegationRequest, VerifyDelegationResponse, } from './types'; @@ -58,6 +61,7 @@ const MESSENGER_EXPOSED_METHODS = [ 'createIntents', 'getIntentsByAddress', 'createWithdrawal', + 'getServiceDetails', ] as const; /** @@ -172,6 +176,30 @@ const CreateWithdrawalResponseStruct = type({ success: literal(true), }); +const ServiceDetailsProtocolStruct = type({ + supportedTokens: array( + type({ + tokenAddress: string(), + tokenDecimals: number(), + }), + ), + adapterAddress: string(), + intentTypes: array(enums(['cash-deposit', 'cash-withdrawal'])), +}); + +const ServiceDetailsResponseStruct = type({ + auth: type({ + message: string(), + }), + chains: record( + string(), + type({ + autoDepositDelegate: string(), + protocol: record(string(), ServiceDetailsProtocolStruct), + }), + ), +}); + // === SERVICE DEFINITION === /** @@ -501,4 +529,48 @@ export class ChompApiService extends BaseDataService< return create(jsonResponse, CreateWithdrawalResponseStruct); } + + /** + * Retrieves service details including delegation redeemer addresses and DeFi + * contract details for signing delegations for auto-deposit functionality. + * + * GET /v1/chomp + * + * @param chainIds - Array of chain IDs (0x-prefixed hex strings) to retrieve + * details for. + * @returns The service details for the requested chains. + */ + async getServiceDetails(chainIds: string[]): Promise { + for (const chainId of chainIds) { + if (!isStrictHexString(chainId)) { + throw new Error( + `Invalid chainId: expected a 0x-prefixed hex string, got '${chainId}'`, + ); + } + } + + const jsonResponse = await this.fetchQuery({ + queryKey: [`${this.name}:getServiceDetails`, chainIds], + queryFn: async () => { + const headers = await this.#authHeaders(); + const url = new URL('/v1/chomp', this.#baseUrl); + url.searchParams.set('chainId', chainIds.join(',')); + const response = await fetch(url, { headers }); + + if (!response.ok) { + throw new HttpError( + response.status, + `GET /v1/chomp failed with status '${response.status}'`, + ); + } + + return response.json(); + }, + }); + + return create( + jsonResponse, + ServiceDetailsResponseStruct, + ) as ServiceDetailsResponse; + } } diff --git a/packages/chomp-api-service/src/index.ts b/packages/chomp-api-service/src/index.ts index 0052e7f8dd..f7c4a7dbf9 100644 --- a/packages/chomp-api-service/src/index.ts +++ b/packages/chomp-api-service/src/index.ts @@ -15,6 +15,7 @@ export type { ChompApiServiceCreateIntentsAction, ChompApiServiceGetIntentsByAddressAction, ChompApiServiceCreateWithdrawalAction, + ChompApiServiceGetServiceDetailsAction, } from './chomp-api-service-method-action-types'; export type { AssociateAddressRequest, @@ -29,6 +30,10 @@ export type { IntentMetadataResponse, SendIntentRequest, SendIntentResponse, + ServiceDetailsChain, + ServiceDetailsProtocol, + ServiceDetailsResponse, + ServiceDetailsSupportedToken, SignedDelegation, VerifyDelegationRequest, VerifyDelegationResponse, diff --git a/packages/chomp-api-service/src/types.ts b/packages/chomp-api-service/src/types.ts index e68092e22d..cf219af470 100644 --- a/packages/chomp-api-service/src/types.ts +++ b/packages/chomp-api-service/src/types.ts @@ -116,3 +116,28 @@ export type IntentEntry = { export type CreateWithdrawalResponse = { success: true; }; + +// === SERVICE DETAILS TYPES === + +export type ServiceDetailsSupportedToken = { + tokenAddress: string; + tokenDecimals: number; +}; + +export type ServiceDetailsProtocol = { + supportedTokens: ServiceDetailsSupportedToken[]; + adapterAddress: string; + intentTypes: ('cash-deposit' | 'cash-withdrawal')[]; +}; + +export type ServiceDetailsChain = { + autoDepositDelegate: string; + protocol: Record; +}; + +export type ServiceDetailsResponse = { + auth: { + message: string; + }; + chains: Record; +}; From 82440b1f30169113c50426f78cdd683f7aea1cd9 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Thu, 16 Apr 2026 15:32:26 +0100 Subject: [PATCH 13/19] chore: fix codeowners --- .github/CODEOWNERS | 6 +++--- packages/chomp-api-service/CHANGELOG.md | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5a53d12117..1819430016 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -40,7 +40,7 @@ ## Earn Team /packages/earn-controller @MetaMask/earn /packages/money-account-balance-service @MetaMask/earn -/packages/chomp-api-service @MetaMask/earn +/packages/chomp-api-service @MetaMask/earn @MetaMask/delegation ## Social AI Team /packages/ai-controllers @MetaMask/social-ai @@ -230,5 +230,5 @@ /packages/social-controllers/CHANGELOG.md @MetaMask/social-ai @MetaMask/core-platform /packages/money-account-controller/package.json @MetaMask/accounts-engineers @MetaMask/core-platform /packages/money-account-controller/CHANGELOG.md @MetaMask/accounts-engineers @MetaMask/core-platform -/packages/chomp-api-service/package.json @MetaMask/accounts-engineers @MetaMask/core-platform -/packages/chomp-api-service/CHANGELOG.md @MetaMask/accounts-engineers @MetaMask/core-platform +/packages/chomp-api-service/package.json @MetaMask/earn @MetaMask/delegation @MetaMask/core-platform +/packages/chomp-api-service/CHANGELOG.md @MetaMask/earn @MetaMask/delegation @MetaMask/core-platform diff --git a/packages/chomp-api-service/CHANGELOG.md b/packages/chomp-api-service/CHANGELOG.md index 5731abfdac..77f2d8816a 100644 --- a/packages/chomp-api-service/CHANGELOG.md +++ b/packages/chomp-api-service/CHANGELOG.md @@ -10,6 +10,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `ChompApiService` ([#8413](https://github.com/MetaMask/core/pull/8413)) -- Add `getServiceDetails` method to retrieve delegation redeemer addresses and DeFi contract details for auto-deposit functionality [Unreleased]: https://github.com/MetaMask/core/ From fe0c15d59181baba526434f633cc81dcf5f9b850 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Thu, 16 Apr 2026 15:42:59 +0100 Subject: [PATCH 14/19] chore: regenerate yarn.lock --- yarn.lock | 794 ++++-------------------------------------------------- 1 file changed, 48 insertions(+), 746 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7a110e9d5b..b87a0e4ee8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -154,18 +154,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0": - version: 7.29.2 - resolution: "@babel/parser@npm:7.29.2" - dependencies: - "@babel/types": "npm:^7.29.0" - bin: - parser: ./bin/babel-parser.js - checksum: 10/45d050bf75aa5194b3255f156173e8553d615ff5a2434674cc4a10cdc7c261931befb8618c996a1c449b87f0ef32a3407879af2ac967d95dc7b4fdbae7037efa - languageName: node - linkType: hard - -"@babel/parser@npm:^7.24.7": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0": version: 7.29.0 resolution: "@babel/parser@npm:7.29.0" dependencies: @@ -720,20 +709,13 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.39.1": +"@eslint/js@npm:9.39.1, @eslint/js@npm:^9.11.0": version: 9.39.1 resolution: "@eslint/js@npm:9.39.1" checksum: 10/b10b9b953212c0f3ffca475159bbe519e9e98847200c7432d1637d444fddcd7b712d2b7710a7dc20510f9cfbe8db330039b2aad09cb55d9545b116d940dbeed2 languageName: node linkType: hard -"@eslint/js@npm:^9.11.0": - version: 9.39.4 - resolution: "@eslint/js@npm:9.39.4" - checksum: 10/0a7ab4c4108cf2cadf66849ebd20f5957cc53052b88d8807d0b54e489dbf6ffcaf741e144e7f9b187c395499ce2e6ddc565dbfa4f60c6df455cf2b30bcbdc5a3 - languageName: node - linkType: hard - "@eslint/object-schema@npm:^2.1.7": version: 2.1.7 resolution: "@eslint/object-schema@npm:2.1.7" @@ -1748,13 +1730,6 @@ __metadata: languageName: node linkType: hard -"@gar/promise-retry@npm:^1.0.0": - version: 1.0.3 - resolution: "@gar/promise-retry@npm:1.0.3" - checksum: 10/0d13ea3bb1025755e055648f6e290d2a7e0c87affaf552218f09f66b3fcd9ea9d5c9cc5fe2aa6e285e1530437768e40f9448fe9a86f4f3417b216dcf488d3d1a - languageName: node - linkType: hard - "@grpc/grpc-js@npm:~1.9.0": version: 1.9.15 resolution: "@grpc/grpc-js@npm:1.9.15" @@ -2945,24 +2920,7 @@ __metadata: languageName: node linkType: hard -"@metamask/auto-changelog@npm:^6.0.0": - version: 6.0.0 - resolution: "@metamask/auto-changelog@npm:6.0.0" - dependencies: - "@octokit/rest": "npm:^20.0.0" - diff: "npm:^5.0.0" - execa: "npm:^5.1.1" - semver: "npm:^7.3.5" - yargs: "npm:^17.0.1" - peerDependencies: - prettier: ">=3.0.0" - bin: - auto-changelog: dist/cli.mjs - checksum: 10/870dde1f24d3bc3d34238d7cda8a326ff3adb5709939159cd7ac8885fa5f17343789e72711e7cc2c4333999c5ac085a027b53e98d9475bf92f4a918db6ceaf7a - languageName: node - linkType: hard - -"@metamask/auto-changelog@npm:^6.1.0": +"@metamask/auto-changelog@npm:^6.0.0, @metamask/auto-changelog@npm:^6.1.0": version: 6.1.0 resolution: "@metamask/auto-changelog@npm:6.1.0" dependencies: @@ -5933,19 +5891,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/agent@npm:^4.0.0": - version: 4.0.0 - resolution: "@npmcli/agent@npm:4.0.0" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^11.2.1" - socks-proxy-agent: "npm:^8.0.3" - checksum: 10/1a81573becc60515031accc696e6405e9b894e65c12b98ef4aeee03b5617c41948633159dbf6caf5dde5b47367eeb749bdc7b7dfb21960930a9060a935c6f636 - languageName: node - linkType: hard - "@npmcli/fs@npm:^3.1.0": version: 3.1.1 resolution: "@npmcli/fs@npm:3.1.1" @@ -5955,15 +5900,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/fs@npm:^5.0.0": - version: 5.0.0 - resolution: "@npmcli/fs@npm:5.0.0" - dependencies: - semver: "npm:^7.3.5" - checksum: 10/4935c7719d17830d0f9fa46c50be17b2a3c945cec61760f6d0909bce47677c42e1810ca673305890f9e84f008ec4d8e841182f371e42100a8159d15f22249208 - languageName: node - linkType: hard - "@npmcli/git@npm:^5.0.0": version: 5.0.8 resolution: "@npmcli/git@npm:5.0.8" @@ -6012,13 +5948,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/redact@npm:^4.0.0": - version: 4.0.0 - resolution: "@npmcli/redact@npm:4.0.0" - checksum: 10/5d52df2b5267f4369c97a2b2f7c427e3d7aa4b6a83e7a1b522e196f6e9d50024c620bd0cb2052067c74d1aaa0c330d9bc04e1d335bfb46180e705bb33423e74c - languageName: node - linkType: hard - "@npmcli/run-script@npm:8.1.0": version: 8.1.0 resolution: "@npmcli/run-script@npm:8.1.0" @@ -6631,20 +6560,13 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-core@npm:4.43.0": +"@tanstack/query-core@npm:4.43.0, @tanstack/query-core@npm:^4.43.0": version: 4.43.0 resolution: "@tanstack/query-core@npm:4.43.0" checksum: 10/c2a5a151c7adaea8311e01a643255f31946ae3164a71567ba80048242821ae14043f13f5516b695baebe5ea7e4b2cf717fd60908a929d18a5c5125fee925ff67 languageName: node linkType: hard -"@tanstack/query-core@npm:^4.43.0": - version: 4.44.0 - resolution: "@tanstack/query-core@npm:4.44.0" - checksum: 10/f7f5c69cb2d44b58e1a9bfaa304a82724bb49f0ff63fd3abdfe377f15825ad910e1d31dd529d94e0650ff17229930eef2f54e281dbe99fa6cbd6a85e7c27bb9d - languageName: node - linkType: hard - "@tanstack/query-core@npm:^5.62.16": version: 5.90.20 resolution: "@tanstack/query-core@npm:5.90.20" @@ -7009,16 +6931,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": - version: 25.6.0 - resolution: "@types/node@npm:25.6.0" - dependencies: - undici-types: "npm:~7.19.0" - checksum: 10/99b18690a4be55904cbf8f6a6ac8eed5ec5b8d791fdd8ee2ae598b46c0fa9b83cda7b70dd7f00dbfb18189dcfc67648fdc7fdd3fcced2619a5a6453d9aec107d - languageName: node - linkType: hard - -"@types/node@npm:22.7.5": +"@types/node@npm:*, @types/node@npm:22.7.5, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": version: 22.7.5 resolution: "@types/node@npm:22.7.5" dependencies: @@ -7168,7 +7081,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.54.0": +"@typescript-eslint/eslint-plugin@npm:8.54.0, @typescript-eslint/eslint-plugin@npm:^8.48.0": version: 8.54.0 resolution: "@typescript-eslint/eslint-plugin@npm:8.54.0" dependencies: @@ -7188,27 +7101,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^8.48.0": - version: 8.58.1 - resolution: "@typescript-eslint/eslint-plugin@npm:8.58.1" - dependencies: - "@eslint-community/regexpp": "npm:^4.12.2" - "@typescript-eslint/scope-manager": "npm:8.58.1" - "@typescript-eslint/type-utils": "npm:8.58.1" - "@typescript-eslint/utils": "npm:8.58.1" - "@typescript-eslint/visitor-keys": "npm:8.58.1" - ignore: "npm:^7.0.5" - natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^2.5.0" - peerDependencies: - "@typescript-eslint/parser": ^8.58.1 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.1.0" - checksum: 10/0fcbe6faadb77313aa91c895c977a24fc72a79eed62f46f7b2d5804db52a9af99351b33b9c4d73fdabb0f69772d5d4a9acdef249a0d1526a44d3817fb51419b5 - languageName: node - linkType: hard - -"@typescript-eslint/parser@npm:8.54.0": +"@typescript-eslint/parser@npm:8.54.0, @typescript-eslint/parser@npm:^8.48.0": version: 8.54.0 resolution: "@typescript-eslint/parser@npm:8.54.0" dependencies: @@ -7224,22 +7117,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^8.48.0": - version: 8.58.1 - resolution: "@typescript-eslint/parser@npm:8.58.1" - dependencies: - "@typescript-eslint/scope-manager": "npm:8.58.1" - "@typescript-eslint/types": "npm:8.58.1" - "@typescript-eslint/typescript-estree": "npm:8.58.1" - "@typescript-eslint/visitor-keys": "npm:8.58.1" - debug: "npm:^4.4.3" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.1.0" - checksum: 10/062584d26609e82169459ebf0c59f4925ba6596f4ea1637a320c34a25c34117585c458b9c6c268f5eeaee1988f4c7257d34d4bd05a214a88de12110e71b48493 - languageName: node - linkType: hard - "@typescript-eslint/project-service@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/project-service@npm:8.54.0" @@ -7253,19 +7130,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/project-service@npm:8.58.1": - version: 8.58.1 - resolution: "@typescript-eslint/project-service@npm:8.58.1" - dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.58.1" - "@typescript-eslint/types": "npm:^8.58.1" - debug: "npm:^4.4.3" - peerDependencies: - typescript: ">=4.8.4 <6.1.0" - checksum: 10/2f3136268fc262e77e8c8c14291e60c54e0228b63ccb022826b6def6d80b83ce9c3a92fef11c888889fb204343c845556868c49495c3aa0a115e9a861dd5fe99 - languageName: node - linkType: hard - "@typescript-eslint/scope-manager@npm:8.54.0, @typescript-eslint/scope-manager@npm:^8.1.0": version: 8.54.0 resolution: "@typescript-eslint/scope-manager@npm:8.54.0" @@ -7276,16 +7140,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.58.1": - version: 8.58.1 - resolution: "@typescript-eslint/scope-manager@npm:8.58.1" - dependencies: - "@typescript-eslint/types": "npm:8.58.1" - "@typescript-eslint/visitor-keys": "npm:8.58.1" - checksum: 10/dc070fd73847807e32cb7dfc37512abd0b1a485b0037d8cfb6c593555a5b673d3ee9d19c61504ea71d067ad610c66f64d70d56f3a5db51895c0a25e45621cd08 - languageName: node - linkType: hard - "@typescript-eslint/tsconfig-utils@npm:8.54.0, @typescript-eslint/tsconfig-utils@npm:^8.54.0": version: 8.54.0 resolution: "@typescript-eslint/tsconfig-utils@npm:8.54.0" @@ -7295,15 +7149,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/tsconfig-utils@npm:8.58.1, @typescript-eslint/tsconfig-utils@npm:^8.58.1": - version: 8.58.1 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.58.1" - peerDependencies: - typescript: ">=4.8.4 <6.1.0" - checksum: 10/4a5cf9a5eb834d05f2d37f7d80319575cf4a75aa52807b96edc0db24349ba417b41cb6f5257ffb07b8b9b4c59c7438637e8c75ed7c2b513bcb07e259b49e058e - languageName: node - linkType: hard - "@typescript-eslint/type-utils@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/type-utils@npm:8.54.0" @@ -7320,22 +7165,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.58.1": - version: 8.58.1 - resolution: "@typescript-eslint/type-utils@npm:8.58.1" - dependencies: - "@typescript-eslint/types": "npm:8.58.1" - "@typescript-eslint/typescript-estree": "npm:8.58.1" - "@typescript-eslint/utils": "npm:8.58.1" - debug: "npm:^4.4.3" - ts-api-utils: "npm:^2.5.0" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.1.0" - checksum: 10/39d62d6711590e817cf9a36257c19ea18e201ceca42b900350e121ea8986c167fbdd9da385ced29c61e38a1b5c76b6c320d59e21d4dd7f32767520e31aef4654 - languageName: node - linkType: hard - "@typescript-eslint/types@npm:8.54.0, @typescript-eslint/types@npm:^8.54.0": version: 8.54.0 resolution: "@typescript-eslint/types@npm:8.54.0" @@ -7343,13 +7172,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:8.58.1, @typescript-eslint/types@npm:^8.58.1": - version: 8.58.1 - resolution: "@typescript-eslint/types@npm:8.58.1" - checksum: 10/447e1351af8a47297096f063b327c69b1c986af89e39cb39e142bb35d7bec2ce8f34f31edcf62d1beb2e09a38e2029b12b50b335dae4e7c9ff49bd82f9127523 - languageName: node - linkType: hard - "@typescript-eslint/typescript-estree@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/typescript-estree@npm:8.54.0" @@ -7369,26 +7191,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.58.1": - version: 8.58.1 - resolution: "@typescript-eslint/typescript-estree@npm:8.58.1" - dependencies: - "@typescript-eslint/project-service": "npm:8.58.1" - "@typescript-eslint/tsconfig-utils": "npm:8.58.1" - "@typescript-eslint/types": "npm:8.58.1" - "@typescript-eslint/visitor-keys": "npm:8.58.1" - debug: "npm:^4.4.3" - minimatch: "npm:^10.2.2" - semver: "npm:^7.7.3" - tinyglobby: "npm:^0.2.15" - ts-api-utils: "npm:^2.5.0" - peerDependencies: - typescript: ">=4.8.4 <6.1.0" - checksum: 10/107510b484148a8a9a5874f5451b9a6649609607ee5e67de36cded786157987a5262b145398b1bd1935afab66134532369a4d6abb53c6f5b7744e3ace0b13f07 - languageName: node - linkType: hard - -"@typescript-eslint/utils@npm:8.54.0, @typescript-eslint/utils@npm:^8.1.0": +"@typescript-eslint/utils@npm:8.54.0, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.1.0": version: 8.54.0 resolution: "@typescript-eslint/utils@npm:8.54.0" dependencies: @@ -7403,21 +7206,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.58.1, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0": - version: 8.58.1 - resolution: "@typescript-eslint/utils@npm:8.58.1" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.9.1" - "@typescript-eslint/scope-manager": "npm:8.58.1" - "@typescript-eslint/types": "npm:8.58.1" - "@typescript-eslint/typescript-estree": "npm:8.58.1" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.1.0" - checksum: 10/c51a5e116d1a09d0eb701c5884d5b9b8c22f79c427cb4c46357e4bcb7dfdfd9beba92e5d518572f42111b7335541a4ccefe3c05595fc3d666c1b62ddd1522e54 - languageName: node - linkType: hard - "@typescript-eslint/visitor-keys@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/visitor-keys@npm:8.54.0" @@ -7428,16 +7216,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.58.1": - version: 8.58.1 - resolution: "@typescript-eslint/visitor-keys@npm:8.58.1" - dependencies: - "@typescript-eslint/types": "npm:8.58.1" - eslint-visitor-keys: "npm:^5.0.0" - checksum: 10/e9f34741da6fc0cb8e9eb67828ea4427ac2004a33ce8d1e1e9ba038471f9ed68405eca871651bb2efa793a467bc5233a4310c5571ad1497cb2a84a600e1733a8 - languageName: node - linkType: hard - "@vercel/stega@npm:^0.1.2": version: 0.1.2 resolution: "@vercel/stega@npm:0.1.2" @@ -7532,13 +7310,6 @@ __metadata: languageName: node linkType: hard -"abbrev@npm:^4.0.0": - version: 4.0.0 - resolution: "abbrev@npm:4.0.0" - checksum: 10/e2f0c6a6708ad738b3e8f50233f4800de31ad41a6cdc50e0cbe51b76fed69fd0213516d92c15ce1a9985fca71a14606a9be22bf00f8475a58987b9bfb671c582 - languageName: node - linkType: hard - "abitype@npm:1.2.3, abitype@npm:^1.2.3": version: 1.2.3 resolution: "abitype@npm:1.2.3" @@ -7640,7 +7411,7 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.1": +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": version: 7.1.1 resolution: "agent-base@npm:7.1.1" dependencies: @@ -7649,13 +7420,6 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.1.0": - version: 7.1.4 - resolution: "agent-base@npm:7.1.4" - checksum: 10/79bef167247789f955aaba113bae74bf64aa1e1acca4b1d6bb444bdf91d82c3e07e9451ef6a6e2e35e8f71a6f97ce33e3d855a5328eb9fad1bc3cc4cfd031ed8 - languageName: node - linkType: hard - "aggregate-error@npm:^3.0.0": version: 3.1.0 resolution: "aggregate-error@npm:3.1.0" @@ -7820,20 +7584,6 @@ __metadata: languageName: node linkType: hard -"async-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-function@npm:1.0.0" - checksum: 10/1a09379937d846f0ce7614e75071c12826945d4e417db634156bf0e4673c495989302f52186dfa9767a1d9181794554717badd193ca2bbab046ef1da741d8efd - languageName: node - linkType: hard - -"async-generator-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-generator-function@npm:1.0.0" - checksum: 10/3d49e7acbeee9e84537f4cb0e0f91893df8eba976759875ae8ee9e3d3c82f6ecdebdb347c2fad9926b92596d93cdfc78ecc988bcdf407e40433e8e8e6fe5d78e - languageName: node - linkType: hard - "async-mutex@npm:^0.3.1": version: 0.3.2 resolution: "async-mutex@npm:0.3.2" @@ -7859,15 +7609,6 @@ __metadata: languageName: node linkType: hard -"available-typed-arrays@npm:^1.0.7": - version: 1.0.7 - resolution: "available-typed-arrays@npm:1.0.7" - dependencies: - possible-typed-array-names: "npm:^1.0.0" - checksum: 10/6c9da3a66caddd83c875010a1ca8ef11eac02ba15fb592dc9418b2b5e7b77b645fa7729380a92d9835c2f05f2ca1b6251f39b993e0feb3f1517c74fa1af02cab - languageName: node - linkType: hard - "axios@npm:^1.7.4": version: 1.7.5 resolution: "axios@npm:1.7.5" @@ -7982,13 +7723,6 @@ __metadata: languageName: node linkType: hard -"balanced-match@npm:^4.0.2": - version: 4.0.4 - resolution: "balanced-match@npm:4.0.4" - checksum: 10/fb07bb66a0959c2843fc055838047e2a95ccebb837c519614afb067ebfdf2fa967ca8d712c35ced07f2cd26fc6f07964230b094891315ad74f11eba3d53178a0 - languageName: node - linkType: hard - "bare-events@npm:^2.2.0": version: 2.4.2 resolution: "bare-events@npm:2.4.2" @@ -8151,15 +7885,6 @@ __metadata: languageName: node linkType: hard -"brace-expansion@npm:^5.0.5": - version: 5.0.5 - resolution: "brace-expansion@npm:5.0.5" - dependencies: - balanced-match: "npm:^4.0.2" - checksum: 10/f259b2ddf04489da9512ad637ba6b4ef2d77abd4445d20f7f1714585f153435200a53fa6a2e4a5ee974df14ddad4cd16421f6f803e96e8b452bd48598878d0ee - languageName: node - linkType: hard - "braces@npm:^3.0.3": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -8302,24 +8027,6 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^20.0.1": - version: 20.0.4 - resolution: "cacache@npm:20.0.4" - dependencies: - "@npmcli/fs": "npm:^5.0.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^13.0.0" - lru-cache: "npm:^11.1.0" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^7.0.2" - ssri: "npm:^13.0.0" - checksum: 10/02c1b4c57dc2473e6f4654220c9405b73ae5fcdb392f82a7cf535468a52b842690cdb3694861d13bbe4dc067d5f8abe9697b4f791ae5b65cd73d62abad1e3e54 - languageName: node - linkType: hard - "call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": version: 1.0.2 resolution: "call-bind-apply-helpers@npm:1.0.2" @@ -8342,28 +8049,6 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.8": - version: 1.0.9 - resolution: "call-bind@npm:1.0.9" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - es-define-property: "npm:^1.0.1" - get-intrinsic: "npm:^1.3.0" - set-function-length: "npm:^1.2.2" - checksum: 10/25b1a98d6158f0adf9fface594ca82be4e3ed481d8ff7f36ad1fccb0c8377e38c6a04ff3248693723222d378677e93077c739defc8a6741c82b7e00bcee1245d - languageName: node - linkType: hard - -"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": - version: 1.0.4 - resolution: "call-bound@npm:1.0.4" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - get-intrinsic: "npm:^1.3.0" - checksum: 10/ef2b96e126ec0e58a7ff694db43f4d0d44f80e641370c21549ed911fecbdbc2df3ebc9bddad918d6bbdefeafb60bb3337902006d5176d72bcd2da74820991af7 - languageName: node - linkType: hard - "callsite@npm:^1.0.0": version: 1.0.0 resolution: "callsite@npm:1.0.0" @@ -9221,7 +8906,7 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.15.0": +"enhanced-resolve@npm:^5.15.0, enhanced-resolve@npm:^5.17.1": version: 5.18.0 resolution: "enhanced-resolve@npm:5.18.0" dependencies: @@ -9231,16 +8916,6 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.17.1": - version: 5.20.1 - resolution: "enhanced-resolve@npm:5.20.1" - dependencies: - graceful-fs: "npm:^4.2.4" - tapable: "npm:^2.3.0" - checksum: 10/588afc56de97334e5742faebcf8177a504da08ea817d399f9901f35d8e9e5e6fa86b4c2ce95a99081f947764e09c9991cc0fc0ba5751bae455c329643a709187 - languageName: node - linkType: hard - "entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" @@ -9672,13 +9347,6 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^5.0.0": - version: 5.0.1 - resolution: "eslint-visitor-keys@npm:5.0.1" - checksum: 10/f9cc1a57b75e0ef949545cac33d01e8367e302de4c1483266ed4d8646ee5c306376660196bbb38b004e767b7043d1e661cb4336b49eff634a1bbe75c1db709ec - languageName: node - linkType: hard - "eslint@npm:^9.39.1": version: 9.39.1 resolution: "eslint@npm:9.39.1" @@ -10375,15 +10043,6 @@ __metadata: languageName: node linkType: hard -"for-each@npm:^0.3.5": - version: 0.3.5 - resolution: "for-each@npm:0.3.5" - dependencies: - is-callable: "npm:^1.2.7" - checksum: 10/330cc2439f85c94f4609de3ee1d32c5693ae15cdd7fe3d112c4fd9efd4ce7143f2c64ef6c2c9e0cfdb0058437f33ef05b5bdae5b98fcc903fb2143fbaf0fea0f - languageName: node - linkType: hard - "foreach@npm:^2.0.4": version: 2.0.6 resolution: "foreach@npm:2.0.6" @@ -10499,13 +10158,6 @@ __metadata: languageName: node linkType: hard -"generator-function@npm:^2.0.0": - version: 2.0.1 - resolution: "generator-function@npm:2.0.1" - checksum: 10/eb7e7eb896c5433f3d40982b2ccacdb3dd990dd3499f14040e002b5d54572476513be8a2e6f9609f6e41ab29f2c4469307611ddbfc37ff4e46b765c326663805 - languageName: node - linkType: hard - "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -10520,24 +10172,21 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.3.0": - version: 1.3.1 - resolution: "get-intrinsic@npm:1.3.1" +"get-intrinsic@npm:^1.2.4": + version: 1.3.0 + resolution: "get-intrinsic@npm:1.3.0" dependencies: - async-function: "npm:^1.0.0" - async-generator-function: "npm:^1.0.0" call-bind-apply-helpers: "npm:^1.0.2" es-define-property: "npm:^1.0.1" es-errors: "npm:^1.3.0" es-object-atoms: "npm:^1.1.1" function-bind: "npm:^1.1.2" - generator-function: "npm:^2.0.0" get-proto: "npm:^1.0.1" gopd: "npm:^1.2.0" has-symbols: "npm:^1.1.0" hasown: "npm:^2.0.2" math-intrinsics: "npm:^1.1.0" - checksum: 10/bb579dda84caa4a3a41611bdd483dade7f00f246f2a7992eb143c5861155290df3fdb48a8406efa3dfb0b434e2c8fafa4eebd469e409d0439247f85fc3fa2cc1 + checksum: 10/6e9dd920ff054147b6f44cb98104330e87caafae051b6d37b13384a45ba15e71af33c3baeac7cb630a0aaa23142718dcf25b45cfdd86c184c5dcb4e56d953a10 languageName: node linkType: hard @@ -10606,7 +10255,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10": +"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -10622,33 +10271,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.3.7": - version: 10.5.0 - resolution: "glob@npm:10.5.0" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^3.1.2" - minimatch: "npm:^9.0.4" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^1.11.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10/ab3bccfefcc0afaedbd1f480cd0c4a2c0e322eb3f0aa7ceaa31b3f00b825069f17cf0f1fc8b6f256795074b903f37c0ade37ddda6a176aa57f1c2bbfe7240653 - languageName: node - linkType: hard - -"glob@npm:^13.0.0": - version: 13.0.6 - resolution: "glob@npm:13.0.6" - dependencies: - minimatch: "npm:^10.2.2" - minipass: "npm:^7.1.3" - path-scurry: "npm:^2.0.2" - checksum: 10/201ad69e5f0aa74e1d8c00a481581f8b8c804b6a4fbfabeeb8541f5d756932800331daeba99b58fb9e4cd67e12ba5a7eba5b82fb476691588418060b84353214 - languageName: node - linkType: hard - "glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.7": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -10770,31 +10392,21 @@ __metadata: languageName: node linkType: hard -"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": +"has-symbols@npm:^1.1.0": version: 1.1.0 resolution: "has-symbols@npm:1.1.0" checksum: 10/959385c98696ebbca51e7534e0dc723ada325efa3475350951363cce216d27373e0259b63edb599f72eb94d6cde8577b4b2375f080b303947e560f85692834fa languageName: node linkType: hard -"has-tostringtag@npm:^1.0.2": - version: 1.0.2 - resolution: "has-tostringtag@npm:1.0.2" - dependencies: - has-symbols: "npm:^1.0.3" - checksum: 10/c74c5f5ceee3c8a5b8bc37719840dc3749f5b0306d818974141dda2471a1a2ca6c8e46b9d6ac222c5345df7a901c9b6f350b1e6d62763fec877e26609a401bfe - languageName: node - linkType: hard - "hash-base@npm:^3.0.0": - version: 3.1.2 - resolution: "hash-base@npm:3.1.2" + version: 3.1.0 + resolution: "hash-base@npm:3.1.0" dependencies: inherits: "npm:^2.0.4" - readable-stream: "npm:^2.3.8" - safe-buffer: "npm:^5.2.1" - to-buffer: "npm:^1.2.1" - checksum: 10/f2100420521ec77736ebd9279f2c0b3ab2820136a2fa408ea36f3201d3f6984cda166806e6a0287f92adf179430bedfbdd74348ac351e24a3eff9f01a8c406b0 + readable-stream: "npm:^3.6.0" + safe-buffer: "npm:^5.2.0" + checksum: 10/26b7e97ac3de13cb23fc3145e7e3450b0530274a9562144fc2bf5c1e2983afd0e09ed7cc3b20974ba66039fad316db463da80eb452e7373e780cbee9a0d2f2dc languageName: node linkType: hard @@ -11158,13 +10770,6 @@ __metadata: languageName: node linkType: hard -"is-callable@npm:^1.2.7": - version: 1.2.7 - resolution: "is-callable@npm:1.2.7" - checksum: 10/48a9297fb92c99e9df48706241a189da362bff3003354aea4048bd5f7b2eb0d823cd16d0a383cece3d76166ba16d85d9659165ac6fcce1ac12e6c649d66dbdb9 - languageName: node - linkType: hard - "is-ci@npm:^2.0.0": version: 2.0.0 resolution: "is-ci@npm:2.0.0" @@ -11291,15 +10896,6 @@ __metadata: languageName: node linkType: hard -"is-typed-array@npm:^1.1.14": - version: 1.1.15 - resolution: "is-typed-array@npm:1.1.15" - dependencies: - which-typed-array: "npm:^1.1.16" - checksum: 10/e8cf60b9ea85667097a6ad68c209c9722cfe8c8edf04d6218366469e51944c5cc25bae45ffb845c23f811d262e4314d3b0168748eb16711aa34d12724cdf0735 - languageName: node - linkType: hard - "is-unicode-supported@npm:^0.1.0": version: 0.1.0 resolution: "is-unicode-supported@npm:0.1.0" @@ -11330,13 +10926,6 @@ __metadata: languageName: node linkType: hard -"isarray@npm:^2.0.5": - version: 2.0.5 - resolution: "isarray@npm:2.0.5" - checksum: 10/1d8bc7911e13bb9f105b1b3e0b396c787a9e63046af0b8fe0ab1414488ab06b2b099b87a2d8a9e31d21c9a6fad773c7fc8b257c4880f2d957274479d28ca3414 - languageName: node - linkType: hard - "isarray@npm:~1.0.0": version: 1.0.0 resolution: "isarray@npm:1.0.0" @@ -11358,13 +10947,6 @@ __metadata: languageName: node linkType: hard -"isexe@npm:^4.0.0": - version: 4.0.0 - resolution: "isexe@npm:4.0.0" - checksum: 10/2ead327ef596042ef9c9ec5f236b316acfaedb87f4bb61b3c3d574fb2e9c8a04b67305e04733bde52c24d9622fdebd3270aadb632adfbf9cadef88fe30f479e5 - languageName: node - linkType: hard - "isomorphic-fetch@npm:^3.0.0": version: 3.0.0 resolution: "isomorphic-fetch@npm:3.0.0" @@ -12346,13 +11928,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": - version: 11.3.3 - resolution: "lru-cache@npm:11.3.3" - checksum: 10/d45c1992232d0ab6ee5a9b93f62f43205ba5eeca51b2cfe6fa40a6aeb91b3cb0a318b273ab29ab36b66f779d4111df514c01bb7613ca4d4028953de49ecb82a9 - languageName: node - linkType: hard - "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -12430,26 +12005,6 @@ __metadata: languageName: node linkType: hard -"make-fetch-happen@npm:^15.0.0": - version: 15.0.5 - resolution: "make-fetch-happen@npm:15.0.5" - dependencies: - "@gar/promise-retry": "npm:^1.0.0" - "@npmcli/agent": "npm:^4.0.0" - "@npmcli/redact": "npm:^4.0.0" - cacache: "npm:^20.0.1" - http-cache-semantics: "npm:^4.1.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^5.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^1.0.0" - proc-log: "npm:^6.0.0" - ssri: "npm:^13.0.0" - checksum: 10/d2649effb06c00cb2b266057cb1c8c1e99cfc8d1378e7d9c26cc8f00be41bc63d59b77a5576ed28f8105acc57fb16220b64217f8d3a6a066a594c004aa163afa - languageName: node - linkType: hard - "makeerror@npm:1.0.12": version: 1.0.12 resolution: "makeerror@npm:1.0.12" @@ -12661,15 +12216,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^10.2.2": - version: 10.2.5 - resolution: "minimatch@npm:10.2.5" - dependencies: - brace-expansion: "npm:^5.0.5" - checksum: 10/19e87a931aff60ee7b9d80f39f817b8bfc54f61f8356ee3549fbf636dbccacacfec8d803eac73293955c4527cd085247dfc064bce4a5e349f8f3b85e2bf5da0f - languageName: node - linkType: hard - "minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -12739,21 +12285,6 @@ __metadata: languageName: node linkType: hard -"minipass-fetch@npm:^5.0.0": - version: 5.0.2 - resolution: "minipass-fetch@npm:5.0.2" - dependencies: - iconv-lite: "npm:^0.7.2" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^2.0.0" - minizlib: "npm:^3.0.1" - dependenciesMeta: - iconv-lite: - optional: true - checksum: 10/4f3f65ea5b20a3a287765ebf21cc73e62031f754944272df2a3039296cc75a8fc2dc50b8a3c4f39ce3ac6e5cc583e8dc664d12c6ab98e0883d263e49f344bc86 - languageName: node - linkType: hard - "minipass-flush@npm:^1.0.5": version: 1.0.5 resolution: "minipass-flush@npm:1.0.5" @@ -12781,15 +12312,6 @@ __metadata: languageName: node linkType: hard -"minipass-sized@npm:^2.0.0": - version: 2.0.0 - resolution: "minipass-sized@npm:2.0.0" - dependencies: - minipass: "npm:^7.1.2" - checksum: 10/3b89adf64ca705662f77481e278eff5ec0a57aeffb5feba7cc8843722b1e7770efc880f2a17d1d4877b2d7bf227873cd46afb4da44c0fd18088b601ea50f96bb - languageName: node - linkType: hard - "minipass@npm:^3.0.0": version: 3.3.6 resolution: "minipass@npm:3.3.6" @@ -12806,10 +12328,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": - version: 7.1.3 - resolution: "minipass@npm:7.1.3" - checksum: 10/175e4d5e20980c3cd316ae82d2c031c42f6c746467d8b1905b51060a0ba4461441a0c25bb67c025fd9617f9a3873e152c7b543c6b5ac83a1846be8ade80dffd6 +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 languageName: node linkType: hard @@ -12823,12 +12345,12 @@ __metadata: languageName: node linkType: hard -"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": - version: 3.1.0 - resolution: "minizlib@npm:3.1.0" +"minizlib@npm:^3.0.1": + version: 3.0.2 + resolution: "minizlib@npm:3.0.2" dependencies: minipass: "npm:^7.1.2" - checksum: 10/f47365cc2cb7f078cbe7e046eb52655e2e7e97f8c0a9a674f4da60d94fb0624edfcec9b5db32e8ba5a99a5f036f595680ae6fe02a262beaa73026e505cc52f99 + checksum: 10/c075bed1594f68dcc8c35122333520112daefd4d070e5d0a228bd4cf5580e9eed3981b96c0ae1d62488e204e80fd27b2b9d0068ca9a5ef3993e9565faf63ca41 languageName: node linkType: hard @@ -12848,6 +12370,15 @@ __metadata: languageName: node linkType: hard +"mkdirp@npm:^3.0.1": + version: 3.0.1 + resolution: "mkdirp@npm:3.0.1" + bin: + mkdirp: dist/cjs/src/bin.js + checksum: 10/16fd79c28645759505914561e249b9a1f5fe3362279ad95487a4501e4467abeb714fd35b95307326b8fd03f3c7719065ef11a6f97b7285d7888306d1bd2232ba + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -12919,13 +12450,6 @@ __metadata: languageName: node linkType: hard -"negotiator@npm:^1.0.0": - version: 1.0.0 - resolution: "negotiator@npm:1.0.0" - checksum: 10/b5734e87295324fabf868e36fb97c84b7d7f3156ec5f4ee5bf6e488079c11054f818290fc33804cef7b1ee21f55eeb14caea83e7dafae6492a409b3e573153e5 - languageName: node - linkType: hard - "neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" @@ -12987,7 +12511,7 @@ __metadata: languageName: node linkType: hard -"node-gyp@npm:^10.0.0": +"node-gyp@npm:^10.0.0, node-gyp@npm:latest": version: 10.2.0 resolution: "node-gyp@npm:10.2.0" dependencies: @@ -13007,26 +12531,6 @@ __metadata: languageName: node linkType: hard -"node-gyp@npm:latest": - version: 12.2.0 - resolution: "node-gyp@npm:12.2.0" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^15.0.0" - nopt: "npm:^9.0.0" - proc-log: "npm:^6.0.0" - semver: "npm:^7.3.5" - tar: "npm:^7.5.4" - tinyglobby: "npm:^0.2.12" - which: "npm:^6.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10/4ebab5b77585a637315e969c2274b5520562473fe75de850639a580c2599652fb9f33959ec782ea45a2e149d8f04b548030f472eeeb3dbdf19a7f2ccbc30b908 - languageName: node - linkType: hard - "node-int64@npm:^0.4.0": version: 0.4.0 resolution: "node-int64@npm:0.4.0" @@ -13052,17 +12556,6 @@ __metadata: languageName: node linkType: hard -"nopt@npm:^9.0.0": - version: 9.0.0 - resolution: "nopt@npm:9.0.0" - dependencies: - abbrev: "npm:^4.0.0" - bin: - nopt: bin/nopt.js - checksum: 10/56a1ccd2ad711fb5115918e2c96828703cddbe12ba2c3bd00591758f6fa30e6f47dd905c59dbfcf9b773f3a293b45996609fb6789ae29d6bfcc3cf3a6f7d9fda - languageName: node - linkType: hard - "normalize-package-data@npm:^2.5.0": version: 2.5.0 resolution: "normalize-package-data@npm:2.5.0" @@ -13187,13 +12680,6 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": - version: 1.13.4 - resolution: "object-inspect@npm:1.13.4" - checksum: 10/aa13b1190ad3e366f6c83ad8a16ed37a19ed57d267385aa4bfdccda833d7b90465c057ff6c55d035a6b2e52c1a2295582b294217a0a3a1ae7abdd6877ef781fb - languageName: node - linkType: hard - "on-finished@npm:2.4.1": version: 2.4.1 resolution: "on-finished@npm:2.4.1" @@ -13391,13 +12877,6 @@ __metadata: languageName: node linkType: hard -"p-map@npm:^7.0.2": - version: 7.0.4 - resolution: "p-map@npm:7.0.4" - checksum: 10/ef48c3b2e488f31c693c9fcc0df0ef76518cf6426a495cf9486ebbb0fd7f31aef7f90e96f72e0070c0ff6e3177c9318f644b512e2c29e3feee8d7153fcb6782e - languageName: node - linkType: hard - "p-throttle@npm:^4.1.1": version: 4.1.1 resolution: "p-throttle@npm:4.1.1" @@ -13525,16 +13004,6 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^2.0.2": - version: 2.0.2 - resolution: "path-scurry@npm:2.0.2" - dependencies: - lru-cache: "npm:^11.0.0" - minipass: "npm:^7.1.2" - checksum: 10/2b4257422bcb870a4c2d205b3acdbb213a72f5e2250f61c80f79c9d014d010f82bdf8584441612c8e1fa4eb098678f5704a66fa8377d72646bad4be38e57a2c3 - languageName: node - linkType: hard - "path-to-regexp@npm:0.1.12": version: 0.1.12 resolution: "path-to-regexp@npm:0.1.12" @@ -13583,13 +13052,6 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^4.0.4": - version: 4.0.4 - resolution: "picomatch@npm:4.0.4" - checksum: 10/f6ef80a3590827ce20378ae110ac78209cc4f74d39236370f1780f957b7ee41c12acde0e4651b90f39983506fd2f5e449994716f516db2e9752924aff8de93ce - languageName: node - linkType: hard - "pify@npm:^5.0.0": version: 5.0.0 resolution: "pify@npm:5.0.0" @@ -13638,13 +13100,6 @@ __metadata: languageName: node linkType: hard -"possible-typed-array-names@npm:^1.0.0": - version: 1.1.0 - resolution: "possible-typed-array-names@npm:1.1.0" - checksum: 10/2f44137b8d3dd35f4a7ba7469eec1cd9cfbb46ec164b93a5bc1f4c3d68599c9910ee3b91da1d28b4560e9cc8414c3cd56fedc07259c67e52cc774476270d3302 - languageName: node - linkType: hard - "postcss@npm:^8.4.40": version: 8.4.41 resolution: "postcss@npm:8.4.41" @@ -13708,13 +13163,6 @@ __metadata: languageName: node linkType: hard -"proc-log@npm:^6.0.0": - version: 6.1.0 - resolution: "proc-log@npm:6.1.0" - checksum: 10/9033f30f168ed5a0991b773d0c50ff88384c4738e9a0a67d341de36bf7293771eed648ab6a0562f62276da12fde91f3bbfc75ffff6e71ad49aafd74fc646be66 - languageName: node - linkType: hard - "process-nextick-args@npm:~2.0.0": version: 2.0.1 resolution: "process-nextick-args@npm:2.0.1" @@ -13838,7 +13286,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.13.0": +"qs@npm:6.13.0, qs@npm:^6.11.2": version: 6.13.0 resolution: "qs@npm:6.13.0" dependencies: @@ -13847,15 +13295,6 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.11.2": - version: 6.15.1 - resolution: "qs@npm:6.15.1" - dependencies: - side-channel: "npm:^1.1.0" - checksum: 10/ec10b9957446b3f4a38000940f6374720b4e2985209b89df197066038c951472ea24cd98d6bc6df73a0cbec75bc056f638032e3fb447345017ff7e0f0a2693ac - languageName: node - linkType: hard - "querystringify@npm:^2.1.1": version: 2.2.0 resolution: "querystringify@npm:2.2.0" @@ -13960,7 +13399,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.2, readable-stream@npm:^2.3.8": +"readable-stream@npm:^2.0.2": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -14256,7 +13695,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 @@ -14472,41 +13911,6 @@ __metadata: languageName: node linkType: hard -"side-channel-list@npm:^1.0.0": - version: 1.0.1 - resolution: "side-channel-list@npm:1.0.1" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.4" - checksum: 10/3499671cd52adaee739eac1e14d07530b8e3530192741aeb05e7fe4ad1b51d1368ceea2cd3c21b0f62b05410a5c70a7c4d997ba4b143303ef73d0c65dfd1c252 - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10/5771861f77feefe44f6195ed077a9e4f389acc188f895f570d56445e251b861754b547ea9ef73ecee4e01fdada6568bfe9020d2ec2dfc5571e9fa1bbc4a10615 - languageName: node - linkType: hard - -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10/a815c89bc78c5723c714ea1a77c938377ea710af20d4fb886d362b0d1f8ac73a17816a5f6640f354017d7e292a43da9c5e876c22145bac00b76cfb3468001736 - languageName: node - linkType: hard - "side-channel@npm:^1.0.6": version: 1.0.6 resolution: "side-channel@npm:1.0.6" @@ -14519,19 +13923,6 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10/7d53b9db292c6262f326b6ff3bc1611db84ece36c2c7dc0e937954c13c73185b0406c56589e2bb8d071d6fee468e14c39fb5d203ee39be66b7b8174f179afaba - languageName: node - linkType: hard - "signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -14716,15 +14107,6 @@ __metadata: languageName: node linkType: hard -"ssri@npm:^13.0.0": - version: 13.0.1 - resolution: "ssri@npm:13.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/ae560d0378d074006a71b06af71bfbe84a3fe1ac6e16c1f07575f69e670d40170507fe52b21bcc23399429bc6a15f4bc3ea8d9bc88e9dfd7e87de564e6da6a72 - languageName: node - linkType: hard - "stable-hash@npm:^0.0.4": version: 0.0.4 resolution: "stable-hash@npm:0.0.4" @@ -14943,13 +14325,6 @@ __metadata: languageName: node linkType: hard -"tapable@npm:^2.3.0": - version: 2.3.2 - resolution: "tapable@npm:2.3.2" - checksum: 10/fd3affe2e34efb3970883f934b1828f10b48dffb1eb71a52b7f955bfdd88bf80e94ec388704d95334f72ddf77e34d813b19e1f4bf56897d20252fa025d44bede - languageName: node - linkType: hard - "tar-stream@npm:^3.1.7": version: 3.1.7 resolution: "tar-stream@npm:3.1.7" @@ -14975,16 +14350,17 @@ __metadata: languageName: node linkType: hard -"tar@npm:^7.4.3, tar@npm:^7.5.4": - version: 7.5.13 - resolution: "tar@npm:7.5.13" +"tar@npm:^7.4.3": + version: 7.4.3 + resolution: "tar@npm:7.4.3" dependencies: "@isaacs/fs-minipass": "npm:^4.0.0" chownr: "npm:^3.0.0" minipass: "npm:^7.1.2" - minizlib: "npm:^3.1.0" + minizlib: "npm:^3.0.1" + mkdirp: "npm:^3.0.1" yallist: "npm:^5.0.0" - checksum: 10/2bc2b6f0349038a6621dbba1c4522d45752d5071b2994692257113c2050cd23fafc30308f820e5f8ad6fda3f7d7f92adc9a432aa733daa04c42af2061c021c3f + checksum: 10/12a2a4fc6dee23e07cc47f1aeb3a14a1afd3f16397e1350036a8f4cdfee8dcac7ef5978337a4e7b2ac2c27a9a6d46388fc2088ea7c80cb6878c814b1425f8ecf languageName: node linkType: hard @@ -15008,16 +14384,6 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.12": - version: 0.2.16 - resolution: "tinyglobby@npm:0.2.16" - dependencies: - fdir: "npm:^6.5.0" - picomatch: "npm:^4.0.4" - checksum: 10/5c2c41b572ada38449e7c86a5fe034f204a1dbba577225a761a14f29f48dc3f2fc0d81a6c56fcc67c5a742cc3aa9fb5e2ca18dbf22b610b0bc0e549b34d5a0f8 - languageName: node - linkType: hard - "tinyglobby@npm:^0.2.15": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" @@ -15042,17 +14408,6 @@ __metadata: languageName: node linkType: hard -"to-buffer@npm:^1.2.1": - version: 1.2.2 - resolution: "to-buffer@npm:1.2.2" - dependencies: - isarray: "npm:^2.0.5" - safe-buffer: "npm:^5.2.1" - typed-array-buffer: "npm:^1.0.3" - checksum: 10/69d806c20524ff1e4c44d49276bc96ff282dcae484780a3974e275dabeb75651ea430b074a2a4023701e63b3e1d87811cd82c0972f35280fe5461710e4872aba - languageName: node - linkType: hard - "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -15113,15 +14468,6 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^2.5.0": - version: 2.5.0 - resolution: "ts-api-utils@npm:2.5.0" - peerDependencies: - typescript: ">=4.8.4" - checksum: 10/d5f1936f5618c6ab6942a97b78802217540ced00e7501862ae1f578d9a3aa189fc06050e64cb8951d21f7088e5fd35f53d2bf0d0370a883861c7b05e993ebc44 - languageName: node - linkType: hard - "ts-jest@npm:^29.2.5": version: 29.4.6 resolution: "ts-jest@npm:29.4.6" @@ -15277,17 +14623,6 @@ __metadata: languageName: node linkType: hard -"typed-array-buffer@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-buffer@npm:1.0.3" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-typed-array: "npm:^1.1.14" - checksum: 10/3fb91f0735fb413b2bbaaca9fabe7b8fc14a3fa5a5a7546bab8a57e755be0e3788d893195ad9c2b842620592de0e68d4c077d4c2c41f04ec25b8b5bb82fa9a80 - languageName: node - linkType: hard - "typedarray@npm:^0.0.6": version: 0.0.6 resolution: "typedarray@npm:0.0.6" @@ -15380,13 +14715,6 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~7.19.0": - version: 7.19.2 - resolution: "undici-types@npm:7.19.2" - checksum: 10/05c34c63444c8caca7137f122b29ed50c1d7d05d1e0b2337f423575d3264054c4a0139e47e82e65723d09b97fcad6d8b0223b3550430a9006cc00e72a1e035bf - languageName: node - linkType: hard - "unique-filename@npm:^3.0.0": version: 3.0.0 resolution: "unique-filename@npm:3.0.0" @@ -15732,21 +15060,6 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.16": - version: 1.1.20 - resolution: "which-typed-array@npm:1.1.20" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - for-each: "npm:^0.3.5" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - checksum: 10/e56da3fc995d330ff012f682476f7883c16b12d36c6717c87c7ca23eb5a5ef957fa89115dacb389b11a9b4e99d5dbe2d12689b4d5d08c050b5aed0eae385b840 - languageName: node - linkType: hard - "which@npm:^1.2.14": version: 1.3.1 resolution: "which@npm:1.3.1" @@ -15791,17 +15104,6 @@ __metadata: languageName: node linkType: hard -"which@npm:^6.0.0": - version: 6.0.1 - resolution: "which@npm:6.0.1" - dependencies: - isexe: "npm:^4.0.0" - bin: - node-which: bin/which.js - checksum: 10/dbea77c7d3058bf6c78bf9659d2dce4d2b57d39a15b826b2af6ac2e5a219b99dc8a831b79fdbc453c0598adb4f3f84cf9c2491fd52beb9f5d2dececcad117f68 - languageName: node - linkType: hard - "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" From a820fad07fd067e7f33eba8b31da45b2510b3412 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Thu, 16 Apr 2026 19:29:14 +0100 Subject: [PATCH 15/19] chore: fix lint errors arising from changes to master --- packages/chomp-api-service/package.json | 22 ++++++++-------- .../src/chomp-api-service.test.ts | 25 ++++++++----------- yarn.lock | 4 +-- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/packages/chomp-api-service/package.json b/packages/chomp-api-service/package.json index b368bb1e0f..ccb790bb81 100644 --- a/packages/chomp-api-service/package.json +++ b/packages/chomp-api-service/package.json @@ -10,12 +10,17 @@ "bugs": { "url": "https://github.com/MetaMask/core/issues" }, + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/MetaMask/core.git" }, - "license": "MIT", + "files": [ + "dist/" + ], "sideEffects": false, + "main": "./dist/index.cjs", + "types": "./dist/index.d.cts", "exports": { ".": { "import": { @@ -29,11 +34,10 @@ }, "./package.json": "./package.json" }, - "main": "./dist/index.cjs", - "types": "./dist/index.d.cts", - "files": [ - "dist/" - ], + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, "scripts": { "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references", "build:all": "ts-bridge --project tsconfig.build.json --verbose --clean", @@ -55,7 +59,7 @@ "@tanstack/query-core": "^4.43.0" }, "devDependencies": { - "@metamask/auto-changelog": "^6.0.0", + "@metamask/auto-changelog": "^6.1.0", "@ts-bridge/cli": "^0.6.4", "@types/jest": "^29.5.14", "deepmerge": "^4.2.2", @@ -68,9 +72,5 @@ }, "engines": { "node": "^18.18 || >=20" - }, - "publishConfig": { - "access": "public", - "registry": "https://registry.npmjs.org/" } } diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index 0379971bb7..876ac388b9 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -464,19 +464,16 @@ describe('ChompApiService', () => { }, chains: { '0xa4b1': { - autoDepositDelegate: - '0xb4827a2a066cd2ef88560efdf063dd05c6c41cc7', + autoDepositDelegate: '0xb4827a2a066cd2ef88560efdf063dd05c6c41cc7', protocol: { vedaProtocol: { supportedTokens: [ { - tokenAddress: - '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', + tokenAddress: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', tokenDecimals: 6, }, ], - adapterAddress: - '0x4839b1BA117BdFFA986FCfA4E5fE6b9027b8f8B1', + adapterAddress: '0x4839b1BA117BdFFA986FCfA4E5fE6b9027b8f8B1', intentTypes: ['cash-deposit', 'cash-withdrawal'], }, }, @@ -516,9 +513,7 @@ describe('ChompApiService', () => { it('throws when a chainId is not a valid hex string', async () => { const { service } = createService(); - await expect( - service.getServiceDetails(['not-hex']), - ).rejects.toThrow( + await expect(service.getServiceDetails(['not-hex'])).rejects.toThrow( "Invalid chainId: expected a 0x-prefixed hex string, got 'not-hex'", ); }); @@ -531,9 +526,9 @@ describe('ChompApiService', () => { .reply(400); const { service } = createService(); - await expect( - service.getServiceDetails(['0xa4b1']), - ).rejects.toThrow("GET /v1/chomp failed with status '400'"); + await expect(service.getServiceDetails(['0xa4b1'])).rejects.toThrow( + "GET /v1/chomp failed with status '400'", + ); }); it('throws on malformed response', async () => { @@ -543,9 +538,9 @@ describe('ChompApiService', () => { .reply(200, JSON.stringify({ bad: 'data' })); const { service } = createService(); - await expect( - service.getServiceDetails(['0xa4b1']), - ).rejects.toThrow('At path: auth -- Expected an object'); + await expect(service.getServiceDetails(['0xa4b1'])).rejects.toThrow( + 'At path: auth -- Expected an object', + ); }); }); }); diff --git a/yarn.lock b/yarn.lock index b87a0e4ee8..6e0e6c4cd8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2920,7 +2920,7 @@ __metadata: languageName: node linkType: hard -"@metamask/auto-changelog@npm:^6.0.0, @metamask/auto-changelog@npm:^6.1.0": +"@metamask/auto-changelog@npm:^6.1.0": version: 6.1.0 resolution: "@metamask/auto-changelog@npm:6.1.0" dependencies: @@ -3123,7 +3123,7 @@ __metadata: version: 0.0.0-use.local resolution: "@metamask/chomp-api-service@workspace:packages/chomp-api-service" dependencies: - "@metamask/auto-changelog": "npm:^6.0.0" + "@metamask/auto-changelog": "npm:^6.1.0" "@metamask/base-data-service": "npm:^0.1.1" "@metamask/controller-utils": "npm:^11.20.0" "@metamask/messenger": "npm:^1.1.1" From 06ff793d531634f404ea419cc3834721399bdba0 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Fri, 17 Apr 2026 10:27:05 +0100 Subject: [PATCH 16/19] chore: remove duplicated hex validation --- .../src/chomp-api-service.test.ts | 2 +- .../src/chomp-api-service.ts | 21 +++++++------------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index 876ac388b9..33dfae0827 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -406,7 +406,7 @@ describe('ChompApiService', () => { const { service } = createService(); await expect(service.getIntentsByAddress('0xabc')).rejects.toThrow( - 'At path: 0.account -- Expected a value of type `Hex string`', + 'At path: 0.account -- Expected a string, but received: undefined', ); }); }); diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index deb0e4ad4e..64c0c73cd2 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -11,7 +11,6 @@ import { array, boolean, create, - define, enums, literal, number, @@ -20,7 +19,7 @@ import { string, type, } from '@metamask/superstruct'; -import { isStrictHexString } from '@metamask/utils'; +import { isStrictHexString, StrictHexStruct } from '@metamask/utils'; import type { QueryClientConfig } from '@tanstack/query-core'; import type { ChompApiServiceMethodActions } from './chomp-api-service-method-action-types'; @@ -122,10 +121,6 @@ export type ChompApiServiceMessenger = Messenger< // === RESPONSE VALIDATION === -const HexStringStruct = define('Hex string', (value) => - isStrictHexString(value), -); - const AssociateAddressResponseStruct = type({ profileId: string(), address: string(), @@ -148,9 +143,9 @@ const SendIntentResponseArrayStruct = array( type({ delegationHash: string(), metadata: type({ - allowance: HexStringStruct, + allowance: StrictHexStruct, tokenSymbol: string(), - tokenAddress: HexStringStruct, + tokenAddress: StrictHexStruct, type: enums(['cash-deposit', 'cash-withdrawal']), }), createdAt: string(), @@ -159,13 +154,13 @@ const SendIntentResponseArrayStruct = array( const IntentEntryArrayStruct = array( type({ - account: HexStringStruct, - delegationHash: HexStringStruct, - chainId: HexStringStruct, + account: StrictHexStruct, + delegationHash: StrictHexStruct, + chainId: StrictHexStruct, status: enums(['active', 'revoked']), metadata: type({ - allowance: HexStringStruct, - tokenAddress: HexStringStruct, + allowance: StrictHexStruct, + tokenAddress: StrictHexStruct, tokenSymbol: string(), type: enums(['deposit', 'withdraw']), }), From 79f5d6834d7e3381a1896b5804d2529a73226117 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Fri, 17 Apr 2026 13:27:45 +0100 Subject: [PATCH 17/19] chore: use strict hex instead of string when appropriate --- .../chomp-api-service-method-action-types.ts | 2 +- .../src/chomp-api-service.test.ts | 62 ++++++------------- .../src/chomp-api-service.ts | 33 ++++------ packages/chomp-api-service/src/types.ts | 26 ++++---- 4 files changed, 47 insertions(+), 76 deletions(-) diff --git a/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts b/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts index 4d81b15a5a..7b878bd16a 100644 --- a/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts +++ b/packages/chomp-api-service/src/chomp-api-service-method-action-types.ts @@ -54,7 +54,7 @@ export type ChompApiServiceGetIntentsByAddressAction = { }; /** - * Creates a withdrawal for card spend flows. + * Submits a withdrawal request via POST /v1/withdrawal */ export type ChompApiServiceCreateWithdrawalAction = { type: `ChompApiService:createWithdrawal`; diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index 33dfae0827..4a51486681 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -15,13 +15,15 @@ const MOCK_TOKEN = 'mock-jwt-token'; describe('ChompApiService', () => { describe('associateAddress', () => { + const associateRequest = { + signature: '0x123' as const, + timestamp: '2026-01-01T00:00:00Z', + address: '0xabc' as const, + }; + it('sends a POST with auth headers and returns the response on 201', async () => { nock(BASE_URL) - .post('/v1/auth/address', { - signature: '0x123', - timestamp: '2026-01-01T00:00:00Z', - address: '0xabc', - }) + .post('/v1/auth/address', associateRequest) .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) .matchHeader('Content-Type', 'application/json') .reply(201, { @@ -33,11 +35,7 @@ describe('ChompApiService', () => { const result = await rootMessenger.call( 'ChompApiService:associateAddress', - { - signature: '0x123', - timestamp: '2026-01-01T00:00:00Z', - address: '0xabc', - }, + associateRequest, ); expect(result).toStrictEqual({ @@ -55,11 +53,7 @@ describe('ChompApiService', () => { }); const { service } = createService(); - const result = await service.associateAddress({ - signature: '0x123', - timestamp: '2026-01-01T00:00:00Z', - address: '0xabc', - }); + const result = await service.associateAddress(associateRequest); expect(result).toStrictEqual({ profileId: 'p1', @@ -75,13 +69,9 @@ describe('ChompApiService', () => { .reply(500); const { service } = createService(); - await expect( - service.associateAddress({ - signature: '0x123', - timestamp: '2026-01-01T00:00:00Z', - address: '0xabc', - }), - ).rejects.toThrow("POST /v1/auth/address failed with status '500'"); + await expect(service.associateAddress(associateRequest)).rejects.toThrow( + "POST /v1/auth/address failed with status '500'", + ); }); it('throws on malformed response', async () => { @@ -90,23 +80,19 @@ describe('ChompApiService', () => { .reply(201, JSON.stringify({ missing: 'fields' })); const { service } = createService(); - await expect( - service.associateAddress({ - signature: '0x123', - timestamp: '2026-01-01T00:00:00Z', - address: '0xabc', - }), - ).rejects.toThrow('At path: profileId -- Expected a string'); + await expect(service.associateAddress(associateRequest)).rejects.toThrow( + 'At path: profileId -- Expected a string', + ); }); }); describe('createUpgrade', () => { const upgradeRequest = { - r: '0x1', - s: '0x2', + r: '0x1' as const, + s: '0x2' as const, v: 27, yParity: 0, - address: '0xabc', + address: '0xabc' as const, chainId: '1', nonce: '0', }; @@ -228,7 +214,7 @@ describe('ChompApiService', () => { nock(BASE_URL) .post('/v1/intent/verify-delegation', delegationRequest) .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) - .reply(200, { valid: true, delegationHash: '0xhash123' }); + .reply(200, { valid: true, delegationHash: '0xabc123' }); const { rootMessenger } = createService(); const result = await rootMessenger.call( @@ -238,7 +224,7 @@ describe('ChompApiService', () => { expect(result).toStrictEqual({ valid: true, - delegationHash: '0xhash123', + delegationHash: '0xabc123', }); }); @@ -510,14 +496,6 @@ describe('ChompApiService', () => { expect(result).toStrictEqual(serviceDetailsResponse); }); - it('throws when a chainId is not a valid hex string', async () => { - const { service } = createService(); - - await expect(service.getServiceDetails(['not-hex'])).rejects.toThrow( - "Invalid chainId: expected a 0x-prefixed hex string, got 'not-hex'", - ); - }); - it('throws on non-OK status', async () => { nock(BASE_URL) .get('/v1/chomp') diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index 64c0c73cd2..fffc6f82b9 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -19,7 +19,8 @@ import { string, type, } from '@metamask/superstruct'; -import { isStrictHexString, StrictHexStruct } from '@metamask/utils'; +import type { Hex } from '@metamask/utils'; +import { StrictHexStruct } from '@metamask/utils'; import type { QueryClientConfig } from '@tanstack/query-core'; import type { ChompApiServiceMethodActions } from './chomp-api-service-method-action-types'; @@ -123,25 +124,25 @@ export type ChompApiServiceMessenger = Messenger< const AssociateAddressResponseStruct = type({ profileId: string(), - address: string(), + address: StrictHexStruct, status: string(), }); const UpgradeResponseStruct = type({ - signerAddress: string(), + signerAddress: StrictHexStruct, status: string(), createdAt: string(), }); const VerifyDelegationResponseStruct = type({ valid: boolean(), - delegationHash: optional(string()), + delegationHash: optional(StrictHexStruct), errors: optional(array(string())), }); const SendIntentResponseArrayStruct = array( type({ - delegationHash: string(), + delegationHash: StrictHexStruct, metadata: type({ allowance: StrictHexStruct, tokenSymbol: string(), @@ -174,11 +175,11 @@ const CreateWithdrawalResponseStruct = type({ const ServiceDetailsProtocolStruct = type({ supportedTokens: array( type({ - tokenAddress: string(), + tokenAddress: StrictHexStruct, tokenDecimals: number(), }), ), - adapterAddress: string(), + adapterAddress: StrictHexStruct, intentTypes: array(enums(['cash-deposit', 'cash-withdrawal'])), }); @@ -187,9 +188,9 @@ const ServiceDetailsResponseStruct = type({ message: string(), }), chains: record( - string(), + StrictHexStruct, type({ - autoDepositDelegate: string(), + autoDepositDelegate: StrictHexStruct, protocol: record(string(), ServiceDetailsProtocolStruct), }), ), @@ -346,7 +347,7 @@ export class ChompApiService extends BaseDataService< * @param address - The address to look up. * @returns The upgrade record, or null if not found. */ - async getUpgrade(address: string): Promise { + async getUpgrade(address: Hex): Promise { const jsonResponse = await this.fetchQuery({ queryKey: [`${this.name}:getUpgrade`, address], queryFn: async () => { @@ -464,7 +465,7 @@ export class ChompApiService extends BaseDataService< * @param address - The address to look up intents for. * @returns The array of intents for the address. */ - async getIntentsByAddress(address: string): Promise { + async getIntentsByAddress(address: Hex): Promise { const jsonResponse = await this.fetchQuery({ queryKey: [`${this.name}:getIntentsByAddress`, address], queryFn: async () => { @@ -535,15 +536,7 @@ export class ChompApiService extends BaseDataService< * details for. * @returns The service details for the requested chains. */ - async getServiceDetails(chainIds: string[]): Promise { - for (const chainId of chainIds) { - if (!isStrictHexString(chainId)) { - throw new Error( - `Invalid chainId: expected a 0x-prefixed hex string, got '${chainId}'`, - ); - } - } - + async getServiceDetails(chainIds: Hex[]): Promise { const jsonResponse = await this.fetchQuery({ queryKey: [`${this.name}:getServiceDetails`, chainIds], queryFn: async () => { diff --git a/packages/chomp-api-service/src/types.ts b/packages/chomp-api-service/src/types.ts index cf219af470..348363e029 100644 --- a/packages/chomp-api-service/src/types.ts +++ b/packages/chomp-api-service/src/types.ts @@ -20,17 +20,17 @@ export type SignedDelegation = { // === REQUEST TYPES === export type AssociateAddressRequest = { - signature: string; + signature: Hex; timestamp: string; - address: string; + address: Hex; }; export type CreateUpgradeRequest = { - r: string; - s: string; + r: Hex; + s: Hex; v: number; yParity: number; - address: string; + address: Hex; chainId: string; nonce: string; }; @@ -65,19 +65,19 @@ export type CreateWithdrawalRequest = { export type AssociateAddressResponse = { profileId: string; - address: string; + address: Hex; status: string; }; export type UpgradeResponse = { - signerAddress: string; + signerAddress: Hex; status: string; createdAt: string; }; export type VerifyDelegationResponse = { valid: boolean; - delegationHash?: string; + delegationHash?: Hex; errors?: string[]; }; @@ -89,7 +89,7 @@ export type IntentMetadataResponse = { }; export type SendIntentResponse = { - delegationHash: string; + delegationHash: Hex; metadata: IntentMetadataResponse; createdAt: string; }; @@ -120,18 +120,18 @@ export type CreateWithdrawalResponse = { // === SERVICE DETAILS TYPES === export type ServiceDetailsSupportedToken = { - tokenAddress: string; + tokenAddress: Hex; tokenDecimals: number; }; export type ServiceDetailsProtocol = { supportedTokens: ServiceDetailsSupportedToken[]; - adapterAddress: string; + adapterAddress: Hex; intentTypes: ('cash-deposit' | 'cash-withdrawal')[]; }; export type ServiceDetailsChain = { - autoDepositDelegate: string; + autoDepositDelegate: Hex; protocol: Record; }; @@ -139,5 +139,5 @@ export type ServiceDetailsResponse = { auth: { message: string; }; - chains: Record; + chains: Record; }; From cb725d5d79a76942b34d845122a2f7e97ebd58b7 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Fri, 17 Apr 2026 15:20:18 +0100 Subject: [PATCH 18/19] chore: remove unneeded type casts --- packages/chomp-api-service/src/chomp-api-service.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index fffc6f82b9..78449f38a5 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -451,10 +451,7 @@ export class ChompApiService extends BaseDataService< }, }); - return create( - jsonResponse, - SendIntentResponseArrayStruct, - ) as SendIntentResponse[]; + return create(jsonResponse, SendIntentResponseArrayStruct); } /** @@ -486,7 +483,7 @@ export class ChompApiService extends BaseDataService< }, }); - return create(jsonResponse, IntentEntryArrayStruct) as IntentEntry[]; + return create(jsonResponse, IntentEntryArrayStruct); } /** @@ -556,9 +553,6 @@ export class ChompApiService extends BaseDataService< }, }); - return create( - jsonResponse, - ServiceDetailsResponseStruct, - ) as ServiceDetailsResponse; + return create(jsonResponse, ServiceDetailsResponseStruct); } } From 0b15c9f6beaf6b870ed74acd784c79dca44a1a21 Mon Sep 17 00:00:00 2001 From: John Whiles Date: Fri, 17 Apr 2026 15:29:55 +0100 Subject: [PATCH 19/19] feat: improve naming of types, and remove uneeded type casts --- .../src/chomp-api-service.test.ts | 54 +++++++++---------- .../src/chomp-api-service.ts | 44 +++++++-------- packages/chomp-api-service/src/index.ts | 12 ++--- packages/chomp-api-service/src/types.ts | 16 +++--- 4 files changed, 63 insertions(+), 63 deletions(-) diff --git a/packages/chomp-api-service/src/chomp-api-service.test.ts b/packages/chomp-api-service/src/chomp-api-service.test.ts index 4a51486681..6b538ef480 100644 --- a/packages/chomp-api-service/src/chomp-api-service.test.ts +++ b/packages/chomp-api-service/src/chomp-api-service.test.ts @@ -15,7 +15,7 @@ const MOCK_TOKEN = 'mock-jwt-token'; describe('ChompApiService', () => { describe('associateAddress', () => { - const associateRequest = { + const associateParams = { signature: '0x123' as const, timestamp: '2026-01-01T00:00:00Z', address: '0xabc' as const, @@ -23,7 +23,7 @@ describe('ChompApiService', () => { it('sends a POST with auth headers and returns the response on 201', async () => { nock(BASE_URL) - .post('/v1/auth/address', associateRequest) + .post('/v1/auth/address', associateParams) .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) .matchHeader('Content-Type', 'application/json') .reply(201, { @@ -35,7 +35,7 @@ describe('ChompApiService', () => { const result = await rootMessenger.call( 'ChompApiService:associateAddress', - associateRequest, + associateParams, ); expect(result).toStrictEqual({ @@ -53,7 +53,7 @@ describe('ChompApiService', () => { }); const { service } = createService(); - const result = await service.associateAddress(associateRequest); + const result = await service.associateAddress(associateParams); expect(result).toStrictEqual({ profileId: 'p1', @@ -69,7 +69,7 @@ describe('ChompApiService', () => { .reply(500); const { service } = createService(); - await expect(service.associateAddress(associateRequest)).rejects.toThrow( + await expect(service.associateAddress(associateParams)).rejects.toThrow( "POST /v1/auth/address failed with status '500'", ); }); @@ -80,14 +80,14 @@ describe('ChompApiService', () => { .reply(201, JSON.stringify({ missing: 'fields' })); const { service } = createService(); - await expect(service.associateAddress(associateRequest)).rejects.toThrow( + await expect(service.associateAddress(associateParams)).rejects.toThrow( 'At path: profileId -- Expected a string', ); }); }); describe('createUpgrade', () => { - const upgradeRequest = { + const upgradeParams = { r: '0x1' as const, s: '0x2' as const, v: 27, @@ -105,14 +105,14 @@ describe('ChompApiService', () => { it('sends a POST with auth headers and returns the response', async () => { nock(BASE_URL) - .post('/v1/account-upgrade', upgradeRequest) + .post('/v1/account-upgrade', upgradeParams) .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) .reply(200, upgradeResponse); const { rootMessenger } = createService(); const result = await rootMessenger.call( 'ChompApiService:createUpgrade', - upgradeRequest, + upgradeParams, ); expect(result).toStrictEqual(upgradeResponse); @@ -125,7 +125,7 @@ describe('ChompApiService', () => { .reply(500); const { service } = createService(); - await expect(service.createUpgrade(upgradeRequest)).rejects.toThrow( + await expect(service.createUpgrade(upgradeParams)).rejects.toThrow( "POST /v1/account-upgrade failed with status '500'", ); }); @@ -136,7 +136,7 @@ describe('ChompApiService', () => { .reply(200, JSON.stringify({ bad: 'data' })); const { service } = createService(); - await expect(service.createUpgrade(upgradeRequest)).rejects.toThrow( + await expect(service.createUpgrade(upgradeParams)).rejects.toThrow( 'At path: signerAddress -- Expected a string', ); }); @@ -198,7 +198,7 @@ describe('ChompApiService', () => { }); describe('verifyDelegation', () => { - const delegationRequest = { + const delegationParams = { signedDelegation: { delegate: '0x1' as const, delegator: '0x2' as const, @@ -212,14 +212,14 @@ describe('ChompApiService', () => { it('sends a POST with auth headers and returns the response', async () => { nock(BASE_URL) - .post('/v1/intent/verify-delegation', delegationRequest) + .post('/v1/intent/verify-delegation', delegationParams) .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) .reply(200, { valid: true, delegationHash: '0xabc123' }); const { rootMessenger } = createService(); const result = await rootMessenger.call( 'ChompApiService:verifyDelegation', - delegationRequest, + delegationParams, ); expect(result).toStrictEqual({ @@ -234,7 +234,7 @@ describe('ChompApiService', () => { .reply(200, { valid: false, errors: ['bad signature'] }); const { service } = createService(); - const result = await service.verifyDelegation(delegationRequest); + const result = await service.verifyDelegation(delegationParams); expect(result).toStrictEqual({ valid: false, @@ -249,7 +249,7 @@ describe('ChompApiService', () => { .reply(400); const { service } = createService(); - await expect(service.verifyDelegation(delegationRequest)).rejects.toThrow( + await expect(service.verifyDelegation(delegationParams)).rejects.toThrow( "POST /v1/intent/verify-delegation failed with status '400'", ); }); @@ -260,14 +260,14 @@ describe('ChompApiService', () => { .reply(200, JSON.stringify({ bad: 'data' })); const { service } = createService(); - await expect(service.verifyDelegation(delegationRequest)).rejects.toThrow( + await expect(service.verifyDelegation(delegationParams)).rejects.toThrow( 'At path: valid -- Expected a value of type `boolean`', ); }); }); describe('createIntents', () => { - const intentRequest = [ + const intentParams = [ { account: '0xabc' as const, delegationHash: '0xdef' as const, @@ -296,14 +296,14 @@ describe('ChompApiService', () => { it('sends a POST with auth headers and returns the response array', async () => { nock(BASE_URL) - .post('/v1/intent', intentRequest) + .post('/v1/intent', intentParams) .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) .reply(201, intentResponse); const { rootMessenger } = createService(); const result = await rootMessenger.call( 'ChompApiService:createIntents', - intentRequest, + intentParams, ); expect(result).toStrictEqual(intentResponse); @@ -316,7 +316,7 @@ describe('ChompApiService', () => { .reply(409); const { service } = createService(); - await expect(service.createIntents(intentRequest)).rejects.toThrow( + await expect(service.createIntents(intentParams)).rejects.toThrow( "POST /v1/intent failed with status '409'", ); }); @@ -327,7 +327,7 @@ describe('ChompApiService', () => { .reply(201, JSON.stringify([{ bad: 'data' }])); const { service } = createService(); - await expect(service.createIntents(intentRequest)).rejects.toThrow( + await expect(service.createIntents(intentParams)).rejects.toThrow( 'At path: 0.delegationHash -- Expected a string', ); }); @@ -398,7 +398,7 @@ describe('ChompApiService', () => { }); describe('createWithdrawal', () => { - const withdrawalRequest = { + const withdrawalParams = { chainId: '0x1' as const, amount: '1000000', account: '0xabc' as const, @@ -406,14 +406,14 @@ describe('ChompApiService', () => { it('sends a POST with auth headers and returns the response', async () => { nock(BASE_URL) - .post('/v1/withdrawal', withdrawalRequest) + .post('/v1/withdrawal', withdrawalParams) .matchHeader('Authorization', `Bearer ${MOCK_TOKEN}`) .reply(200, { success: true }); const { rootMessenger } = createService(); const result = await rootMessenger.call( 'ChompApiService:createWithdrawal', - withdrawalRequest, + withdrawalParams, ); expect(result).toStrictEqual({ success: true }); @@ -426,7 +426,7 @@ describe('ChompApiService', () => { .reply(400); const { service } = createService(); - await expect(service.createWithdrawal(withdrawalRequest)).rejects.toThrow( + await expect(service.createWithdrawal(withdrawalParams)).rejects.toThrow( "POST /v1/withdrawal failed with status '400'", ); }); @@ -437,7 +437,7 @@ describe('ChompApiService', () => { .reply(200, JSON.stringify({ success: false })); const { service } = createService(); - await expect(service.createWithdrawal(withdrawalRequest)).rejects.toThrow( + await expect(service.createWithdrawal(withdrawalParams)).rejects.toThrow( 'At path: success -- Expected the literal `true`', ); }); diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index 78449f38a5..082e7c74f1 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -25,17 +25,17 @@ import type { QueryClientConfig } from '@tanstack/query-core'; import type { ChompApiServiceMethodActions } from './chomp-api-service-method-action-types'; import type { - AssociateAddressRequest, + AssociateAddressParams, AssociateAddressResponse, - CreateUpgradeRequest, + CreateUpgradeParams, UpgradeResponse, - CreateWithdrawalRequest, + CreateWithdrawalParams, CreateWithdrawalResponse, IntentEntry, - SendIntentRequest, + SendIntentParams, SendIntentResponse, ServiceDetailsResponse, - VerifyDelegationRequest, + VerifyDelegationParams, VerifyDelegationResponse, } from './types'; @@ -266,15 +266,15 @@ export class ChompApiService extends BaseDataService< * * POST /v1/auth/address * - * @param request - The association request containing signature, timestamp, + * @param params - The association params containing signature, timestamp, * and address. * @returns The profile association result. Returns on both 201 and 409. */ async associateAddress( - request: AssociateAddressRequest, + params: AssociateAddressParams, ): Promise { const jsonResponse = await this.fetchQuery({ - queryKey: [`${this.name}:associateAddress`, request], + queryKey: [`${this.name}:associateAddress`, params], staleTime: 0, queryFn: async () => { const headers = await this.#authHeaders(); @@ -283,7 +283,7 @@ export class ChompApiService extends BaseDataService< { method: 'POST', headers, - body: JSON.stringify(request), + body: JSON.stringify(params), }, ); @@ -306,13 +306,13 @@ export class ChompApiService extends BaseDataService< * * POST /v1/account-upgrade * - * @param request - The upgrade request containing signature components and + * @param params - The upgrade params containing signature components and * chain details. * @returns The upgrade result. */ - async createUpgrade(request: CreateUpgradeRequest): Promise { + async createUpgrade(params: CreateUpgradeParams): Promise { const jsonResponse = await this.fetchQuery({ - queryKey: [`${this.name}:createUpgrade`, request], + queryKey: [`${this.name}:createUpgrade`, params], staleTime: 0, queryFn: async () => { const headers = await this.#authHeaders(); @@ -321,7 +321,7 @@ export class ChompApiService extends BaseDataService< { method: 'POST', headers, - body: JSON.stringify(request), + body: JSON.stringify(params), }, ); @@ -384,14 +384,14 @@ export class ChompApiService extends BaseDataService< * * POST /v1/intent/verify-delegation * - * @param request - The delegation verification request. + * @param params - The delegation verification params. * @returns The verification result including validity and optional errors. */ async verifyDelegation( - request: VerifyDelegationRequest, + params: VerifyDelegationParams, ): Promise { const jsonResponse = await this.fetchQuery({ - queryKey: [`${this.name}:verifyDelegation`, request], + queryKey: [`${this.name}:verifyDelegation`, params], staleTime: 0, queryFn: async () => { const headers = await this.#authHeaders(); @@ -400,7 +400,7 @@ export class ChompApiService extends BaseDataService< { method: 'POST', headers, - body: JSON.stringify(request), + body: JSON.stringify(params), }, ); @@ -427,7 +427,7 @@ export class ChompApiService extends BaseDataService< * @returns The array of intent responses. */ async createIntents( - intents: SendIntentRequest[], + intents: SendIntentParams[], ): Promise { const jsonResponse = await this.fetchQuery({ queryKey: [`${this.name}:createIntents`, intents], @@ -491,22 +491,22 @@ export class ChompApiService extends BaseDataService< * * POST /v1/withdrawal * - * @param request - The withdrawal request containing chainId, amount + * @param params - The withdrawal params containing chainId, amount * (decimal or hex string), and account address. * @returns The withdrawal result. */ async createWithdrawal( - request: CreateWithdrawalRequest, + params: CreateWithdrawalParams, ): Promise { const jsonResponse = await this.fetchQuery({ - queryKey: [`${this.name}:createWithdrawal`, request], + queryKey: [`${this.name}:createWithdrawal`, params], staleTime: 0, queryFn: async () => { const headers = await this.#authHeaders(); const response = await fetch(new URL('/v1/withdrawal', this.#baseUrl), { method: 'POST', headers, - body: JSON.stringify(request), + body: JSON.stringify(params), }); if (!response.ok) { diff --git a/packages/chomp-api-service/src/index.ts b/packages/chomp-api-service/src/index.ts index f7c4a7dbf9..74f087f17f 100644 --- a/packages/chomp-api-service/src/index.ts +++ b/packages/chomp-api-service/src/index.ts @@ -18,23 +18,23 @@ export type { ChompApiServiceGetServiceDetailsAction, } from './chomp-api-service-method-action-types'; export type { - AssociateAddressRequest, + AssociateAddressParams, AssociateAddressResponse, - CreateUpgradeRequest, - CreateWithdrawalRequest, + CreateUpgradeParams, + CreateWithdrawalParams, CreateWithdrawalResponse, DelegationCaveat, UpgradeResponse, IntentEntry, - IntentMetadataRequest, + IntentMetadataParams, IntentMetadataResponse, - SendIntentRequest, + SendIntentParams, SendIntentResponse, ServiceDetailsChain, ServiceDetailsProtocol, ServiceDetailsResponse, ServiceDetailsSupportedToken, SignedDelegation, - VerifyDelegationRequest, + VerifyDelegationParams, VerifyDelegationResponse, } from './types'; diff --git a/packages/chomp-api-service/src/types.ts b/packages/chomp-api-service/src/types.ts index 348363e029..56f47e1931 100644 --- a/packages/chomp-api-service/src/types.ts +++ b/packages/chomp-api-service/src/types.ts @@ -17,15 +17,15 @@ export type SignedDelegation = { signature: Hex; }; -// === REQUEST TYPES === +// === PARAMS TYPES === -export type AssociateAddressRequest = { +export type AssociateAddressParams = { signature: Hex; timestamp: string; address: Hex; }; -export type CreateUpgradeRequest = { +export type CreateUpgradeParams = { r: Hex; s: Hex; v: number; @@ -35,26 +35,26 @@ export type CreateUpgradeRequest = { nonce: string; }; -export type VerifyDelegationRequest = { +export type VerifyDelegationParams = { signedDelegation: SignedDelegation; chainId: Hex; }; -export type IntentMetadataRequest = { +export type IntentMetadataParams = { allowance: Hex; tokenSymbol: string; tokenAddress: Hex; type: 'cash-deposit' | 'cash-withdrawal'; }; -export type SendIntentRequest = { +export type SendIntentParams = { account: Hex; delegationHash: Hex; chainId: Hex; - metadata: IntentMetadataRequest; + metadata: IntentMetadataParams; }; -export type CreateWithdrawalRequest = { +export type CreateWithdrawalParams = { chainId: Hex; /** Decimal integer or 0x-prefixed hex string representing the amount. */ amount: string;