From d555b90a1ccb77c10cac941cdc1b08fcea970ee3 Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Tue, 10 Feb 2026 23:58:31 +0000 Subject: [PATCH 01/10] chore: add pre-commit configuration and CI --- .github/workflows/linter.yml | 17 +++++++++++++++++ .pre-commit-config.yaml | 31 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 .github/workflows/linter.yml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..d80b698 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,17 @@ +name: Lint + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + - uses: pre-commit/action@v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..0cd3c8d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,31 @@ +exclude: '^(\.github/|\.vscode/|node_modules/).*|CODE_OF_CONDUCT\.md|CHANGELOG\.md' + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + args: [--unsafe] + - id: check-json + - id: check-added-large-files + - id: detect-private-key + - id: check-shebang-scripts-are-executable + - id: check-executables-have-shebangs + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.14.13 + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 + hooks: + - id: prettier + files: \.(ts|tsx|js|jsx|json|md|yaml|yml|css|html)$ + - repo: https://github.com/codespell-project/codespell + rev: v2.4.1 + hooks: + - id: codespell + args: ["--skip", "*.lock,package-lock.json"] From deb707cd88e6a0181012a13c977473d1da138268 Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Wed, 11 Feb 2026 05:11:07 +0000 Subject: [PATCH 02/10] chore: add license headers to config files --- .github/workflows/linter.yml | 14 ++++++++++++++ .pre-commit-config.yaml | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index d80b698..63207bf 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,3 +1,17 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + name: Lint on: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0cd3c8d..8c2dd37 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,17 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + exclude: '^(\.github/|\.vscode/|node_modules/).*|CODE_OF_CONDUCT\.md|CHANGELOG\.md' repos: From 720a277450129d69eb18a950347f19b7d418401c Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Sun, 22 Feb 2026 17:55:08 +0000 Subject: [PATCH 03/10] chore: add technical terms to codespell ignore list --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c2dd37..8cb9bc6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,4 +42,4 @@ repos: rev: v2.4.1 hooks: - id: codespell - args: ["--skip", "*.lock,package-lock.json"] + args: ["--skip", "*.lock,package-lock.json", "-L", "mor,tok,fpan,dpan"] From aad935f05cee9b5fabf69837ecd42d25182a0a29 Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Sun, 8 Mar 2026 08:53:02 +0000 Subject: [PATCH 04/10] chore: move codespell ignore list to separate file --- .codespellignore | 4 ++++ .pre-commit-config.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .codespellignore diff --git a/.codespellignore b/.codespellignore new file mode 100644 index 0000000..4d75c60 --- /dev/null +++ b/.codespellignore @@ -0,0 +1,4 @@ +mor +tok +fpan +dpan diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8cb9bc6..d303089 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,4 +42,4 @@ repos: rev: v2.4.1 hooks: - id: codespell - args: ["--skip", "*.lock,package-lock.json", "-L", "mor,tok,fpan,dpan"] + args: ["--skip", "*.lock,package-lock.json", "-I", ".codespellignore"] From 1fda2b85ade1c4ff08037d0a73b0cfd34416f04f Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Tue, 17 Mar 2026 07:41:58 +0000 Subject: [PATCH 05/10] chore: align .prettierrc with main repo config --- .prettierrc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..fb0e95d --- /dev/null +++ b/.prettierrc @@ -0,0 +1,19 @@ +{ + "tabWidth": 2, + "useTabs": false, + "trailingComma": "es5", + "bracketSameLine": true, + "overrides": [ + { + "files": "*.md", + "options": { + "tabWidth": 4, + "useTabs": false, + "trailingComma": "es5", + "endOfLine": "lf", + "printWidth": 80, + "proseWrap": "always" + } + } + ] +} From 09024d2063be21dc3a10b4abe277e844f0077a46 Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Tue, 17 Mar 2026 07:44:06 +0000 Subject: [PATCH 06/10] chore: use minimal prettier config --- .prettierrc | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/.prettierrc b/.prettierrc index fb0e95d..b7df515 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,19 +1,7 @@ { "tabWidth": 2, "useTabs": false, - "trailingComma": "es5", - "bracketSameLine": true, - "overrides": [ - { - "files": "*.md", - "options": { - "tabWidth": 4, - "useTabs": false, - "trailingComma": "es5", - "endOfLine": "lf", - "printWidth": 80, - "proseWrap": "always" - } - } - ] + "trailingComma": "none", + "bracketSameLine": false, + "printWidth": 88 } From 9e6196e5f6bda7829d16310c37269c7bda19cb00 Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Tue, 17 Mar 2026 07:46:03 +0000 Subject: [PATCH 07/10] chore: align prettier config with existing code style --- .prettierrc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.prettierrc b/.prettierrc index b7df515..ab5a6b6 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,8 @@ { "tabWidth": 2, "useTabs": false, - "trailingComma": "none", + "singleQuote": false, + "trailingComma": "all", "bracketSameLine": false, - "printWidth": 88 + "printWidth": 80 } From f35190ae235f335dc292170a70da7310dbd0172b Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Tue, 17 Mar 2026 07:47:31 +0000 Subject: [PATCH 08/10] chore: use none for trailing comma --- .prettierrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierrc b/.prettierrc index ab5a6b6..c3c0dbd 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,7 +2,7 @@ "tabWidth": 2, "useTabs": false, "singleQuote": false, - "trailingComma": "all", + "trailingComma": "none", "bracketSameLine": false, "printWidth": 80 } From 9a62e5a99bc189275b9521d1ea12c222b520bc77 Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Tue, 17 Mar 2026 07:49:23 +0000 Subject: [PATCH 09/10] chore: use es5 for trailing comma --- .prettierrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierrc b/.prettierrc index c3c0dbd..a4388dd 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,7 +2,7 @@ "tabWidth": 2, "useTabs": false, "singleQuote": false, - "trailingComma": "none", + "trailingComma": "es5", "bracketSameLine": false, "printWidth": 80 } From 078bc3cc5af5594a121c8961e1196cbb4ce1f2a8 Mon Sep 17 00:00:00 2001 From: nearlyforget Date: Tue, 17 Mar 2026 07:52:51 +0000 Subject: [PATCH 10/10] style: format files with prettier --- a2a/chat-client/App.tsx | 32 +++++----- a2a/chat-client/components/Checkout.tsx | 2 +- a2a/chat-client/config.ts | 4 +- a2a/chat-client/index.tsx | 2 +- .../mocks/credentialProviderProxy.ts | 10 +-- a2a/docs/05-frontend.md | 6 +- rest/nodejs/src/api/checkout.ts | 62 +++++++++---------- rest/nodejs/src/api/order.ts | 2 +- rest/nodejs/src/data/inventory.ts | 2 +- rest/nodejs/src/data/products.ts | 2 +- rest/nodejs/src/data/transactions.ts | 22 +++---- rest/nodejs/src/index.ts | 22 +++---- rest/nodejs/src/models/extensions.ts | 6 +- rest/nodejs/src/utils/validation.ts | 6 +- 14 files changed, 89 insertions(+), 91 deletions(-) diff --git a/a2a/chat-client/App.tsx b/a2a/chat-client/App.tsx index c497344..0c5d681 100644 --- a/a2a/chat-client/App.tsx +++ b/a2a/chat-client/App.tsx @@ -36,7 +36,7 @@ type RequestPart = function createChatMessage( sender: Sender, text: string, - props: Partial = {}, + props: Partial = {} ): ChatMessage { return { id: crypto.randomUUID(), @@ -49,7 +49,7 @@ function createChatMessage( const initialMessage: ChatMessage = createChatMessage( Sender.MODEL, appConfig.defaultMessage, - { id: "initial" }, + { id: "initial" } ); /** @@ -58,7 +58,7 @@ const initialMessage: ChatMessage = createChatMessage( */ function App() { const [user_email, _setUserEmail] = useState( - "foo@example.com", + "foo@example.com" ); const [messages, setMessages] = useState([initialMessage]); const [isLoading, setIsLoading] = useState(false); @@ -96,7 +96,7 @@ function App() { if (!checkout || !checkout.payment || !checkout.payment.handlers) { const errorMessage = createChatMessage( Sender.MODEL, - "Sorry, I couldn't retrieve payment methods.", + "Sorry, I couldn't retrieve payment methods." ); setMessages((prev) => [...prev, errorMessage]); return; @@ -104,12 +104,12 @@ function App() { //find the handler with id "example_payment_provider" const handler = checkout.payment.handlers.find( - (handler: PaymentHandler) => handler.id === "example_payment_provider", + (handler: PaymentHandler) => handler.id === "example_payment_provider" ); if (!handler) { const errorMessage = createChatMessage( Sender.MODEL, - "Sorry, I couldn't find the supported payment handler.", + "Sorry, I couldn't find the supported payment handler." ); setMessages((prev) => [...prev, errorMessage]); return; @@ -119,7 +119,7 @@ function App() { const paymentResponse = await credentialProvider.current.getSupportedPaymentMethods( user_email, - handler.config, + handler.config ); const paymentMethods = paymentResponse.payment_method_aliases; @@ -131,7 +131,7 @@ function App() { console.error("Failed to resolve mandate:", error); const errorMessage = createChatMessage( Sender.MODEL, - "Sorry, I couldn't retrieve payment methods.", + "Sorry, I couldn't retrieve payment methods." ); setMessages((prev) => [...prev, errorMessage]); } @@ -145,7 +145,7 @@ function App() { const userActionMessage = createChatMessage( Sender.USER, `User selected payment method: ${selectedMethod}`, - { isUserAction: true }, + { isUserAction: true } ); setMessages((prev) => [...prev, userActionMessage]); @@ -157,7 +157,7 @@ function App() { const paymentInstrument = await credentialProvider.current.getPaymentToken( user_email, - selectedMethod, + selectedMethod ); if (!paymentInstrument || !paymentInstrument.credential) { @@ -172,7 +172,7 @@ function App() { console.error("Failed to process payment mandate:", error); const errorMessage = createChatMessage( Sender.MODEL, - "Sorry, I couldn't process the payment. Please try again.", + "Sorry, I couldn't process the payment. Please try again." ); setMessages((prev) => [...prev, errorMessage]); } @@ -183,7 +183,7 @@ function App() { const userActionMessage = createChatMessage( Sender.USER, `User confirmed payment.`, - { isUserAction: true }, + { isUserAction: true } ); // Let handleSendMessage manage the loading indicator setMessages((prev) => [ @@ -210,7 +210,7 @@ function App() { console.error("Error confirming payment:", error); const errorMessage = createChatMessage( Sender.MODEL, - "Sorry, there was an issue confirming your payment.", + "Sorry, there was an issue confirming your payment." ); // If handleSendMessage wasn't called, we might need to manually update state // In this case, we remove the loading indicator that handleSendMessage would have added @@ -221,7 +221,7 @@ function App() { const handleSendMessage = async ( messageContent: string | RequestPart[], - options?: { isUserAction?: boolean; headers?: Record }, + options?: { isUserAction?: boolean; headers?: Record } ) => { if (isLoading) return; @@ -231,7 +231,7 @@ function App() { ? "" : typeof messageContent === "string" ? messageContent - : "Sent complex data", + : "Sent complex data" ); if (userMessage.text) { // Only add if there's text @@ -366,7 +366,7 @@ function App() { console.error("Error sending message:", error); const errorMessage = createChatMessage( Sender.MODEL, - "Sorry, something went wrong. Please try again.", + "Sorry, something went wrong. Please try again." ); // Replace the placeholder with the error message setMessages((prev) => [...prev.slice(0, -1), errorMessage]); diff --git a/a2a/chat-client/components/Checkout.tsx b/a2a/chat-client/components/Checkout.tsx index d9e760e..0506adc 100644 --- a/a2a/chat-client/components/Checkout.tsx +++ b/a2a/chat-client/components/Checkout.tsx @@ -95,7 +95,7 @@ const CheckoutComponent: React.FC = ({

{formatCurrency( getItemTotal(lineItem).amount, - checkout.currency, + checkout.currency )}

diff --git a/a2a/chat-client/config.ts b/a2a/chat-client/config.ts index 56b99cb..f120d68 100644 --- a/a2a/chat-client/config.ts +++ b/a2a/chat-client/config.ts @@ -25,7 +25,7 @@ export class AppProperties { description: string, logoUrl: string, defaultMessage: string, - titleText: string, + titleText: string ) { this.name = name; this.description = description; @@ -40,5 +40,5 @@ export const appConfig = new AppProperties( "Your personal shopping assistant.", "/images/logo.jpg", "Hello, I am your Business Agent. How can I help you?", - "Shop with Business Agent", + "Shop with Business Agent" ); diff --git a/a2a/chat-client/index.tsx b/a2a/chat-client/index.tsx index 2faacbd..b291a66 100644 --- a/a2a/chat-client/index.tsx +++ b/a2a/chat-client/index.tsx @@ -26,5 +26,5 @@ const root = ReactDOM.createRoot(rootElement); root.render( - , + ); diff --git a/a2a/chat-client/mocks/credentialProviderProxy.ts b/a2a/chat-client/mocks/credentialProviderProxy.ts index 1e85a44..02d26d6 100644 --- a/a2a/chat-client/mocks/credentialProviderProxy.ts +++ b/a2a/chat-client/mocks/credentialProviderProxy.ts @@ -61,11 +61,11 @@ export class CredentialProviderProxy { async getSupportedPaymentMethods( user_email: string, // biome-ignore lint/suspicious/noExplicitAny: no specific type for config - config: any, + config: any ): Promise<{ payment_method_aliases: PaymentMethod[] }> { console.log( `CredentialProviderProxy: Simulating fetch for ${user_email} supported payment methods with config:`, - config, + config ); // Simulate network latency await new Promise((resolve) => setTimeout(resolve, 500)); @@ -80,17 +80,17 @@ export class CredentialProviderProxy { */ async getPaymentToken( user_email: string, - payment_method_id: string, + payment_method_id: string ): Promise { console.log( - `CredentialProviderProxy: Simulating fetch for payment token for user ${user_email} and method ${payment_method_id}`, + `CredentialProviderProxy: Simulating fetch for payment token for user ${user_email} and method ${payment_method_id}` ); // Simulate network latency await new Promise((resolve) => setTimeout(resolve, 500)); const randomId = crypto.randomUUID(); const payment_method = this._getMockPaymentMethods().payment_method_aliases.find( - (method) => method.id === payment_method_id, + (method) => method.id === payment_method_id ); if (!payment_method) { diff --git a/a2a/docs/05-frontend.md b/a2a/docs/05-frontend.md index 763f404..e28dad2 100644 --- a/a2a/docs/05-frontend.md +++ b/a2a/docs/05-frontend.md @@ -179,7 +179,7 @@ class CredentialProviderProxy { // Returns mock payment methods (wrapped in object) async getSupportedPaymentMethods( user_email: string, - config: any, + config: any ): Promise<{ payment_method_aliases: PaymentMethod[] }> { return { payment_method_aliases: [ @@ -206,7 +206,7 @@ class CredentialProviderProxy { // Converts method to PaymentInstrument with token async getPaymentToken( user_email: string, - payment_method_id: string, + payment_method_id: string ): Promise { return { ...payment_method, @@ -243,6 +243,6 @@ export const appConfig = new AppProperties( "Your personal shopping assistant.", "/images/logo.jpg", "Hello, I am your Business Agent...", - "Shop with Business Agent", + "Shop with Business Agent" ); ``` diff --git a/rest/nodejs/src/api/checkout.ts b/rest/nodejs/src/api/checkout.ts index 840b3d0..caa7aa8 100644 --- a/rest/nodejs/src/api/checkout.ts +++ b/rest/nodejs/src/api/checkout.ts @@ -72,7 +72,7 @@ export class CheckoutService { } private async parseAgentProfile( - ucpAgentHeader: string | undefined, + ucpAgentHeader: string | undefined ): Promise<{ webhook_url?: string } | undefined> { if (!ucpAgentHeader) return undefined; @@ -108,7 +108,7 @@ export class CheckoutService { if (profileData && profileData.ucp && profileData.ucp.capabilities) { const orderCap = profileData.ucp.capabilities.find( - (c) => c.name === "dev.ucp.shopping.order", + (c) => c.name === "dev.ucp.shopping.order" ); if (orderCap && orderCap.config && orderCap.config.webhook_url) { return { webhook_url: orderCap.config.webhook_url }; @@ -122,7 +122,7 @@ export class CheckoutService { private async notifyWebhook( checkout: ExtendedCheckoutResponse, - eventType: string, + eventType: string ): Promise { if (!checkout.platform?.webhook_url) { return; @@ -153,7 +153,7 @@ export class CheckoutService { private constructFulfillmentResponse( reqFulfillment: FulfillmentRequest | undefined, lineItems: LineItemResponse[], - existingFulfillment?: FulfillmentResponse, + existingFulfillment?: FulfillmentResponse ): FulfillmentResponse | undefined { if (!reqFulfillment) { return undefined; @@ -196,13 +196,13 @@ export class CheckoutService { (d): FulfillmentDestinationResponse => ({ ...d, id: d.id || `dest_${uuidv4()}`, - }), + }) ); } else if (existingFulfillment && existingFulfillment.methods) { // Default to shipping if type is not provided in request const targetType = m.type || "shipping"; const existingMethod = existingFulfillment.methods.find( - (em) => em.type === targetType, + (em) => em.type === targetType ); if (existingMethod && existingMethod.destinations) { destinations = existingMethod.destinations; @@ -263,7 +263,7 @@ export class CheckoutService { ) { const dest = method.destinations.find( (d: FulfillmentDestinationResponse) => - d.id === method.selected_destination_id, + d.id === method.selected_destination_id ); // Extract country from flat field or nested address @@ -292,7 +292,7 @@ export class CheckoutService { total: 1500, subtotal: 1500, tax: 0, - }, + } ); } else { options.push({ @@ -326,7 +326,7 @@ export class CheckoutService { if (group.selected_option_id && group.options) { const selected = group.options.find( (o: FulfillmentOptionResponse) => - o.id === group.selected_option_id, + o.id === group.selected_option_id ); if (selected) { grandTotal += selected.total; @@ -389,7 +389,7 @@ export class CheckoutService { if (record.request_hash !== requestHash) { return c.json( { detail: "Idempotency key reused with different parameters" }, - 409, + 409 ); } return c.json(JSON.parse(record.response_body), 201); @@ -437,7 +437,7 @@ export class CheckoutService { const fulfillment = this.constructFulfillmentResponse( _reqFulfillment, - lineItems, + lineItems ); // Construct authoritative checkout @@ -481,7 +481,7 @@ export class CheckoutService { idempotencyKey, requestHash, 201, - JSON.stringify(checkout), + JSON.stringify(checkout) ); } @@ -489,7 +489,7 @@ export class CheckoutService { } catch (e: unknown) { return c.json( { detail: e instanceof Error ? e.message : String(e) }, - 400, + 400 ); } }; @@ -521,7 +521,7 @@ export class CheckoutService { if (record.request_hash !== requestHash) { return c.json( { detail: "Idempotency key reused with different parameters" }, - 409, + 409 ); } return c.json(JSON.parse(record.response_body), 200); @@ -542,7 +542,7 @@ export class CheckoutService { ) { return c.json( { detail: `Cannot update a ${existing.status} checkout session` }, - 409, + 409 ); } @@ -598,7 +598,7 @@ export class CheckoutService { existing.fulfillment = this.constructFulfillmentResponse( updateRequest.fulfillment, existing.line_items, - existing.fulfillment, + existing.fulfillment ); } @@ -614,7 +614,7 @@ export class CheckoutService { idempotencyKey, requestHash, 200, - JSON.stringify(existing), + JSON.stringify(existing) ); } @@ -622,7 +622,7 @@ export class CheckoutService { } catch (e: unknown) { return c.json( { detail: e instanceof Error ? e.message : String(e) }, - 400, + 400 ); } }; @@ -641,7 +641,7 @@ export class CheckoutService { if (record.request_hash !== requestHash) { return c.json( { detail: "Idempotency key reused with different parameters" }, - 409, + 409 ); } return c.json(JSON.parse(record.response_body), 200); @@ -693,12 +693,12 @@ export class CheckoutService { } else if (token === "fail_token") { return c.json( { detail: "Payment Failed: Insufficient Funds (Mock)" }, - 402, + 402 ); } else if (token === "fraud_token") { return c.json( { detail: "Payment Failed: Fraud Detected (Mock)" }, - 403, + 403 ); } else { return c.json({ detail: `Unknown mock token: ${token}` }, 400); @@ -712,7 +712,7 @@ export class CheckoutService { } else { return c.json( { detail: `Unsupported payment handler: ${handlerId}` }, - 400, + 400 ); } } @@ -733,7 +733,7 @@ export class CheckoutService { } return c.json( { detail: `Item ${line.item.id} is out of stock` }, - 409, + 409 ); } reservedItems.push({ id: line.item.id, qty: line.quantity }); @@ -756,7 +756,7 @@ export class CheckoutService { if (method.selected_destination_id && method.destinations) { const dest = method.destinations.find( (d: FulfillmentDestinationResponse) => - d.id === method.selected_destination_id, + d.id === method.selected_destination_id ); if (dest) { if (dest.address) { @@ -774,7 +774,7 @@ export class CheckoutService { if (group.selected_option_id && group.options) { const selected = group.options.find( (opt: FulfillmentOptionResponse) => - opt.id === group.selected_option_id, + opt.id === group.selected_option_id ); if (selected) { const expectationId = `exp_${uuidv4()}`; @@ -783,7 +783,7 @@ export class CheckoutService { if (group.line_item_ids) { for (const liId of group.line_item_ids) { const checkoutLineItem = checkout.line_items.find( - (li) => li.id === liId, + (li) => li.id === liId ); if (checkoutLineItem) { expLineItems.push({ @@ -821,7 +821,7 @@ export class CheckoutService { status: "processing", parent_id: li.parent_id, }; - }, + } ); const order: Order = { @@ -852,7 +852,7 @@ export class CheckoutService { idempotencyKey, requestHash, 200, - JSON.stringify(checkout), + JSON.stringify(checkout) ); } @@ -876,7 +876,7 @@ export class CheckoutService { if (record.request_hash !== requestHash) { return c.json( { detail: "Idempotency key reused with different parameters" }, - 409, + 409 ); } return c.json(JSON.parse(record.response_body), 200); @@ -896,7 +896,7 @@ export class CheckoutService { ) { return c.json( { detail: `Cannot cancel a ${checkout.status} checkout session` }, - 409, + 409 ); } @@ -908,7 +908,7 @@ export class CheckoutService { idempotencyKey, requestHash, 200, - JSON.stringify(checkout), + JSON.stringify(checkout) ); } diff --git a/rest/nodejs/src/api/order.ts b/rest/nodejs/src/api/order.ts index a65f25c..aa7b5b3 100644 --- a/rest/nodejs/src/api/order.ts +++ b/rest/nodejs/src/api/order.ts @@ -28,7 +28,7 @@ export class OrderService { "PUT", `/orders/${id}`, updateRequest.checkout_id, - updateRequest, + updateRequest ); const existing = getOrder(id); diff --git a/rest/nodejs/src/data/inventory.ts b/rest/nodejs/src/data/inventory.ts index d23d373..63574fc 100644 --- a/rest/nodejs/src/data/inventory.ts +++ b/rest/nodejs/src/data/inventory.ts @@ -9,7 +9,7 @@ import { getTransactionsDb } from "./db"; export function getInventory(productId: string): number | undefined { const db = getTransactionsDb(); const stmt = db.prepare( - "SELECT quantity FROM inventory WHERE product_id = ?", + "SELECT quantity FROM inventory WHERE product_id = ?" ); const result = stmt.get(productId) as { quantity: number } | undefined; return result?.quantity; diff --git a/rest/nodejs/src/data/products.ts b/rest/nodejs/src/data/products.ts index f6c3623..88cbe14 100644 --- a/rest/nodejs/src/data/products.ts +++ b/rest/nodejs/src/data/products.ts @@ -19,7 +19,7 @@ export interface Product { export function getProduct(productId: string): Product | undefined { const db = getProductsDb(); const stmt = db.prepare( - "SELECT id, title, price, image_url FROM products WHERE id = ?", + "SELECT id, title, price, image_url FROM products WHERE id = ?" ); const result = stmt.get(productId) as Product | undefined; return result; diff --git a/rest/nodejs/src/data/transactions.ts b/rest/nodejs/src/data/transactions.ts index c2369a8..9a9b55a 100644 --- a/rest/nodejs/src/data/transactions.ts +++ b/rest/nodejs/src/data/transactions.ts @@ -31,7 +31,7 @@ export interface IdempotencyRecord { export function saveCheckout( checkoutId: string, status: string, - checkoutObj: ExtendedCheckoutResponse, + checkoutObj: ExtendedCheckoutResponse ): void { const db = getTransactionsDb(); @@ -43,12 +43,12 @@ export function saveCheckout( if (existing) { const updateStmt = db.prepare( - "UPDATE checkouts SET status = ?, data = ? WHERE id = ?", + "UPDATE checkouts SET status = ?, data = ? WHERE id = ?" ); updateStmt.run(status, dataStr, checkoutId); } else { const insertStmt = db.prepare( - "INSERT INTO checkouts (id, status, data) VALUES (?, ?, ?)", + "INSERT INTO checkouts (id, status, data) VALUES (?, ?, ?)" ); insertStmt.run(checkoutId, status, dataStr); } @@ -63,7 +63,7 @@ export function saveCheckout( * undefined. */ export function getCheckoutSession( - checkoutId: string, + checkoutId: string ): ExtendedCheckoutResponse | undefined { const db = getTransactionsDb(); const stmt = db.prepare("SELECT data FROM checkouts WHERE id = ?"); @@ -92,7 +92,7 @@ export function saveOrder(orderId: string, orderObj: Order): void { updateStmt.run(dataStr, orderId); } else { const insertStmt = db.prepare( - "INSERT INTO orders (id, data) VALUES (?, ?)", + "INSERT INTO orders (id, data) VALUES (?, ?)" ); insertStmt.run(orderId, dataStr); } @@ -118,21 +118,21 @@ export function logRequest( method: string, url: string, checkoutId: string | undefined, - payload: unknown, + payload: unknown ): void { const db = getTransactionsDb(); const stmt = db.prepare( - "INSERT INTO request_logs (method, url, checkout_id, payload) VALUES (?, ?, ?, ?)", + "INSERT INTO request_logs (method, url, checkout_id, payload) VALUES (?, ?, ?, ?)" ); stmt.run(method, url, checkoutId || null, JSON.stringify(payload)); } export function getIdempotencyRecord( - key: string, + key: string ): IdempotencyRecord | undefined { const db = getTransactionsDb(); const stmt = db.prepare( - "SELECT key, request_hash, response_status, response_body FROM idempotency_keys WHERE key = ?", + "SELECT key, request_hash, response_status, response_body FROM idempotency_keys WHERE key = ?" ); return stmt.get(key) as IdempotencyRecord | undefined; } @@ -141,11 +141,11 @@ export function saveIdempotencyRecord( key: string, requestHash: string, status: number, - responseBody: string, + responseBody: string ): void { const db = getTransactionsDb(); const stmt = db.prepare( - "INSERT OR REPLACE INTO idempotency_keys (key, request_hash, response_status, response_body) VALUES (?, ?, ?, ?)", + "INSERT OR REPLACE INTO idempotency_keys (key, request_hash, response_status, response_body) VALUES (?, ?, ?, ?)" ); stmt.run(key, requestHash, status, responseBody); } diff --git a/rest/nodejs/src/index.ts b/rest/nodejs/src/index.ts index 7ffdf3d..6e339d7 100644 --- a/rest/nodejs/src/index.ts +++ b/rest/nodejs/src/index.ts @@ -41,7 +41,7 @@ app.use(async (c: Context, next: () => Promise) => { translateTime: true, }, }, - })(c.env.incoming, c.env.outgoing, () => resolve()), + })(c.env.incoming, c.env.outgoing, () => resolve()) ); c.set("logger", c.env.incoming.log); @@ -63,7 +63,7 @@ app.use(async (c: Context, next: () => Promise) => { if (clientVersion > serverVersion) { return c.json( { error: `Unsupported UCP version: ${clientVersion}` }, - 400, + 400 ); } } @@ -78,49 +78,49 @@ app.get("/.well-known/ucp", discoveryService.getMerchantProfile); app.post( "/checkout-sessions", zValidator("json", ExtendedCheckoutCreateRequestSchema, prettyValidation), - checkoutService.createCheckout, + checkoutService.createCheckout ); app.get( "/checkout-sessions/:id", zValidator("param", IdParamSchema, prettyValidation), - checkoutService.getCheckout, + checkoutService.getCheckout ); app.put( "/checkout-sessions/:id", zValidator("param", IdParamSchema, prettyValidation), zValidator("json", ExtendedCheckoutUpdateRequestSchema, prettyValidation), - checkoutService.updateCheckout, + checkoutService.updateCheckout ); app.post( "/checkout-sessions/:id/complete", zValidator("param", IdParamSchema, prettyValidation), zValidator("json", zCompleteCheckoutRequest, prettyValidation), - checkoutService.completeCheckout, + checkoutService.completeCheckout ); app.post( "/checkout-sessions/:id/cancel", zValidator("param", IdParamSchema, prettyValidation), - checkoutService.cancelCheckout, + checkoutService.cancelCheckout ); /* Order Capability endpoints */ app.get( "/orders/:id", zValidator("param", IdParamSchema, prettyValidation), - orderService.getOrder, + orderService.getOrder ); app.put( "/orders/:id", zValidator("param", IdParamSchema, prettyValidation), zValidator("json", OrderSchema, prettyValidation), - orderService.updateOrder, + orderService.updateOrder ); /* Testing endpoints */ app.post( "/testing/simulate-shipping/:id", zValidator("param", IdParamSchema, prettyValidation), - testingService.shipOrder, + testingService.shipOrder ); serve( @@ -130,5 +130,5 @@ serve( }, (info) => { console.log(`Server is running on http://localhost:${info.port}`); - }, + } ); diff --git a/rest/nodejs/src/models/extensions.ts b/rest/nodejs/src/models/extensions.ts index 7c2b3f5..7c8da19 100644 --- a/rest/nodejs/src/models/extensions.ts +++ b/rest/nodejs/src/models/extensions.ts @@ -39,8 +39,7 @@ export type ExtendedCheckoutResponse = z.infer< export const ExtendedCheckoutCreateRequestSchema = CheckoutCreateRequestSchema.extend( - CheckoutWithFulfillmentCreateRequestSchema.pick({ fulfillment: true }) - .shape, + CheckoutWithFulfillmentCreateRequestSchema.pick({ fulfillment: true }).shape ) .extend(CheckoutWithDiscountSchema.pick({ discounts: true }).shape) .extend(CheckoutWithBuyerConsentSchema.pick({ buyer: true }).shape); @@ -50,8 +49,7 @@ export type ExtendedCheckoutCreateRequest = z.infer< export const ExtendedCheckoutUpdateRequestSchema = CheckoutUpdateRequestSchema.extend( - CheckoutWithFulfillmentUpdateRequestSchema.pick({ fulfillment: true }) - .shape, + CheckoutWithFulfillmentUpdateRequestSchema.pick({ fulfillment: true }).shape ) .extend(CheckoutWithDiscountSchema.pick({ discounts: true }).shape) .extend(CheckoutWithBuyerConsentSchema.pick({ buyer: true }).shape); diff --git a/rest/nodejs/src/utils/validation.ts b/rest/nodejs/src/utils/validation.ts index 093d18a..ea3db80 100644 --- a/rest/nodejs/src/utils/validation.ts +++ b/rest/nodejs/src/utils/validation.ts @@ -13,16 +13,16 @@ export function prettyValidation( result: | { success: true; data: T; target: string } | { success: false; error: any }, - c: Context, + c: Context ) { if (result.success) { c.var.logger.info( - `Request payload (${result.target}) passed validation:\n${JSON.stringify(result.data, null, 2)}`, + `Request payload (${result.target}) passed validation:\n${JSON.stringify(result.data, null, 2)}` ); } else { c.var.logger.warn("Request payload failed validation"); c.var.logger.warn( - `Request payload:\n${JSON.stringify(c.req.json(), null, 2)}`, + `Request payload:\n${JSON.stringify(c.req.json(), null, 2)}` ); const prettyError = z.prettifyError(result.error);