From cb2f6a97066391b5930166897c3f4841b633757e Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Thu, 31 Aug 2023 12:51:53 -0500 Subject: [PATCH 01/34] fix: temporarily revert back to old code examples for advanced (#78) --- advanced-integration/new/README.md | 11 ++ advanced-integration/{ => new}/client/app.js | 0 advanced-integration/new/package.json | 24 +++ .../{ => new}/server/server.js | 0 .../{ => new}/server/views/checkout.ejs | 0 advanced-integration/package.json | 4 +- advanced-integration/paypal-api.js | 100 +++++++++++ advanced-integration/public/app.js | 160 ++++++++++++++++++ advanced-integration/server.js | 44 +++++ advanced-integration/views/checkout.ejs | 101 +++++++++++ 10 files changed, 442 insertions(+), 2 deletions(-) create mode 100644 advanced-integration/new/README.md rename advanced-integration/{ => new}/client/app.js (100%) create mode 100644 advanced-integration/new/package.json rename advanced-integration/{ => new}/server/server.js (100%) rename advanced-integration/{ => new}/server/views/checkout.ejs (100%) create mode 100644 advanced-integration/paypal-api.js create mode 100644 advanced-integration/public/app.js create mode 100644 advanced-integration/server.js create mode 100644 advanced-integration/views/checkout.ejs diff --git a/advanced-integration/new/README.md b/advanced-integration/new/README.md new file mode 100644 index 00000000..923a5234 --- /dev/null +++ b/advanced-integration/new/README.md @@ -0,0 +1,11 @@ +# Advanced Integration Example + +This folder contains example code for an Advanced PayPal integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API. + +## Instructions + +1. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. +2. Run `npm install` +3. Run `npm start` +4. Open http://localhost:8888 +5. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) diff --git a/advanced-integration/client/app.js b/advanced-integration/new/client/app.js similarity index 100% rename from advanced-integration/client/app.js rename to advanced-integration/new/client/app.js diff --git a/advanced-integration/new/package.json b/advanced-integration/new/package.json new file mode 100644 index 00000000..ff3f5b41 --- /dev/null +++ b/advanced-integration/new/package.json @@ -0,0 +1,24 @@ +{ + "name": "paypal-advanced-integration", + "description": "Sample Node.js web app to integrate PayPal Advanced Checkout for online payments", + "version": "1.0.0", + "main": "server/server.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "nodemon server/server.js", + "format": "npx prettier --write **/*.{js,md}", + "format:check": "npx prettier --check **/*.{js,md}", + "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + }, + "license": "Apache-2.0", + "dependencies": { + "dotenv": "^16.3.1", + "ejs": "^3.1.9", + "express": "^4.18.2", + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" + } +} diff --git a/advanced-integration/server/server.js b/advanced-integration/new/server/server.js similarity index 100% rename from advanced-integration/server/server.js rename to advanced-integration/new/server/server.js diff --git a/advanced-integration/server/views/checkout.ejs b/advanced-integration/new/server/views/checkout.ejs similarity index 100% rename from advanced-integration/server/views/checkout.ejs rename to advanced-integration/new/server/views/checkout.ejs diff --git a/advanced-integration/package.json b/advanced-integration/package.json index ff3f5b41..d17aa000 100644 --- a/advanced-integration/package.json +++ b/advanced-integration/package.json @@ -6,10 +6,10 @@ "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon server/server.js", + "start": "nodemon server.js", "format": "npx prettier --write **/*.{js,md}", "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + "lint": "npx eslint server.js paypal-api.js --env=node && npx eslint public/*.js --env=browser" }, "license": "Apache-2.0", "dependencies": { diff --git a/advanced-integration/paypal-api.js b/advanced-integration/paypal-api.js new file mode 100644 index 00000000..6e6c8aaf --- /dev/null +++ b/advanced-integration/paypal-api.js @@ -0,0 +1,100 @@ +import fetch from "node-fetch"; + +// set some important variables +const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET } = process.env; +const base = "https://api-m.sandbox.paypal.com"; + +/** + * Create an order + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +export async function createOrder() { + const purchaseAmount = "100.00"; // TODO: pull prices from a database + const accessToken = await generateAccessToken(); + const url = `${base}/v2/checkout/orders`; + const response = await fetch(url, { + method: "post", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + }, + body: JSON.stringify({ + intent: "CAPTURE", + purchase_units: [ + { + amount: { + currency_code: "USD", + value: purchaseAmount, + }, + }, + ], + }), + }); + + return handleResponse(response); +} + +/** + * Capture payment for an order + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +export async function capturePayment(orderId) { + const accessToken = await generateAccessToken(); + const url = `${base}/v2/checkout/orders/${orderId}/capture`; + const response = await fetch(url, { + method: "post", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + }, + }); + + return handleResponse(response); +} + +/** + * Generate an OAuth 2.0 access token + * @see https://developer.paypal.com/api/rest/authentication/ + */ +export async function generateAccessToken() { + const auth = Buffer.from( + PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET, + ).toString("base64"); + const response = await fetch(`${base}/v1/oauth2/token`, { + method: "post", + body: "grant_type=client_credentials", + headers: { + Authorization: `Basic ${auth}`, + }, + }); + const jsonData = await handleResponse(response); + return jsonData.access_token; +} + +/** + * Generate a client token + * @see https://developer.paypal.com/docs/checkout/advanced/integrate/#link-sampleclienttokenrequest + */ +export async function generateClientToken() { + const accessToken = await generateAccessToken(); + const response = await fetch(`${base}/v1/identity/generate-token`, { + method: "post", + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Language": "en_US", + "Content-Type": "application/json", + }, + }); + console.log("response", response.status); + const jsonData = await handleResponse(response); + return jsonData.client_token; +} + +async function handleResponse(response) { + if (response.status === 200 || response.status === 201) { + return response.json(); + } + + const errorMessage = await response.text(); + throw new Error(errorMessage); +} diff --git a/advanced-integration/public/app.js b/advanced-integration/public/app.js new file mode 100644 index 00000000..f475472d --- /dev/null +++ b/advanced-integration/public/app.js @@ -0,0 +1,160 @@ +window.paypal + .Buttons({ + // Sets up the transaction when a payment button is clicked + createOrder: function () { + return fetch("/api/orders", { + method: "post", + // use the "body" param to optionally pass additional order information + // like product skus and quantities + body: JSON.stringify({ + cart: [ + { + sku: "", + quantity: "", + }, + ], + }), + }) + .then((response) => response.json()) + .then((order) => order.id); + }, + // Finalize the transaction after payer approval + onApprove: function (data) { + return fetch(`/api/orders/${data.orderID}/capture`, { + method: "post", + }) + .then((response) => response.json()) + .then((orderData) => { + // Successful capture! For dev/demo purposes: + console.log( + "Capture result", + orderData, + JSON.stringify(orderData, null, 2), + ); + const transaction = orderData.purchase_units[0].payments.captures[0]; + alert(`Transaction ${transaction.status}: ${transaction.id} + + See console for all available details + `); + // When ready to go live, remove the alert and show a success message within this page. For example: + // var element = document.getElementById('paypal-button-container'); + // element.innerHTML = '

Thank you for your payment!

'; + // Or go to another URL: actions.redirect('thank_you.html'); + }); + }, + }) + .render("#paypal-button-container"); + +// If this returns false or the card fields aren't visible, see Step #1. +if (window.paypal.HostedFields.isEligible()) { + let orderId; + + // Renders card fields + window.paypal.HostedFields.render({ + // Call your server to set up the transaction + createOrder: () => { + return fetch("/api/orders", { + method: "post", + // use the "body" param to optionally pass additional order information + // like product skus and quantities + body: JSON.stringify({ + cart: [ + { + sku: "", + quantity: "", + }, + ], + }), + }) + .then((res) => res.json()) + .then((orderData) => { + orderId = orderData.id; // needed later to complete capture + return orderData.id; + }); + }, + styles: { + ".valid": { + color: "green", + }, + ".invalid": { + color: "red", + }, + }, + fields: { + number: { + selector: "#card-number", + placeholder: "4111 1111 1111 1111", + }, + cvv: { + selector: "#cvv", + placeholder: "123", + }, + expirationDate: { + selector: "#expiration-date", + placeholder: "MM/YY", + }, + }, + }).then((cardFields) => { + document.querySelector("#card-form").addEventListener("submit", (event) => { + event.preventDefault(); + cardFields + .submit({ + // Cardholder's first and last name + cardholderName: document.getElementById("card-holder-name").value, + // Billing Address + billingAddress: { + // Street address, line 1 + streetAddress: document.getElementById( + "card-billing-address-street", + ).value, + // Street address, line 2 (Ex: Unit, Apartment, etc.) + extendedAddress: document.getElementById( + "card-billing-address-unit", + ).value, + // State + region: document.getElementById("card-billing-address-state").value, + // City + locality: document.getElementById("card-billing-address-city") + .value, + // Postal Code + postalCode: document.getElementById("card-billing-address-zip") + .value, + // Country Code + countryCodeAlpha2: document.getElementById( + "card-billing-address-country", + ).value, + }, + }) + .then(() => { + fetch(`/api/orders/${orderId}/capture`, { + method: "post", + }) + .then((res) => res.json()) + .then((orderData) => { + // Two cases to handle: + // (1) Other non-recoverable errors -> Show a failure message + // (2) Successful transaction -> Show confirmation or thank you + // This example reads a v2/checkout/orders capture response, propagated from the server + // You could use a different API or structure for your 'orderData' + const errorDetail = + Array.isArray(orderData.details) && orderData.details[0]; + if (errorDetail) { + var msg = "Sorry, your transaction could not be processed."; + if (errorDetail.description) + msg += "\n\n" + errorDetail.description; + if (orderData.debug_id) msg += " (" + orderData.debug_id + ")"; + return alert(msg); // Show a failure message + } + // Show a success message or redirect + alert("Transaction completed!"); + }); + }) + .catch((err) => { + alert("Payment could not be captured! " + JSON.stringify(err)); + }); + }); + }); +} else { + // Hides card fields if the merchant isn't eligible + document.querySelector("#card-form").style = "display: none"; +} diff --git a/advanced-integration/server.js b/advanced-integration/server.js new file mode 100644 index 00000000..73076fcb --- /dev/null +++ b/advanced-integration/server.js @@ -0,0 +1,44 @@ +import "dotenv/config"; +import express from "express"; +import * as paypal from "./paypal-api.js"; +const { PORT = 8888 } = process.env; + +const app = express(); +app.set("view engine", "ejs"); +app.use(express.static("public")); + +// render checkout page with client id & unique client token +app.get("/", async (req, res) => { + const clientId = process.env.PAYPAL_CLIENT_ID; + try { + const clientToken = await paypal.generateClientToken(); + res.render("checkout", { clientId, clientToken }); + } catch (err) { + res.status(500).send(err.message); + } +}); + +// create order +app.post("/api/orders", async (req, res) => { + try { + const order = await paypal.createOrder(); + res.json(order); + } catch (err) { + res.status(500).send(err.message); + } +}); + +// capture payment +app.post("/api/orders/:orderID/capture", async (req, res) => { + const { orderID } = req.params; + try { + const captureData = await paypal.capturePayment(orderID); + res.json(captureData); + } catch (err) { + res.status(500).send(err.message); + } +}); + +app.listen(PORT, () => { + console.log(`Server listening at http://localhost:${PORT}/`); +}); diff --git a/advanced-integration/views/checkout.ejs b/advanced-integration/views/checkout.ejs new file mode 100644 index 00000000..12522326 --- /dev/null +++ b/advanced-integration/views/checkout.ejs @@ -0,0 +1,101 @@ + + + + + + + + +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ + +
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+

+ +
+
+ + + From fa12c9c095bf95bd07be85f0cfd64aa71ea9240f Mon Sep 17 00:00:00 2001 From: sdarshale <141275730+sdarshale@users.noreply.github.com> Date: Mon, 18 Sep 2023 15:25:37 -0500 Subject: [PATCH 02/34] Update README with codespace details (#80) --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e2f4e583..34a45ef6 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,22 @@ These examples will ask you to run commands like `npm install` and `npm start`. You'll need a version of node >= 16 which can be downloaded from the [Node.js website](https://nodejs.org/en/download/). -### PayPal Codespaces Links +## PayPal Codespaces + +PayPal codespaces require a client ID and client secret for your app. + +### Link to codespaces + | Application | Codespaces Link | | ---- | ---- | | Advanced Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration%2Fdevcontainer.json)| -| Standard Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fstandard-integration%2Fdevcontainer.json)| \ No newline at end of file +| Standard Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fstandard-integration%2Fdevcontainer.json)| + +### Learn more + +You can read more about codespaces in the [PayPal Developer Docs](https://developer.paypal.com/api/rest/sandbox/codespaces). + +## Submit Feedback + +* To report a bug or suggest a new feature, create an [issue in GitHub](https://github.com/paypal-examples/paypaldevsupport/issues/new/choose). +* To submit feedback, go to [GitHub Codespaces](https://developer.paypal.com/api/rest/sandbox/codespaces) and select the "Feedback" tab. From e26deb2111246895d7bd3184cc0b77261cdc6f45 Mon Sep 17 00:00:00 2001 From: sdarshale <141275730+sdarshale@users.noreply.github.com> Date: Fri, 22 Sep 2023 16:07:21 -0500 Subject: [PATCH 03/34] chore(docs): update readme feedback header section (#81) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 34a45ef6..06ce3837 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ PayPal codespaces require a client ID and client secret for your app. You can read more about codespaces in the [PayPal Developer Docs](https://developer.paypal.com/api/rest/sandbox/codespaces). -## Submit Feedback +### Feedback * To report a bug or suggest a new feature, create an [issue in GitHub](https://github.com/paypal-examples/paypaldevsupport/issues/new/choose). * To submit feedback, go to [GitHub Codespaces](https://developer.paypal.com/api/rest/sandbox/codespaces) and select the "Feedback" tab. From 53f4e726e51fabb4595f40c78aa1421e537ebd40 Mon Sep 17 00:00:00 2001 From: cnallam <130782580+cnallam@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:42:07 -0700 Subject: [PATCH 04/34] Update README.md for typo fix (#83) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 06ce3837..b0bba29e 100644 --- a/README.md +++ b/README.md @@ -59,4 +59,4 @@ You can read more about codespaces in the [PayPal Developer Docs](https://develo ### Feedback * To report a bug or suggest a new feature, create an [issue in GitHub](https://github.com/paypal-examples/paypaldevsupport/issues/new/choose). -* To submit feedback, go to [GitHub Codespaces](https://developer.paypal.com/api/rest/sandbox/codespaces) and select the "Feedback" tab. +* To submit feedback, go to [PayPal Developer Docs](https://developer.paypal.com/api/rest/sandbox/codespaces) and select the "Feedback" tab. From d3c1ada47587a24c9b96e3f02d4617ca5889b1e5 Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Wed, 4 Oct 2023 16:08:51 -0500 Subject: [PATCH 05/34] Rename the advanced integration "new" folder to "v1" (#85) --- advanced-integration/{new => v1}/README.md | 0 advanced-integration/{new => v1}/client/app.js | 0 advanced-integration/{new => v1}/package.json | 0 advanced-integration/{new => v1}/server/server.js | 0 advanced-integration/{new => v1}/server/views/checkout.ejs | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename advanced-integration/{new => v1}/README.md (100%) rename advanced-integration/{new => v1}/client/app.js (100%) rename advanced-integration/{new => v1}/package.json (100%) rename advanced-integration/{new => v1}/server/server.js (100%) rename advanced-integration/{new => v1}/server/views/checkout.ejs (100%) diff --git a/advanced-integration/new/README.md b/advanced-integration/v1/README.md similarity index 100% rename from advanced-integration/new/README.md rename to advanced-integration/v1/README.md diff --git a/advanced-integration/new/client/app.js b/advanced-integration/v1/client/app.js similarity index 100% rename from advanced-integration/new/client/app.js rename to advanced-integration/v1/client/app.js diff --git a/advanced-integration/new/package.json b/advanced-integration/v1/package.json similarity index 100% rename from advanced-integration/new/package.json rename to advanced-integration/v1/package.json diff --git a/advanced-integration/new/server/server.js b/advanced-integration/v1/server/server.js similarity index 100% rename from advanced-integration/new/server/server.js rename to advanced-integration/v1/server/server.js diff --git a/advanced-integration/new/server/views/checkout.ejs b/advanced-integration/v1/server/views/checkout.ejs similarity index 100% rename from advanced-integration/new/server/views/checkout.ejs rename to advanced-integration/v1/server/views/checkout.ejs From 5c89c3c1743a1e7df9f36986454eb232ac8d3c3c Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Thu, 5 Oct 2023 16:39:08 -0500 Subject: [PATCH 06/34] Add new card fields beta component (#84) --- .../devcontainer.json | 40 +++++ .../welcome-message.sh | 23 +++ advanced-integration/beta/.env.example | 5 + advanced-integration/beta/README.md | 11 ++ .../beta/client/checkout.html | 24 +++ advanced-integration/beta/client/checkout.js | 144 +++++++++++++++++ advanced-integration/beta/package.json | 23 +++ advanced-integration/beta/server/server.js | 152 ++++++++++++++++++ 8 files changed, 422 insertions(+) create mode 100644 .devcontainer/advanced-integration-beta/devcontainer.json create mode 100644 .devcontainer/advanced-integration-beta/welcome-message.sh create mode 100644 advanced-integration/beta/.env.example create mode 100644 advanced-integration/beta/README.md create mode 100644 advanced-integration/beta/client/checkout.html create mode 100644 advanced-integration/beta/client/checkout.js create mode 100644 advanced-integration/beta/package.json create mode 100644 advanced-integration/beta/server/server.js diff --git a/.devcontainer/advanced-integration-beta/devcontainer.json b/.devcontainer/advanced-integration-beta/devcontainer.json new file mode 100644 index 00000000..44c2d10c --- /dev/null +++ b/.devcontainer/advanced-integration-beta/devcontainer.json @@ -0,0 +1,40 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "PayPal Advanced Integration (beta)", + "image": "mcr.microsoft.com/devcontainers/javascript-node:20", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/beta", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash ../.devcontainer/advanced-integration-beta/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "npm install", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": { + "Start server": "npm start" + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [8888], + "portsAttributes": { + "8888": { + "label": "Preview of Advanced Checkout Flow", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "customizations": { + "vscode": { + "extensions": ["vsls-contrib.codetour"], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + } +} diff --git a/.devcontainer/advanced-integration-beta/welcome-message.sh b/.devcontainer/advanced-integration-beta/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-beta/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/advanced-integration/beta/.env.example b/advanced-integration/beta/.env.example new file mode 100644 index 00000000..2251fbbb --- /dev/null +++ b/advanced-integration/beta/.env.example @@ -0,0 +1,5 @@ +# Create an application to obtain credentials at +# https://developer.paypal.com/dashboard/applications/sandbox + +PAYPAL_CLIENT_ID=YOUR_CLIENT_ID_GOES_HERE +PAYPAL_CLIENT_SECRET=YOUR_SECRET_GOES_HERE diff --git a/advanced-integration/beta/README.md b/advanced-integration/beta/README.md new file mode 100644 index 00000000..923a5234 --- /dev/null +++ b/advanced-integration/beta/README.md @@ -0,0 +1,11 @@ +# Advanced Integration Example + +This folder contains example code for an Advanced PayPal integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API. + +## Instructions + +1. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. +2. Run `npm install` +3. Run `npm start` +4. Open http://localhost:8888 +5. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) diff --git a/advanced-integration/beta/client/checkout.html b/advanced-integration/beta/client/checkout.html new file mode 100644 index 00000000..a052a57a --- /dev/null +++ b/advanced-integration/beta/client/checkout.html @@ -0,0 +1,24 @@ + + + + + + + PayPal JS SDK Advanced Integration - Checkout Flow + + +
+
+
+
+
+
+ +
+

+ + + + + diff --git a/advanced-integration/beta/client/checkout.js b/advanced-integration/beta/client/checkout.js new file mode 100644 index 00000000..517edeb8 --- /dev/null +++ b/advanced-integration/beta/client/checkout.js @@ -0,0 +1,144 @@ +async function createOrderCallback() { + try { + const response = await fetch("/api/orders", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + // use the "body" param to optionally pass additional order information + // like product ids and quantities + body: JSON.stringify({ + cart: [ + { + id: "YOUR_PRODUCT_ID", + quantity: "YOUR_PRODUCT_QUANTITY", + }, + ], + }), + }); + + const orderData = await response.json(); + + if (orderData.id) { + return orderData.id; + } else { + const errorDetail = orderData?.details?.[0]; + const errorMessage = errorDetail + ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` + : JSON.stringify(orderData); + + throw new Error(errorMessage); + } + } catch (error) { + console.error(error); + resultMessage(`Could not initiate PayPal Checkout...

${error}`); + } +} + +async function onApproveCallback(data, actions) { + try { + const response = await fetch(`/api/orders/${data.orderID}/capture`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }); + + const orderData = await response.json(); + // Three cases to handle: + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // (2) Other non-recoverable errors -> Show a failure message + // (3) Successful transaction -> Show confirmation or thank you message + + const transaction = + orderData?.purchase_units?.[0]?.payments?.captures?.[0] || + orderData?.purchase_units?.[0]?.payments?.authorizations?.[0]; + const errorDetail = orderData?.details?.[0]; + + // this actions.restart() behavior only applies to the Buttons component + if (errorDetail?.issue === "INSTRUMENT_DECLINED" && !data.card && actions) { + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ + return actions.restart(); + } else if ( + errorDetail || + !transaction || + transaction.status === "DECLINED" + ) { + // (2) Other non-recoverable errors -> Show a failure message + let errorMessage; + if (transaction) { + errorMessage = `Transaction ${transaction.status}: ${transaction.id}`; + } else if (errorDetail) { + errorMessage = `${errorDetail.description} (${orderData.debug_id})`; + } else { + errorMessage = JSON.stringify(orderData); + } + + throw new Error(errorMessage); + } else { + // (3) Successful transaction -> Show confirmation or thank you message + // Or go to another URL: actions.redirect('thank_you.html'); + resultMessage( + `Transaction ${transaction.status}: ${transaction.id}

See console for all available details`, + ); + console.log( + "Capture result", + orderData, + JSON.stringify(orderData, null, 2), + ); + } + } catch (error) { + console.error(error); + resultMessage( + `Sorry, your transaction could not be processed...

${error}`, + ); + } +} + +window.paypal + .Buttons({ + createOrder: createOrderCallback, + onApprove: onApproveCallback, + }) + .render("#paypal-button-container"); + +const cardField = window.paypal.CardFields({ + createOrder: createOrderCallback, + onApprove: onApproveCallback, +}); + +// Render each field after checking for eligibility +if (cardField.isEligible()) { + const nameField = cardField.NameField(); + nameField.render("#card-name-field-container"); + + const numberField = cardField.NumberField(); + numberField.render("#card-number-field-container"); + + const cvvField = cardField.CVVField(); + cvvField.render("#card-cvv-field-container"); + + const expiryField = cardField.ExpiryField(); + expiryField.render("#card-expiry-field-container"); + + // Add click listener to submit button and call the submit function on the CardField component + document + .getElementById("multi-card-field-button") + .addEventListener("click", () => { + cardField.submit().catch((error) => { + resultMessage( + `Sorry, your transaction could not be processed...

${error}`, + ); + }); + }); +} else { + // Hides card fields if the merchant isn't eligible + document.querySelector("#card-form").style = "display: none"; +} + +// Example function to show a result to the user. Your site's UI library can be used instead. +function resultMessage(message) { + const container = document.querySelector("#result-message"); + container.innerHTML = message; +} diff --git a/advanced-integration/beta/package.json b/advanced-integration/beta/package.json new file mode 100644 index 00000000..c87347ac --- /dev/null +++ b/advanced-integration/beta/package.json @@ -0,0 +1,23 @@ +{ + "name": "paypal-advanced-integration", + "description": "Sample Node.js web app to integrate PayPal Advanced Checkout for online payments", + "version": "1.0.0", + "main": "server/server.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "nodemon server/server.js", + "format": "npx prettier --write **/*.{js,md}", + "format:check": "npx prettier --check **/*.{js,md}", + "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + }, + "license": "Apache-2.0", + "dependencies": { + "dotenv": "^16.3.1", + "express": "^4.18.2", + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" + } +} diff --git a/advanced-integration/beta/server/server.js b/advanced-integration/beta/server/server.js new file mode 100644 index 00000000..0d8d3cb8 --- /dev/null +++ b/advanced-integration/beta/server/server.js @@ -0,0 +1,152 @@ +import express from "express"; +import fetch from "node-fetch"; +import "dotenv/config"; +import path from "path"; + +const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8888 } = process.env; +const base = "https://api-m.sandbox.paypal.com"; +const app = express(); + +// host static files +app.use(express.static("client")); + +// parse post params sent in body in json format +app.use(express.json()); + +/** + * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs. + * @see https://developer.paypal.com/api/rest/authentication/ + */ +const generateAccessToken = async () => { + try { + if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) { + throw new Error("MISSING_API_CREDENTIALS"); + } + const auth = Buffer.from( + PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET, + ).toString("base64"); + const response = await fetch(`${base}/v1/oauth2/token`, { + method: "POST", + body: "grant_type=client_credentials", + headers: { + Authorization: `Basic ${auth}`, + }, + }); + + const data = await response.json(); + return data.access_token; + } catch (error) { + console.error("Failed to generate Access Token:", error); + } +}; + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +const createOrder = async (cart) => { + // use the cart information passed from the front-end to calculate the purchase unit details + console.log( + "shopping cart information passed from the frontend createOrder() callback:", + cart, + ); + + const accessToken = await generateAccessToken(); + const url = `${base}/v2/checkout/orders`; + const payload = { + intent: "CAPTURE", + purchase_units: [ + { + amount: { + currency_code: "USD", + value: "100.00", + }, + }, + ], + }; + + const response = await fetch(url, { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: + // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ + // "PayPal-Mock-Response": '{"mock_application_codes": "MISSING_REQUIRED_PARAMETER"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "PERMISSION_DENIED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' + }, + method: "POST", + body: JSON.stringify(payload), + }); + + return handleResponse(response); +}; + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +const captureOrder = async (orderID) => { + const accessToken = await generateAccessToken(); + const url = `${base}/v2/checkout/orders/${orderID}/capture`; + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: + // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ + // "PayPal-Mock-Response": '{"mock_application_codes": "INSTRUMENT_DECLINED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "TRANSACTION_REFUSED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' + }, + }); + + return handleResponse(response); +}; + +async function handleResponse(response) { + try { + const jsonResponse = await response.json(); + return { + jsonResponse, + httpStatusCode: response.status, + }; + } catch (err) { + const errorMessage = await response.text(); + throw new Error(errorMessage); + } +} + +app.post("/api/orders", async (req, res) => { + try { + // use the cart information passed from the front-end to calculate the order amount detals + const { cart } = req.body; + const { jsonResponse, httpStatusCode } = await createOrder(cart); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to create order." }); + } +}); + +app.post("/api/orders/:orderID/capture", async (req, res) => { + try { + const { orderID } = req.params; + const { jsonResponse, httpStatusCode } = await captureOrder(orderID); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to capture order." }); + } +}); + +// serve index.html +app.get("/", (req, res) => { + res.sendFile(path.resolve("./client/checkout.html")); +}); + +app.listen(PORT, () => { + console.log(`Node server listening at http://localhost:${PORT}/`); +}); From ba6914a3b3439ba478c61ce4ea1f8062fcd555c2 Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Thu, 5 Oct 2023 16:50:55 -0500 Subject: [PATCH 07/34] Fix codespaces path --- .devcontainer/advanced-integration-beta/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/advanced-integration-beta/devcontainer.json b/.devcontainer/advanced-integration-beta/devcontainer.json index 44c2d10c..818b454f 100644 --- a/.devcontainer/advanced-integration-beta/devcontainer.json +++ b/.devcontainer/advanced-integration-beta/devcontainer.json @@ -4,7 +4,7 @@ "image": "mcr.microsoft.com/devcontainers/javascript-node:20", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/beta", // Use 'onCreateCommand' to run commands when creating the container. - "onCreateCommand": "bash ../.devcontainer/advanced-integration-beta/welcome-message.sh", + "onCreateCommand": "bash ../../.devcontainer/advanced-integration-beta/welcome-message.sh", // Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "npm install", // Use 'postAttachCommand' to run commands when attaching to the container. From f62771f2529d0ff5ecf2e92e051871968dcf9d81 Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Fri, 6 Oct 2023 10:01:31 -0500 Subject: [PATCH 08/34] Use existing css to center beta card form --- advanced-integration/beta/client/checkout.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/advanced-integration/beta/client/checkout.html b/advanced-integration/beta/client/checkout.html index a052a57a..cbc61169 100644 --- a/advanced-integration/beta/client/checkout.html +++ b/advanced-integration/beta/client/checkout.html @@ -8,8 +8,8 @@ PayPal JS SDK Advanced Integration - Checkout Flow -
-
+
+
From 5a3ea22d61bf6da31b63c6d046c4f3608c07d393 Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Fri, 6 Oct 2023 12:36:46 -0500 Subject: [PATCH 09/34] fix(docs): update instructions for replacing client-id in html (#86) --- advanced-integration/beta/README.md | 12 +++++++----- standard-integration/README.md | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/advanced-integration/beta/README.md b/advanced-integration/beta/README.md index 923a5234..2f6e5140 100644 --- a/advanced-integration/beta/README.md +++ b/advanced-integration/beta/README.md @@ -4,8 +4,10 @@ This folder contains example code for an Advanced PayPal integration using both ## Instructions -1. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. -2. Run `npm install` -3. Run `npm start` -4. Open http://localhost:8888 -5. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) +1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create) +2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. +3. Replace `test` in [client/checkout.html](client/checkout.html) with your app's client-id +4. Run `npm install` +5. Run `npm start` +6. Open http://localhost:8888 +7. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) diff --git a/standard-integration/README.md b/standard-integration/README.md index c0bf83f3..408396b8 100644 --- a/standard-integration/README.md +++ b/standard-integration/README.md @@ -6,7 +6,7 @@ This folder contains example code for a Standard PayPal integration using both t 1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create) 2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET` -3. Replace `test` in `client/index.html` with your app's client-id +3. Replace `test` in [client/checkout.html](client/checkout.html) with your app's client-id 4. Run `npm install` 5. Run `npm start` 6. Open http://localhost:8888 From f240e2692b7876bad75fdc7d063fe833675cce8f Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:32:17 -0500 Subject: [PATCH 10/34] Add codespaces example for hosted fields v1 changes --- .../advanced-integration-v1/devcontainer.json | 40 +++++++++++++++++++ .../welcome-message.sh | 23 +++++++++++ 2 files changed, 63 insertions(+) create mode 100644 .devcontainer/advanced-integration-v1/devcontainer.json create mode 100644 .devcontainer/advanced-integration-v1/welcome-message.sh diff --git a/.devcontainer/advanced-integration-v1/devcontainer.json b/.devcontainer/advanced-integration-v1/devcontainer.json new file mode 100644 index 00000000..62758180 --- /dev/null +++ b/.devcontainer/advanced-integration-v1/devcontainer.json @@ -0,0 +1,40 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "PayPal Advanced Integration (v1)", + "image": "mcr.microsoft.com/devcontainers/javascript-node:20", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/v1", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash ../../.devcontainer/advanced-integration-v1/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "npm install", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": { + "Start server": "npm start" + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [8888], + "portsAttributes": { + "8888": { + "label": "Preview of Advanced Checkout Flow", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "customizations": { + "vscode": { + "extensions": ["vsls-contrib.codetour"], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + } +} diff --git a/.devcontainer/advanced-integration-v1/welcome-message.sh b/.devcontainer/advanced-integration-v1/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-v1/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" From 7c03b1a77659e04876aec873016d2f62c9b7966b Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:51:03 -0500 Subject: [PATCH 11/34] Update the name of the v2 card fields codespaces config (#88) --- .../devcontainer.json | 2 +- .../welcome-message.sh | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename .devcontainer/{advanced-integration-beta => advanced-integration-v2}/devcontainer.json (96%) rename .devcontainer/{advanced-integration-beta => advanced-integration-v2}/welcome-message.sh (100%) diff --git a/.devcontainer/advanced-integration-beta/devcontainer.json b/.devcontainer/advanced-integration-v2/devcontainer.json similarity index 96% rename from .devcontainer/advanced-integration-beta/devcontainer.json rename to .devcontainer/advanced-integration-v2/devcontainer.json index 818b454f..b3a54490 100644 --- a/.devcontainer/advanced-integration-beta/devcontainer.json +++ b/.devcontainer/advanced-integration-v2/devcontainer.json @@ -1,6 +1,6 @@ // For more details, see https://aka.ms/devcontainer.json. { - "name": "PayPal Advanced Integration (beta)", + "name": "PayPal Advanced Integration (v2)", "image": "mcr.microsoft.com/devcontainers/javascript-node:20", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/beta", // Use 'onCreateCommand' to run commands when creating the container. diff --git a/.devcontainer/advanced-integration-beta/welcome-message.sh b/.devcontainer/advanced-integration-v2/welcome-message.sh similarity index 100% rename from .devcontainer/advanced-integration-beta/welcome-message.sh rename to .devcontainer/advanced-integration-v2/welcome-message.sh From 4fe6e5ad42cf1e93852ec246701d57344ceafc31 Mon Sep 17 00:00:00 2001 From: cnallam <130782580+cnallam@users.noreply.github.com> Date: Tue, 24 Oct 2023 17:10:16 +0000 Subject: [PATCH 12/34] My Changes --- standard-integration/server/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard-integration/server/server.js b/standard-integration/server/server.js index 0d8d3cb8..fba19829 100644 --- a/standard-integration/server/server.js +++ b/standard-integration/server/server.js @@ -59,7 +59,7 @@ const createOrder = async (cart) => { { amount: { currency_code: "USD", - value: "100.00", + value: "110.00", }, }, ], From 39aeb3cb00899f1354ce1ec010952fdbae73a944 Mon Sep 17 00:00:00 2001 From: "Devon Apple (PayPal)" <105875840+devapplepaypal@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:35:46 -0700 Subject: [PATCH 13/34] update advanced integration format to support v1 and v2 (#87) --- advanced-integration/README.md | 9 +- advanced-integration/beta/README.md | 13 -- advanced-integration/package.json | 24 --- advanced-integration/v1/.gitignore | 1 + advanced-integration/v1/README.md | 15 +- advanced-integration/v1/client/app.js | 186 ------------------ .../{.env.example => v1/env.example} | 0 advanced-integration/v1/package.json | 4 +- advanced-integration/{ => v1}/paypal-api.js | 0 advanced-integration/{ => v1}/public/app.js | 0 advanced-integration/{ => v1}/server.js | 0 advanced-integration/v1/server/server.js | 178 ----------------- .../v1/{server => }/views/checkout.ejs | 31 ++- .../{beta => v2}/.env.example | 0 advanced-integration/v2/README.md | 23 +++ .../{beta => v2}/client/checkout.html | 0 .../{beta => v2}/client/checkout.js | 0 .../{beta => v2}/package.json | 0 .../{beta => v2}/server/server.js | 0 19 files changed, 56 insertions(+), 428 deletions(-) delete mode 100644 advanced-integration/beta/README.md delete mode 100644 advanced-integration/package.json create mode 100644 advanced-integration/v1/.gitignore delete mode 100644 advanced-integration/v1/client/app.js rename advanced-integration/{.env.example => v1/env.example} (100%) rename advanced-integration/{ => v1}/paypal-api.js (100%) rename advanced-integration/{ => v1}/public/app.js (100%) rename advanced-integration/{ => v1}/server.js (100%) delete mode 100644 advanced-integration/v1/server/server.js rename advanced-integration/v1/{server => }/views/checkout.ejs (88%) rename advanced-integration/{beta => v2}/.env.example (100%) create mode 100644 advanced-integration/v2/README.md rename advanced-integration/{beta => v2}/client/checkout.html (100%) rename advanced-integration/{beta => v2}/client/checkout.js (100%) rename advanced-integration/{beta => v2}/package.json (100%) rename advanced-integration/{beta => v2}/server/server.js (100%) diff --git a/advanced-integration/README.md b/advanced-integration/README.md index 923a5234..96d2c205 100644 --- a/advanced-integration/README.md +++ b/advanced-integration/README.md @@ -1,9 +1,14 @@ -# Advanced Integration Example +# Advanced Checkout Integration Example -This folder contains example code for an Advanced PayPal integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API. +This folder contains example code for a PayPal advanced Checkout integration using both the JavaScript SDK and Node.js to complete transactions with the PayPal REST API. + +* [`v2`](v2/README.md) contains sample code for the current advanced Checkout integration. This includes guidance on using Hosted Card Fields. +* [`v1`](v1/README.md) contains sample code for the legacy advanced Checkout integration. Use `v2` for new integrations. ## Instructions +These instructions apply to the sample code for both `v2` and `v1`: + 1. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. 2. Run `npm install` 3. Run `npm start` diff --git a/advanced-integration/beta/README.md b/advanced-integration/beta/README.md deleted file mode 100644 index 2f6e5140..00000000 --- a/advanced-integration/beta/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Advanced Integration Example - -This folder contains example code for an Advanced PayPal integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API. - -## Instructions - -1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create) -2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. -3. Replace `test` in [client/checkout.html](client/checkout.html) with your app's client-id -4. Run `npm install` -5. Run `npm start` -6. Open http://localhost:8888 -7. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) diff --git a/advanced-integration/package.json b/advanced-integration/package.json deleted file mode 100644 index d17aa000..00000000 --- a/advanced-integration/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "paypal-advanced-integration", - "description": "Sample Node.js web app to integrate PayPal Advanced Checkout for online payments", - "version": "1.0.0", - "main": "server/server.js", - "type": "module", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon server.js", - "format": "npx prettier --write **/*.{js,md}", - "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server.js paypal-api.js --env=node && npx eslint public/*.js --env=browser" - }, - "license": "Apache-2.0", - "dependencies": { - "dotenv": "^16.3.1", - "ejs": "^3.1.9", - "express": "^4.18.2", - "node-fetch": "^3.3.2" - }, - "devDependencies": { - "nodemon": "^3.0.1" - } -} diff --git a/advanced-integration/v1/.gitignore b/advanced-integration/v1/.gitignore new file mode 100644 index 00000000..4c49bd78 --- /dev/null +++ b/advanced-integration/v1/.gitignore @@ -0,0 +1 @@ +.env diff --git a/advanced-integration/v1/README.md b/advanced-integration/v1/README.md index 923a5234..152ef9ae 100644 --- a/advanced-integration/v1/README.md +++ b/advanced-integration/v1/README.md @@ -1,11 +1,14 @@ # Advanced Integration Example -This folder contains example code for an Advanced PayPal integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API. +This folder contains example code for [version 1](https://developer.paypal.com/docs/checkout/advanced/integrate/sdk/v1) of a PayPal advanced Checkout integration using the JavaScript SDK and Node.js to complete transactions with the PayPal REST API. + +> **Note:** Version 1 is a legacy integration. Use [version 2](https://developer.paypal.com/docs/checkout/advanced/integrate/) for new integrations. ## Instructions -1. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. -2. Run `npm install` -3. Run `npm start` -4. Open http://localhost:8888 -5. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) +1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create). +2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. +3. Run `npm install`. +4. Run `npm start`. +5. Open http://localhost:8888. +6. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator). diff --git a/advanced-integration/v1/client/app.js b/advanced-integration/v1/client/app.js deleted file mode 100644 index 65f048d7..00000000 --- a/advanced-integration/v1/client/app.js +++ /dev/null @@ -1,186 +0,0 @@ -async function createOrderCallback() { - try { - const response = await fetch("/api/orders", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - // use the "body" param to optionally pass additional order information - // like product ids and quantities - body: JSON.stringify({ - cart: [ - { - id: "YOUR_PRODUCT_ID", - quantity: "YOUR_PRODUCT_QUANTITY", - }, - ], - }), - }); - - const orderData = await response.json(); - - if (orderData.id) { - return orderData.id; - } else { - const errorDetail = orderData?.details?.[0]; - const errorMessage = errorDetail - ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` - : JSON.stringify(orderData); - - throw new Error(errorMessage); - } - } catch (error) { - console.error(error); - resultMessage(`Could not initiate PayPal Checkout...

${error}`); - } -} - -async function onApproveCallback(data, actions) { - try { - const response = await fetch(`/api/orders/${data.orderID}/capture`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - }); - - const orderData = await response.json(); - // Three cases to handle: - // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() - // (2) Other non-recoverable errors -> Show a failure message - // (3) Successful transaction -> Show confirmation or thank you message - - const transaction = - orderData?.purchase_units?.[0]?.payments?.captures?.[0] || - orderData?.purchase_units?.[0]?.payments?.authorizations?.[0]; - const errorDetail = orderData?.details?.[0]; - - // this actions.restart() behavior only applies to the Buttons component - if (errorDetail?.issue === "INSTRUMENT_DECLINED" && !data.card && actions) { - // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() - // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ - return actions.restart(); - } else if ( - errorDetail || - !transaction || - transaction.status === "DECLINED" - ) { - // (2) Other non-recoverable errors -> Show a failure message - let errorMessage; - if (transaction) { - errorMessage = `Transaction ${transaction.status}: ${transaction.id}`; - } else if (errorDetail) { - errorMessage = `${errorDetail.description} (${orderData.debug_id})`; - } else { - errorMessage = JSON.stringify(orderData); - } - - throw new Error(errorMessage); - } else { - // (3) Successful transaction -> Show confirmation or thank you message - // Or go to another URL: actions.redirect('thank_you.html'); - resultMessage( - `Transaction ${transaction.status}: ${transaction.id}

See console for all available details`, - ); - console.log( - "Capture result", - orderData, - JSON.stringify(orderData, null, 2), - ); - } - } catch (error) { - console.error(error); - resultMessage( - `Sorry, your transaction could not be processed...

${error}`, - ); - } -} - -window.paypal - .Buttons({ - createOrder: createOrderCallback, - onApprove: onApproveCallback, - }) - .render("#paypal-button-container"); - -// Example function to show a result to the user. Your site's UI library can be used instead. -function resultMessage(message) { - const container = document.querySelector("#result-message"); - container.innerHTML = message; -} - -// If this returns false or the card fields aren't visible, see Step #1. -if (window.paypal.HostedFields.isEligible()) { - // Renders card fields - window.paypal.HostedFields.render({ - // Call your server to set up the transaction - createOrder: createOrderCallback, - styles: { - ".valid": { - color: "green", - }, - ".invalid": { - color: "red", - }, - }, - fields: { - number: { - selector: "#card-number", - placeholder: "4111 1111 1111 1111", - }, - cvv: { - selector: "#cvv", - placeholder: "123", - }, - expirationDate: { - selector: "#expiration-date", - placeholder: "MM/YY", - }, - }, - }).then((cardFields) => { - document.querySelector("#card-form").addEventListener("submit", (event) => { - event.preventDefault(); - cardFields - .submit({ - // Cardholder's first and last name - cardholderName: document.getElementById("card-holder-name").value, - // Billing Address - billingAddress: { - // Street address, line 1 - streetAddress: document.getElementById( - "card-billing-address-street", - ).value, - // Street address, line 2 (Ex: Unit, Apartment, etc.) - extendedAddress: document.getElementById( - "card-billing-address-unit", - ).value, - // State - region: document.getElementById("card-billing-address-state").value, - // City - locality: document.getElementById("card-billing-address-city") - .value, - // Postal Code - postalCode: document.getElementById("card-billing-address-zip") - .value, - // Country Code - countryCodeAlpha2: document.getElementById( - "card-billing-address-country", - ).value, - }, - }) - .then((data) => { - return onApproveCallback(data); - }) - .catch((orderData) => { - resultMessage( - `Sorry, your transaction could not be processed...

${JSON.stringify( - orderData, - )}`, - ); - }); - }); - }); -} else { - // Hides card fields if the merchant isn't eligible - document.querySelector("#card-form").style = "display: none"; -} diff --git a/advanced-integration/.env.example b/advanced-integration/v1/env.example similarity index 100% rename from advanced-integration/.env.example rename to advanced-integration/v1/env.example diff --git a/advanced-integration/v1/package.json b/advanced-integration/v1/package.json index ff3f5b41..d17aa000 100644 --- a/advanced-integration/v1/package.json +++ b/advanced-integration/v1/package.json @@ -6,10 +6,10 @@ "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon server/server.js", + "start": "nodemon server.js", "format": "npx prettier --write **/*.{js,md}", "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + "lint": "npx eslint server.js paypal-api.js --env=node && npx eslint public/*.js --env=browser" }, "license": "Apache-2.0", "dependencies": { diff --git a/advanced-integration/paypal-api.js b/advanced-integration/v1/paypal-api.js similarity index 100% rename from advanced-integration/paypal-api.js rename to advanced-integration/v1/paypal-api.js diff --git a/advanced-integration/public/app.js b/advanced-integration/v1/public/app.js similarity index 100% rename from advanced-integration/public/app.js rename to advanced-integration/v1/public/app.js diff --git a/advanced-integration/server.js b/advanced-integration/v1/server.js similarity index 100% rename from advanced-integration/server.js rename to advanced-integration/v1/server.js diff --git a/advanced-integration/v1/server/server.js b/advanced-integration/v1/server/server.js deleted file mode 100644 index a7d84407..00000000 --- a/advanced-integration/v1/server/server.js +++ /dev/null @@ -1,178 +0,0 @@ -import express from "express"; -import fetch from "node-fetch"; -import "dotenv/config"; - -const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8888 } = process.env; -const base = "https://api-m.sandbox.paypal.com"; -const app = express(); -app.set("view engine", "ejs"); -app.set("views", "./server/views"); -app.use(express.static("client")); - -// parse post params sent in body in json format -app.use(express.json()); - -/** - * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs. - * @see https://developer.paypal.com/api/rest/authentication/ - */ -const generateAccessToken = async () => { - try { - if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) { - throw new Error("MISSING_API_CREDENTIALS"); - } - const auth = Buffer.from( - PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET, - ).toString("base64"); - const response = await fetch(`${base}/v1/oauth2/token`, { - method: "POST", - body: "grant_type=client_credentials", - headers: { - Authorization: `Basic ${auth}`, - }, - }); - - const data = await response.json(); - return data.access_token; - } catch (error) { - console.error("Failed to generate Access Token:", error); - } -}; - -/** - * Generate a client token for rendering the hosted card fields. - * @see https://developer.paypal.com/docs/checkout/advanced/integrate/#link-integratebackend - */ -const generateClientToken = async () => { - const accessToken = await generateAccessToken(); - const url = `${base}/v1/identity/generate-token`; - const response = await fetch(url, { - method: "POST", - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Language": "en_US", - "Content-Type": "application/json", - }, - }); - - return handleResponse(response); -}; - -/** - * Create an order to start the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create - */ -const createOrder = async (cart) => { - // use the cart information passed from the front-end to calculate the purchase unit details - console.log( - "shopping cart information passed from the frontend createOrder() callback:", - cart, - ); - - const accessToken = await generateAccessToken(); - const url = `${base}/v2/checkout/orders`; - const payload = { - intent: "CAPTURE", - purchase_units: [ - { - amount: { - currency_code: "USD", - value: "100.00", - }, - }, - ], - }; - - const response = await fetch(url, { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: - // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ - // "PayPal-Mock-Response": '{"mock_application_codes": "MISSING_REQUIRED_PARAMETER"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "PERMISSION_DENIED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' - }, - method: "POST", - body: JSON.stringify(payload), - }); - - return handleResponse(response); -}; - -/** - * Capture payment for the created order to complete the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture - */ -const captureOrder = async (orderID) => { - const accessToken = await generateAccessToken(); - const url = `${base}/v2/checkout/orders/${orderID}/capture`; - - const response = await fetch(url, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: - // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ - // "PayPal-Mock-Response": '{"mock_application_codes": "INSTRUMENT_DECLINED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "TRANSACTION_REFUSED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' - }, - }); - - return handleResponse(response); -}; - -async function handleResponse(response) { - try { - const jsonResponse = await response.json(); - return { - jsonResponse, - httpStatusCode: response.status, - }; - } catch (err) { - const errorMessage = await response.text(); - throw new Error(errorMessage); - } -} - -// render checkout page with client id & unique client token -app.get("/", async (req, res) => { - try { - const { jsonResponse } = await generateClientToken(); - res.render("checkout", { - clientId: PAYPAL_CLIENT_ID, - clientToken: jsonResponse.client_token, - }); - } catch (err) { - res.status(500).send(err.message); - } -}); - -app.post("/api/orders", async (req, res) => { - try { - // use the cart information passed from the front-end to calculate the order amount detals - const { cart } = req.body; - const { jsonResponse, httpStatusCode } = await createOrder(cart); - res.status(httpStatusCode).json(jsonResponse); - } catch (error) { - console.error("Failed to create order:", error); - res.status(500).json({ error: "Failed to create order." }); - } -}); - -app.post("/api/orders/:orderID/capture", async (req, res) => { - try { - const { orderID } = req.params; - const { jsonResponse, httpStatusCode } = await captureOrder(orderID); - res.status(httpStatusCode).json(jsonResponse); - } catch (error) { - console.error("Failed to create order:", error); - res.status(500).json({ error: "Failed to capture order." }); - } -}); - -app.listen(PORT, () => { - console.log(`Node server listening at http://localhost:${PORT}/`); -}); diff --git a/advanced-integration/v1/server/views/checkout.ejs b/advanced-integration/v1/views/checkout.ejs similarity index 88% rename from advanced-integration/v1/server/views/checkout.ejs rename to advanced-integration/v1/views/checkout.ejs index 85cd7085..12522326 100644 --- a/advanced-integration/v1/server/views/checkout.ejs +++ b/advanced-integration/v1/views/checkout.ejs @@ -1,14 +1,12 @@ - - + - - - PayPal JS SDK Advanced Integration + + + /> diff --git a/advanced-integration/beta/.env.example b/advanced-integration/v2/.env.example similarity index 100% rename from advanced-integration/beta/.env.example rename to advanced-integration/v2/.env.example diff --git a/advanced-integration/v2/README.md b/advanced-integration/v2/README.md new file mode 100644 index 00000000..fc665be3 --- /dev/null +++ b/advanced-integration/v2/README.md @@ -0,0 +1,23 @@ +# Advanced Integration Example + +This folder contains example code for [version 2](https://developer.paypal.com/docs/checkout/advanced/integrate/) of a PayPal advanced Checkout integration using the JavaScript SDK and Node.js to complete transactions with the PayPal REST API. + +Version 2 is the current advanced Checkout integration, and includes hosted card fields. + +## Instructions + +1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create) +2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. +3. Replace `test` in [client/checkout.html](client/checkout.html) with your app's client-id +4. Run `npm install` +5. Run `npm start` +6. Open http://localhost:8888 +7. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) + +## Examples + +The documentation for advanced Checkout integration using JavaScript SDK includes additional sample code in the following sections: + +* **3. Adding PayPal buttons and card fields** includes [a full-stack Node.js example](v2/examples/full-stack/). +* **4. Call Orders API for PayPal buttons and card fields** includes [a server-side example](v2/examples/call-orders-api-server-side/) +* **5. Capture order** includes [a server-side example](v2/examples/capture-order-server-side/) diff --git a/advanced-integration/beta/client/checkout.html b/advanced-integration/v2/client/checkout.html similarity index 100% rename from advanced-integration/beta/client/checkout.html rename to advanced-integration/v2/client/checkout.html diff --git a/advanced-integration/beta/client/checkout.js b/advanced-integration/v2/client/checkout.js similarity index 100% rename from advanced-integration/beta/client/checkout.js rename to advanced-integration/v2/client/checkout.js diff --git a/advanced-integration/beta/package.json b/advanced-integration/v2/package.json similarity index 100% rename from advanced-integration/beta/package.json rename to advanced-integration/v2/package.json diff --git a/advanced-integration/beta/server/server.js b/advanced-integration/v2/server/server.js similarity index 100% rename from advanced-integration/beta/server/server.js rename to advanced-integration/v2/server/server.js From 8895d079bd2077b913d2d901dcd9154e04366ab2 Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Tue, 24 Oct 2023 15:42:21 -0500 Subject: [PATCH 14/34] Update codespaces links to support v1 and v2 (#89) --- .../advanced-integration/devcontainer.json | 40 ------------------- .../advanced-integration/welcome-message.sh | 23 ----------- README.md | 3 +- 3 files changed, 2 insertions(+), 64 deletions(-) delete mode 100644 .devcontainer/advanced-integration/devcontainer.json delete mode 100644 .devcontainer/advanced-integration/welcome-message.sh diff --git a/.devcontainer/advanced-integration/devcontainer.json b/.devcontainer/advanced-integration/devcontainer.json deleted file mode 100644 index 2e840f6f..00000000 --- a/.devcontainer/advanced-integration/devcontainer.json +++ /dev/null @@ -1,40 +0,0 @@ -// For more details, see https://aka.ms/devcontainer.json. -{ - "name": "PayPal Advanced Integration", - "image": "mcr.microsoft.com/devcontainers/javascript-node:20", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration", - // Use 'onCreateCommand' to run commands when creating the container. - "onCreateCommand": "bash ../.devcontainer/advanced-integration/welcome-message.sh", - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "npm install", - // Use 'postAttachCommand' to run commands when attaching to the container. - "postAttachCommand": { - "Start server": "npm start" - }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - "forwardPorts": [8888], - "portsAttributes": { - "8888": { - "label": "Preview of Advanced Checkout Flow", - "onAutoForward": "openBrowserOnce" - } - }, - "secrets": { - "PAYPAL_CLIENT_ID": { - "description": "Sandbox client ID of the application.", - "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" - }, - "PAYPAL_CLIENT_SECRET": { - "description": "Sandbox secret of the application.", - "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" - } - }, - "customizations": { - "vscode": { - "extensions": ["vsls-contrib.codetour"], - "settings": { - "git.openRepositoryInParentFolders": "always" - } - } - } -} diff --git a/.devcontainer/advanced-integration/welcome-message.sh b/.devcontainer/advanced-integration/welcome-message.sh deleted file mode 100644 index ae9a72f9..00000000 --- a/.devcontainer/advanced-integration/welcome-message.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -set -e - -WELCOME_MESSAGE=" -👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" - -🛠️ Your environment is fully setup with all the required software. - -🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." - -ALTERNATE_WELCOME_MESSAGE=" -👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" - -🛠️ Your environment is fully setup with all the required software. - -🚀 The checkout page will automatically open in the browser after the server is started." - -if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then - WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" -fi - -sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/README.md b/README.md index b0bba29e..6a5e4692 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,8 @@ PayPal codespaces require a client ID and client secret for your app. | Application | Codespaces Link | | ---- | ---- | -| Advanced Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration%2Fdevcontainer.json)| +| Advanced Integration v2 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration-v2%2Fdevcontainer.json)| +| Advanced Integration v1 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration-v1%2Fdevcontainer.json)| | Standard Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fstandard-integration%2Fdevcontainer.json)| ### Learn more From 91683d348eb0235f101e22d7a94788bd9cf8770b Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Tue, 24 Oct 2023 15:47:32 -0500 Subject: [PATCH 15/34] Clean up advanced-integration directory (#90) --- advanced-integration/v1/package.json | 2 +- advanced-integration/{ => v2}/.gitignore | 0 advanced-integration/views/checkout.ejs | 101 ----------------------- 3 files changed, 1 insertion(+), 102 deletions(-) rename advanced-integration/{ => v2}/.gitignore (100%) delete mode 100644 advanced-integration/views/checkout.ejs diff --git a/advanced-integration/v1/package.json b/advanced-integration/v1/package.json index d17aa000..e1b47190 100644 --- a/advanced-integration/v1/package.json +++ b/advanced-integration/v1/package.json @@ -2,7 +2,7 @@ "name": "paypal-advanced-integration", "description": "Sample Node.js web app to integrate PayPal Advanced Checkout for online payments", "version": "1.0.0", - "main": "server/server.js", + "main": "server.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/advanced-integration/.gitignore b/advanced-integration/v2/.gitignore similarity index 100% rename from advanced-integration/.gitignore rename to advanced-integration/v2/.gitignore diff --git a/advanced-integration/views/checkout.ejs b/advanced-integration/views/checkout.ejs deleted file mode 100644 index 12522326..00000000 --- a/advanced-integration/views/checkout.ejs +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - -
-
-
- -
-
-
- -
-
-
- -
-
-
- - -
- - -
-
- - -
-
- -
-
- -
-
- -
-
- -
-

- -
-
- - - From e453180421cfaa9359ccf0cd5531318074c17af6 Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Wed, 25 Oct 2023 10:01:12 -0500 Subject: [PATCH 16/34] Fix codespace path for advanced integration v2 (#92) --- .devcontainer/advanced-integration-v2/devcontainer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/advanced-integration-v2/devcontainer.json b/.devcontainer/advanced-integration-v2/devcontainer.json index b3a54490..703549f5 100644 --- a/.devcontainer/advanced-integration-v2/devcontainer.json +++ b/.devcontainer/advanced-integration-v2/devcontainer.json @@ -2,9 +2,9 @@ { "name": "PayPal Advanced Integration (v2)", "image": "mcr.microsoft.com/devcontainers/javascript-node:20", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/beta", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/v2", // Use 'onCreateCommand' to run commands when creating the container. - "onCreateCommand": "bash ../../.devcontainer/advanced-integration-beta/welcome-message.sh", + "onCreateCommand": "bash ../../.devcontainer/advanced-integration-v2/welcome-message.sh", // Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "npm install", // Use 'postAttachCommand' to run commands when attaching to the container. From c4ee30fb101f3b2ea4a3665a37c7beca65fb02b5 Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Wed, 25 Oct 2023 12:14:00 -0500 Subject: [PATCH 17/34] Add ejs to better match the v2 advanced integration docs (#93) --- advanced-integration/v2/README.md | 6 +++--- advanced-integration/v2/package.json | 1 + advanced-integration/v2/server/server.js | 16 ++++++++++++---- .../checkout.html => server/views/checkout.ejs} | 3 +-- 4 files changed, 17 insertions(+), 9 deletions(-) rename advanced-integration/v2/{client/checkout.html => server/views/checkout.ejs} (89%) diff --git a/advanced-integration/v2/README.md b/advanced-integration/v2/README.md index fc665be3..2cf823b0 100644 --- a/advanced-integration/v2/README.md +++ b/advanced-integration/v2/README.md @@ -18,6 +18,6 @@ Version 2 is the current advanced Checkout integration, and includes hosted card The documentation for advanced Checkout integration using JavaScript SDK includes additional sample code in the following sections: -* **3. Adding PayPal buttons and card fields** includes [a full-stack Node.js example](v2/examples/full-stack/). -* **4. Call Orders API for PayPal buttons and card fields** includes [a server-side example](v2/examples/call-orders-api-server-side/) -* **5. Capture order** includes [a server-side example](v2/examples/capture-order-server-side/) +- **3. Adding PayPal buttons and card fields** includes [a full-stack Node.js example](v2/examples/full-stack/). +- **4. Call Orders API for PayPal buttons and card fields** includes [a server-side example](v2/examples/call-orders-api-server-side/) +- **5. Capture order** includes [a server-side example](v2/examples/capture-order-server-side/) diff --git a/advanced-integration/v2/package.json b/advanced-integration/v2/package.json index c87347ac..ff3f5b41 100644 --- a/advanced-integration/v2/package.json +++ b/advanced-integration/v2/package.json @@ -14,6 +14,7 @@ "license": "Apache-2.0", "dependencies": { "dotenv": "^16.3.1", + "ejs": "^3.1.9", "express": "^4.18.2", "node-fetch": "^3.3.2" }, diff --git a/advanced-integration/v2/server/server.js b/advanced-integration/v2/server/server.js index 0d8d3cb8..f1188758 100644 --- a/advanced-integration/v2/server/server.js +++ b/advanced-integration/v2/server/server.js @@ -1,12 +1,14 @@ import express from "express"; import fetch from "node-fetch"; import "dotenv/config"; -import path from "path"; const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8888 } = process.env; const base = "https://api-m.sandbox.paypal.com"; const app = express(); +app.set("view engine", "ejs"); +app.set("views", "./server/views"); + // host static files app.use(express.static("client")); @@ -142,9 +144,15 @@ app.post("/api/orders/:orderID/capture", async (req, res) => { } }); -// serve index.html -app.get("/", (req, res) => { - res.sendFile(path.resolve("./client/checkout.html")); +// render checkout page with client id & unique client token +app.get("/", async (req, res) => { + try { + res.render("checkout", { + clientId: PAYPAL_CLIENT_ID, + }); + } catch (err) { + res.status(500).send(err.message); + } }); app.listen(PORT, () => { diff --git a/advanced-integration/v2/client/checkout.html b/advanced-integration/v2/server/views/checkout.ejs similarity index 89% rename from advanced-integration/v2/client/checkout.html rename to advanced-integration/v2/server/views/checkout.ejs index cbc61169..2b685ad6 100644 --- a/advanced-integration/v2/client/checkout.html +++ b/advanced-integration/v2/server/views/checkout.ejs @@ -17,8 +17,7 @@

- - + From 4603a5180889611fe9f66acd6c89e03b34576e02 Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Thu, 26 Oct 2023 09:58:18 -0500 Subject: [PATCH 18/34] Update instructions for v2 card fields (#97) --- advanced-integration/v2/README.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/advanced-integration/v2/README.md b/advanced-integration/v2/README.md index 2cf823b0..40cd1bd6 100644 --- a/advanced-integration/v2/README.md +++ b/advanced-integration/v2/README.md @@ -8,16 +8,7 @@ Version 2 is the current advanced Checkout integration, and includes hosted card 1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create) 2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. -3. Replace `test` in [client/checkout.html](client/checkout.html) with your app's client-id -4. Run `npm install` -5. Run `npm start` -6. Open http://localhost:8888 -7. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) - -## Examples - -The documentation for advanced Checkout integration using JavaScript SDK includes additional sample code in the following sections: - -- **3. Adding PayPal buttons and card fields** includes [a full-stack Node.js example](v2/examples/full-stack/). -- **4. Call Orders API for PayPal buttons and card fields** includes [a server-side example](v2/examples/call-orders-api-server-side/) -- **5. Capture order** includes [a server-side example](v2/examples/capture-order-server-side/) +3. Run `npm install` +4. Run `npm start` +5. Open http://localhost:8888 +6. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) From 4f82e502daad966285dcc49f1f21eae059e33764 Mon Sep 17 00:00:00 2001 From: Jesse Shawl Date: Mon, 13 Nov 2023 15:34:15 -0600 Subject: [PATCH 19/34] feat: add example for saving a payment method (#99) --- save-payment-method/.env.example | 5 + save-payment-method/.gitignore | 1 + save-payment-method/README.md | 15 ++ save-payment-method/client/app.js | 97 +++++++++ save-payment-method/package.json | 24 +++ save-payment-method/server/server.js | 193 ++++++++++++++++++ save-payment-method/server/views/checkout.ejs | 17 ++ 7 files changed, 352 insertions(+) create mode 100644 save-payment-method/.env.example create mode 100644 save-payment-method/.gitignore create mode 100644 save-payment-method/README.md create mode 100644 save-payment-method/client/app.js create mode 100644 save-payment-method/package.json create mode 100644 save-payment-method/server/server.js create mode 100644 save-payment-method/server/views/checkout.ejs diff --git a/save-payment-method/.env.example b/save-payment-method/.env.example new file mode 100644 index 00000000..2251fbbb --- /dev/null +++ b/save-payment-method/.env.example @@ -0,0 +1,5 @@ +# Create an application to obtain credentials at +# https://developer.paypal.com/dashboard/applications/sandbox + +PAYPAL_CLIENT_ID=YOUR_CLIENT_ID_GOES_HERE +PAYPAL_CLIENT_SECRET=YOUR_SECRET_GOES_HERE diff --git a/save-payment-method/.gitignore b/save-payment-method/.gitignore new file mode 100644 index 00000000..4c49bd78 --- /dev/null +++ b/save-payment-method/.gitignore @@ -0,0 +1 @@ +.env diff --git a/save-payment-method/README.md b/save-payment-method/README.md new file mode 100644 index 00000000..f1f4a0e9 --- /dev/null +++ b/save-payment-method/README.md @@ -0,0 +1,15 @@ +# Save Payment Method Example + +This folder contains example code for a PayPal Save Payment Method integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API. + +[View the Documentation](https://developer.paypal.com/docs/checkout/save-payment-methods/during-purchase/js-sdk/paypal/) + +## Instructions + +1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create) +2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET` +3. Replace `test` in [client/app.js](client/app.js) with your app's client-id +4. Run `npm install` +5. Run `npm start` +6. Open http://localhost:8888 +7. Click "PayPal" and log in with one of your [Sandbox test accounts](https://developer.paypal.com/dashboard/accounts) diff --git a/save-payment-method/client/app.js b/save-payment-method/client/app.js new file mode 100644 index 00000000..eebd2017 --- /dev/null +++ b/save-payment-method/client/app.js @@ -0,0 +1,97 @@ +window.paypal + .Buttons({ + async createOrder() { + try { + const response = await fetch("/api/orders", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + // use the "body" param to optionally pass additional order information + // like product ids and quantities + body: JSON.stringify({ + cart: [ + { + id: "YOUR_PRODUCT_ID", + quantity: "YOUR_PRODUCT_QUANTITY", + }, + ], + }), + }); + + const orderData = await response.json(); + + if (orderData.id) { + return orderData.id; + } else { + const errorDetail = orderData?.details?.[0]; + const errorMessage = errorDetail + ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` + : JSON.stringify(orderData); + + throw new Error(errorMessage); + } + } catch (error) { + console.error(error); + resultMessage(`Could not initiate PayPal Checkout...

${error}`); + } + }, + async onApprove(data, actions) { + try { + const response = await fetch(`/api/orders/${data.orderID}/capture`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }); + + const orderData = await response.json(); + // Three cases to handle: + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // (2) Other non-recoverable errors -> Show a failure message + // (3) Successful transaction -> Show confirmation or thank you message + + const errorDetail = orderData?.details?.[0]; + + if (errorDetail?.issue === "INSTRUMENT_DECLINED") { + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ + return actions.restart(); + } else if (errorDetail) { + // (2) Other non-recoverable errors -> Show a failure message + throw new Error(`${errorDetail.description} (${orderData.debug_id})`); + } else if (!orderData.purchase_units) { + throw new Error(JSON.stringify(orderData)); + } else { + // (3) Successful transaction -> Show confirmation or thank you message + // Or go to another URL: actions.redirect('thank_you.html'); + const transaction = + orderData?.purchase_units?.[0]?.payments?.captures?.[0] || + orderData?.purchase_units?.[0]?.payments?.authorizations?.[0]; + resultMessage( + `Transaction ${transaction.status}: ${transaction.id}

See console for all available details.
+ See the return buyer experience + `, + ); + + console.log( + "Capture result", + orderData, + JSON.stringify(orderData, null, 2), + ); + } + } catch (error) { + console.error(error); + resultMessage( + `Sorry, your transaction could not be processed...

${error}`, + ); + } + }, + }) + .render("#paypal-button-container"); + +// Example function to show a result to the user. Your site's UI library can be used instead. +function resultMessage(message) { + const container = document.querySelector("#result-message"); + container.innerHTML = message; +} diff --git a/save-payment-method/package.json b/save-payment-method/package.json new file mode 100644 index 00000000..858c68af --- /dev/null +++ b/save-payment-method/package.json @@ -0,0 +1,24 @@ +{ + "name": "paypal-save-payment-method", + "description": "Sample Node.js web app to integrate PayPal Save Payment Method for online payments", + "version": "1.0.0", + "main": "server/server.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "nodemon server/server.js", + "format": "npx prettier --write **/*.{js,md}", + "format:check": "npx prettier --check **/*.{js,md}", + "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + }, + "license": "Apache-2.0", + "dependencies": { + "dotenv": "^16.3.1", + "ejs": "^3.1.9", + "express": "^4.18.2", + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" + } +} diff --git a/save-payment-method/server/server.js b/save-payment-method/server/server.js new file mode 100644 index 00000000..7d2596f2 --- /dev/null +++ b/save-payment-method/server/server.js @@ -0,0 +1,193 @@ +import express from "express"; +import fetch from "node-fetch"; +import "dotenv/config"; + +const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8888 } = process.env; +const base = "https://api-m.sandbox.paypal.com"; +const app = express(); + +app.set("view engine", "ejs"); +app.set("views", "./server/views"); + +// host static files +app.use(express.static("client")); + +// parse post params sent in body in json format +app.use(express.json()); + +/** + * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs. + * @see https://developer.paypal.com/api/rest/authentication/ + */ +const authenticate = async (bodyParams) => { + const params = { + grant_type: "client_credentials", + response_type: "id_token", + ...bodyParams, + }; + + // pass the url encoded value as the body of the post call + const urlEncodedParams = new URLSearchParams(params).toString(); + try { + if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) { + throw new Error("MISSING_API_CREDENTIALS"); + } + const auth = Buffer.from( + PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET, + ).toString("base64"); + + const response = await fetch(`${base}/v1/oauth2/token`, { + method: "POST", + body: urlEncodedParams, + headers: { + Authorization: `Basic ${auth}`, + }, + }); + return handleResponse(response); + } catch (error) { + console.error("Failed to generate Access Token:", error); + } +}; + +const generateAccessToken = async () => { + const { jsonResponse } = await authenticate(); + return jsonResponse.access_token; +}; + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +const createOrder = async (cart) => { + // use the cart information passed from the front-end to calculate the purchase unit details + console.log( + "shopping cart information passed from the frontend createOrder() callback:", + cart, + ); + + const accessToken = await generateAccessToken(); + const url = `${base}/v2/checkout/orders`; + const payload = { + intent: "CAPTURE", + purchase_units: [ + { + amount: { + currency_code: "USD", + value: "110.00", + }, + }, + ], + payment_source: { + paypal: { + attributes: { + vault: { + store_in_vault: "ON_SUCCESS", + usage_type: "MERCHANT", + customer_type: "CONSUMER", + }, + }, + experience_context: { + return_url: "http://example.com", + cancel_url: "http://example.com", + shipping_preference: "NO_SHIPPING", + }, + }, + }, + }; + + const response = await fetch(url, { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: + // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ + // "PayPal-Mock-Response": '{"mock_application_codes": "MISSING_REQUIRED_PARAMETER"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "PERMISSION_DENIED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' + }, + method: "POST", + body: JSON.stringify(payload), + }); + + return handleResponse(response); +}; + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +const captureOrder = async (orderID) => { + const accessToken = await generateAccessToken(); + const url = `${base}/v2/checkout/orders/${orderID}/capture`; + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: + // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ + // "PayPal-Mock-Response": '{"mock_application_codes": "INSTRUMENT_DECLINED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "TRANSACTION_REFUSED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' + }, + }); + + return handleResponse(response); +}; + +async function handleResponse(response) { + try { + const jsonResponse = await response.json(); + return { + jsonResponse, + httpStatusCode: response.status, + }; + } catch (err) { + const errorMessage = await response.text(); + throw new Error(errorMessage); + } +} + +app.post("/api/orders", async (req, res) => { + try { + // use the cart information passed from the front-end to calculate the order amount detals + const { cart } = req.body; + const { jsonResponse, httpStatusCode } = await createOrder(cart); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to create order." }); + } +}); + +app.post("/api/orders/:orderID/capture", async (req, res) => { + try { + const { orderID } = req.params; + const { jsonResponse, httpStatusCode } = await captureOrder(orderID); + console.log("capture response", jsonResponse); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to capture order." }); + } +}); + +// render checkout page with client id & user id token +app.get("/", async (req, res) => { + try { + const { jsonResponse } = await authenticate({ + target_customer_id: req.query.customerID, + }); + res.render("checkout", { + clientId: PAYPAL_CLIENT_ID, + userIdToken: jsonResponse.id_token, + }); + } catch (err) { + res.status(500).send(err.message); + } +}); + +app.listen(PORT, () => { + console.log(`Node server listening at http://localhost:${PORT}/`); +}); diff --git a/save-payment-method/server/views/checkout.ejs b/save-payment-method/server/views/checkout.ejs new file mode 100644 index 00000000..fa995630 --- /dev/null +++ b/save-payment-method/server/views/checkout.ejs @@ -0,0 +1,17 @@ + + + + + + PayPal JS SDK Save Payment Method Integration + + +
+

+ + + + From 31e5b51e67e693ca802ae54a8fb25287bbf69ec7 Mon Sep 17 00:00:00 2001 From: Navinkumar Patil <134013160+NavinPayPal@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:28:54 -0800 Subject: [PATCH 20/34] Update devcontainer.json with paypal vs code extension (#106) --- .devcontainer/advanced-integration-v2/devcontainer.json | 2 +- .devcontainer/standard-integration/devcontainer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/advanced-integration-v2/devcontainer.json b/.devcontainer/advanced-integration-v2/devcontainer.json index 703549f5..9a4ab9ac 100644 --- a/.devcontainer/advanced-integration-v2/devcontainer.json +++ b/.devcontainer/advanced-integration-v2/devcontainer.json @@ -31,7 +31,7 @@ }, "customizations": { "vscode": { - "extensions": ["vsls-contrib.codetour"], + "extensions": ["vsls-contrib.codetour","PayPal.vscode-paypal"], "settings": { "git.openRepositoryInParentFolders": "always" } diff --git a/.devcontainer/standard-integration/devcontainer.json b/.devcontainer/standard-integration/devcontainer.json index 846dd982..c6d0ffec 100644 --- a/.devcontainer/standard-integration/devcontainer.json +++ b/.devcontainer/standard-integration/devcontainer.json @@ -31,7 +31,7 @@ }, "customizations": { "vscode": { - "extensions": ["vsls-contrib.codetour"], + "extensions": ["vsls-contrib.codetour","PayPal.vscode-paypal"], "settings": { "git.openRepositoryInParentFolders": "always" } From 6419cb99349318f6eb89e657779b9f8c769cfe4d Mon Sep 17 00:00:00 2001 From: Greg Jopa <534034+gregjopa@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:45:54 -0600 Subject: [PATCH 21/34] Update hosted-fields example to new standards (#109) --- advanced-integration/v1/client/app.js | 186 ++++++++++++++++++ advanced-integration/v1/package.json | 6 +- advanced-integration/v1/paypal-api.js | 100 ---------- advanced-integration/v1/public/app.js | 160 --------------- advanced-integration/v1/server.js | 44 ----- advanced-integration/v1/server/server.js | 178 +++++++++++++++++ .../v1/server/views/checkout.ejs | 104 ++++++++++ 7 files changed, 471 insertions(+), 307 deletions(-) create mode 100644 advanced-integration/v1/client/app.js delete mode 100644 advanced-integration/v1/paypal-api.js delete mode 100644 advanced-integration/v1/public/app.js delete mode 100644 advanced-integration/v1/server.js create mode 100644 advanced-integration/v1/server/server.js create mode 100644 advanced-integration/v1/server/views/checkout.ejs diff --git a/advanced-integration/v1/client/app.js b/advanced-integration/v1/client/app.js new file mode 100644 index 00000000..65f048d7 --- /dev/null +++ b/advanced-integration/v1/client/app.js @@ -0,0 +1,186 @@ +async function createOrderCallback() { + try { + const response = await fetch("/api/orders", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + // use the "body" param to optionally pass additional order information + // like product ids and quantities + body: JSON.stringify({ + cart: [ + { + id: "YOUR_PRODUCT_ID", + quantity: "YOUR_PRODUCT_QUANTITY", + }, + ], + }), + }); + + const orderData = await response.json(); + + if (orderData.id) { + return orderData.id; + } else { + const errorDetail = orderData?.details?.[0]; + const errorMessage = errorDetail + ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` + : JSON.stringify(orderData); + + throw new Error(errorMessage); + } + } catch (error) { + console.error(error); + resultMessage(`Could not initiate PayPal Checkout...

${error}`); + } +} + +async function onApproveCallback(data, actions) { + try { + const response = await fetch(`/api/orders/${data.orderID}/capture`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }); + + const orderData = await response.json(); + // Three cases to handle: + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // (2) Other non-recoverable errors -> Show a failure message + // (3) Successful transaction -> Show confirmation or thank you message + + const transaction = + orderData?.purchase_units?.[0]?.payments?.captures?.[0] || + orderData?.purchase_units?.[0]?.payments?.authorizations?.[0]; + const errorDetail = orderData?.details?.[0]; + + // this actions.restart() behavior only applies to the Buttons component + if (errorDetail?.issue === "INSTRUMENT_DECLINED" && !data.card && actions) { + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ + return actions.restart(); + } else if ( + errorDetail || + !transaction || + transaction.status === "DECLINED" + ) { + // (2) Other non-recoverable errors -> Show a failure message + let errorMessage; + if (transaction) { + errorMessage = `Transaction ${transaction.status}: ${transaction.id}`; + } else if (errorDetail) { + errorMessage = `${errorDetail.description} (${orderData.debug_id})`; + } else { + errorMessage = JSON.stringify(orderData); + } + + throw new Error(errorMessage); + } else { + // (3) Successful transaction -> Show confirmation or thank you message + // Or go to another URL: actions.redirect('thank_you.html'); + resultMessage( + `Transaction ${transaction.status}: ${transaction.id}

See console for all available details`, + ); + console.log( + "Capture result", + orderData, + JSON.stringify(orderData, null, 2), + ); + } + } catch (error) { + console.error(error); + resultMessage( + `Sorry, your transaction could not be processed...

${error}`, + ); + } +} + +window.paypal + .Buttons({ + createOrder: createOrderCallback, + onApprove: onApproveCallback, + }) + .render("#paypal-button-container"); + +// Example function to show a result to the user. Your site's UI library can be used instead. +function resultMessage(message) { + const container = document.querySelector("#result-message"); + container.innerHTML = message; +} + +// If this returns false or the card fields aren't visible, see Step #1. +if (window.paypal.HostedFields.isEligible()) { + // Renders card fields + window.paypal.HostedFields.render({ + // Call your server to set up the transaction + createOrder: createOrderCallback, + styles: { + ".valid": { + color: "green", + }, + ".invalid": { + color: "red", + }, + }, + fields: { + number: { + selector: "#card-number", + placeholder: "4111 1111 1111 1111", + }, + cvv: { + selector: "#cvv", + placeholder: "123", + }, + expirationDate: { + selector: "#expiration-date", + placeholder: "MM/YY", + }, + }, + }).then((cardFields) => { + document.querySelector("#card-form").addEventListener("submit", (event) => { + event.preventDefault(); + cardFields + .submit({ + // Cardholder's first and last name + cardholderName: document.getElementById("card-holder-name").value, + // Billing Address + billingAddress: { + // Street address, line 1 + streetAddress: document.getElementById( + "card-billing-address-street", + ).value, + // Street address, line 2 (Ex: Unit, Apartment, etc.) + extendedAddress: document.getElementById( + "card-billing-address-unit", + ).value, + // State + region: document.getElementById("card-billing-address-state").value, + // City + locality: document.getElementById("card-billing-address-city") + .value, + // Postal Code + postalCode: document.getElementById("card-billing-address-zip") + .value, + // Country Code + countryCodeAlpha2: document.getElementById( + "card-billing-address-country", + ).value, + }, + }) + .then((data) => { + return onApproveCallback(data); + }) + .catch((orderData) => { + resultMessage( + `Sorry, your transaction could not be processed...

${JSON.stringify( + orderData, + )}`, + ); + }); + }); + }); +} else { + // Hides card fields if the merchant isn't eligible + document.querySelector("#card-form").style = "display: none"; +} diff --git a/advanced-integration/v1/package.json b/advanced-integration/v1/package.json index e1b47190..ff3f5b41 100644 --- a/advanced-integration/v1/package.json +++ b/advanced-integration/v1/package.json @@ -2,14 +2,14 @@ "name": "paypal-advanced-integration", "description": "Sample Node.js web app to integrate PayPal Advanced Checkout for online payments", "version": "1.0.0", - "main": "server.js", + "main": "server/server.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon server.js", + "start": "nodemon server/server.js", "format": "npx prettier --write **/*.{js,md}", "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server.js paypal-api.js --env=node && npx eslint public/*.js --env=browser" + "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" }, "license": "Apache-2.0", "dependencies": { diff --git a/advanced-integration/v1/paypal-api.js b/advanced-integration/v1/paypal-api.js deleted file mode 100644 index 6e6c8aaf..00000000 --- a/advanced-integration/v1/paypal-api.js +++ /dev/null @@ -1,100 +0,0 @@ -import fetch from "node-fetch"; - -// set some important variables -const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET } = process.env; -const base = "https://api-m.sandbox.paypal.com"; - -/** - * Create an order - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create - */ -export async function createOrder() { - const purchaseAmount = "100.00"; // TODO: pull prices from a database - const accessToken = await generateAccessToken(); - const url = `${base}/v2/checkout/orders`; - const response = await fetch(url, { - method: "post", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }, - body: JSON.stringify({ - intent: "CAPTURE", - purchase_units: [ - { - amount: { - currency_code: "USD", - value: purchaseAmount, - }, - }, - ], - }), - }); - - return handleResponse(response); -} - -/** - * Capture payment for an order - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture - */ -export async function capturePayment(orderId) { - const accessToken = await generateAccessToken(); - const url = `${base}/v2/checkout/orders/${orderId}/capture`; - const response = await fetch(url, { - method: "post", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }, - }); - - return handleResponse(response); -} - -/** - * Generate an OAuth 2.0 access token - * @see https://developer.paypal.com/api/rest/authentication/ - */ -export async function generateAccessToken() { - const auth = Buffer.from( - PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET, - ).toString("base64"); - const response = await fetch(`${base}/v1/oauth2/token`, { - method: "post", - body: "grant_type=client_credentials", - headers: { - Authorization: `Basic ${auth}`, - }, - }); - const jsonData = await handleResponse(response); - return jsonData.access_token; -} - -/** - * Generate a client token - * @see https://developer.paypal.com/docs/checkout/advanced/integrate/#link-sampleclienttokenrequest - */ -export async function generateClientToken() { - const accessToken = await generateAccessToken(); - const response = await fetch(`${base}/v1/identity/generate-token`, { - method: "post", - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Language": "en_US", - "Content-Type": "application/json", - }, - }); - console.log("response", response.status); - const jsonData = await handleResponse(response); - return jsonData.client_token; -} - -async function handleResponse(response) { - if (response.status === 200 || response.status === 201) { - return response.json(); - } - - const errorMessage = await response.text(); - throw new Error(errorMessage); -} diff --git a/advanced-integration/v1/public/app.js b/advanced-integration/v1/public/app.js deleted file mode 100644 index f475472d..00000000 --- a/advanced-integration/v1/public/app.js +++ /dev/null @@ -1,160 +0,0 @@ -window.paypal - .Buttons({ - // Sets up the transaction when a payment button is clicked - createOrder: function () { - return fetch("/api/orders", { - method: "post", - // use the "body" param to optionally pass additional order information - // like product skus and quantities - body: JSON.stringify({ - cart: [ - { - sku: "", - quantity: "", - }, - ], - }), - }) - .then((response) => response.json()) - .then((order) => order.id); - }, - // Finalize the transaction after payer approval - onApprove: function (data) { - return fetch(`/api/orders/${data.orderID}/capture`, { - method: "post", - }) - .then((response) => response.json()) - .then((orderData) => { - // Successful capture! For dev/demo purposes: - console.log( - "Capture result", - orderData, - JSON.stringify(orderData, null, 2), - ); - const transaction = orderData.purchase_units[0].payments.captures[0]; - alert(`Transaction ${transaction.status}: ${transaction.id} - - See console for all available details - `); - // When ready to go live, remove the alert and show a success message within this page. For example: - // var element = document.getElementById('paypal-button-container'); - // element.innerHTML = '

Thank you for your payment!

'; - // Or go to another URL: actions.redirect('thank_you.html'); - }); - }, - }) - .render("#paypal-button-container"); - -// If this returns false or the card fields aren't visible, see Step #1. -if (window.paypal.HostedFields.isEligible()) { - let orderId; - - // Renders card fields - window.paypal.HostedFields.render({ - // Call your server to set up the transaction - createOrder: () => { - return fetch("/api/orders", { - method: "post", - // use the "body" param to optionally pass additional order information - // like product skus and quantities - body: JSON.stringify({ - cart: [ - { - sku: "", - quantity: "", - }, - ], - }), - }) - .then((res) => res.json()) - .then((orderData) => { - orderId = orderData.id; // needed later to complete capture - return orderData.id; - }); - }, - styles: { - ".valid": { - color: "green", - }, - ".invalid": { - color: "red", - }, - }, - fields: { - number: { - selector: "#card-number", - placeholder: "4111 1111 1111 1111", - }, - cvv: { - selector: "#cvv", - placeholder: "123", - }, - expirationDate: { - selector: "#expiration-date", - placeholder: "MM/YY", - }, - }, - }).then((cardFields) => { - document.querySelector("#card-form").addEventListener("submit", (event) => { - event.preventDefault(); - cardFields - .submit({ - // Cardholder's first and last name - cardholderName: document.getElementById("card-holder-name").value, - // Billing Address - billingAddress: { - // Street address, line 1 - streetAddress: document.getElementById( - "card-billing-address-street", - ).value, - // Street address, line 2 (Ex: Unit, Apartment, etc.) - extendedAddress: document.getElementById( - "card-billing-address-unit", - ).value, - // State - region: document.getElementById("card-billing-address-state").value, - // City - locality: document.getElementById("card-billing-address-city") - .value, - // Postal Code - postalCode: document.getElementById("card-billing-address-zip") - .value, - // Country Code - countryCodeAlpha2: document.getElementById( - "card-billing-address-country", - ).value, - }, - }) - .then(() => { - fetch(`/api/orders/${orderId}/capture`, { - method: "post", - }) - .then((res) => res.json()) - .then((orderData) => { - // Two cases to handle: - // (1) Other non-recoverable errors -> Show a failure message - // (2) Successful transaction -> Show confirmation or thank you - // This example reads a v2/checkout/orders capture response, propagated from the server - // You could use a different API or structure for your 'orderData' - const errorDetail = - Array.isArray(orderData.details) && orderData.details[0]; - if (errorDetail) { - var msg = "Sorry, your transaction could not be processed."; - if (errorDetail.description) - msg += "\n\n" + errorDetail.description; - if (orderData.debug_id) msg += " (" + orderData.debug_id + ")"; - return alert(msg); // Show a failure message - } - // Show a success message or redirect - alert("Transaction completed!"); - }); - }) - .catch((err) => { - alert("Payment could not be captured! " + JSON.stringify(err)); - }); - }); - }); -} else { - // Hides card fields if the merchant isn't eligible - document.querySelector("#card-form").style = "display: none"; -} diff --git a/advanced-integration/v1/server.js b/advanced-integration/v1/server.js deleted file mode 100644 index 73076fcb..00000000 --- a/advanced-integration/v1/server.js +++ /dev/null @@ -1,44 +0,0 @@ -import "dotenv/config"; -import express from "express"; -import * as paypal from "./paypal-api.js"; -const { PORT = 8888 } = process.env; - -const app = express(); -app.set("view engine", "ejs"); -app.use(express.static("public")); - -// render checkout page with client id & unique client token -app.get("/", async (req, res) => { - const clientId = process.env.PAYPAL_CLIENT_ID; - try { - const clientToken = await paypal.generateClientToken(); - res.render("checkout", { clientId, clientToken }); - } catch (err) { - res.status(500).send(err.message); - } -}); - -// create order -app.post("/api/orders", async (req, res) => { - try { - const order = await paypal.createOrder(); - res.json(order); - } catch (err) { - res.status(500).send(err.message); - } -}); - -// capture payment -app.post("/api/orders/:orderID/capture", async (req, res) => { - const { orderID } = req.params; - try { - const captureData = await paypal.capturePayment(orderID); - res.json(captureData); - } catch (err) { - res.status(500).send(err.message); - } -}); - -app.listen(PORT, () => { - console.log(`Server listening at http://localhost:${PORT}/`); -}); diff --git a/advanced-integration/v1/server/server.js b/advanced-integration/v1/server/server.js new file mode 100644 index 00000000..a7d84407 --- /dev/null +++ b/advanced-integration/v1/server/server.js @@ -0,0 +1,178 @@ +import express from "express"; +import fetch from "node-fetch"; +import "dotenv/config"; + +const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8888 } = process.env; +const base = "https://api-m.sandbox.paypal.com"; +const app = express(); +app.set("view engine", "ejs"); +app.set("views", "./server/views"); +app.use(express.static("client")); + +// parse post params sent in body in json format +app.use(express.json()); + +/** + * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs. + * @see https://developer.paypal.com/api/rest/authentication/ + */ +const generateAccessToken = async () => { + try { + if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) { + throw new Error("MISSING_API_CREDENTIALS"); + } + const auth = Buffer.from( + PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET, + ).toString("base64"); + const response = await fetch(`${base}/v1/oauth2/token`, { + method: "POST", + body: "grant_type=client_credentials", + headers: { + Authorization: `Basic ${auth}`, + }, + }); + + const data = await response.json(); + return data.access_token; + } catch (error) { + console.error("Failed to generate Access Token:", error); + } +}; + +/** + * Generate a client token for rendering the hosted card fields. + * @see https://developer.paypal.com/docs/checkout/advanced/integrate/#link-integratebackend + */ +const generateClientToken = async () => { + const accessToken = await generateAccessToken(); + const url = `${base}/v1/identity/generate-token`; + const response = await fetch(url, { + method: "POST", + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Language": "en_US", + "Content-Type": "application/json", + }, + }); + + return handleResponse(response); +}; + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +const createOrder = async (cart) => { + // use the cart information passed from the front-end to calculate the purchase unit details + console.log( + "shopping cart information passed from the frontend createOrder() callback:", + cart, + ); + + const accessToken = await generateAccessToken(); + const url = `${base}/v2/checkout/orders`; + const payload = { + intent: "CAPTURE", + purchase_units: [ + { + amount: { + currency_code: "USD", + value: "100.00", + }, + }, + ], + }; + + const response = await fetch(url, { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: + // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ + // "PayPal-Mock-Response": '{"mock_application_codes": "MISSING_REQUIRED_PARAMETER"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "PERMISSION_DENIED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' + }, + method: "POST", + body: JSON.stringify(payload), + }); + + return handleResponse(response); +}; + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +const captureOrder = async (orderID) => { + const accessToken = await generateAccessToken(); + const url = `${base}/v2/checkout/orders/${orderID}/capture`; + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: + // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ + // "PayPal-Mock-Response": '{"mock_application_codes": "INSTRUMENT_DECLINED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "TRANSACTION_REFUSED"}' + // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' + }, + }); + + return handleResponse(response); +}; + +async function handleResponse(response) { + try { + const jsonResponse = await response.json(); + return { + jsonResponse, + httpStatusCode: response.status, + }; + } catch (err) { + const errorMessage = await response.text(); + throw new Error(errorMessage); + } +} + +// render checkout page with client id & unique client token +app.get("/", async (req, res) => { + try { + const { jsonResponse } = await generateClientToken(); + res.render("checkout", { + clientId: PAYPAL_CLIENT_ID, + clientToken: jsonResponse.client_token, + }); + } catch (err) { + res.status(500).send(err.message); + } +}); + +app.post("/api/orders", async (req, res) => { + try { + // use the cart information passed from the front-end to calculate the order amount detals + const { cart } = req.body; + const { jsonResponse, httpStatusCode } = await createOrder(cart); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to create order." }); + } +}); + +app.post("/api/orders/:orderID/capture", async (req, res) => { + try { + const { orderID } = req.params; + const { jsonResponse, httpStatusCode } = await captureOrder(orderID); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to capture order." }); + } +}); + +app.listen(PORT, () => { + console.log(`Node server listening at http://localhost:${PORT}/`); +}); diff --git a/advanced-integration/v1/server/views/checkout.ejs b/advanced-integration/v1/server/views/checkout.ejs new file mode 100644 index 00000000..85cd7085 --- /dev/null +++ b/advanced-integration/v1/server/views/checkout.ejs @@ -0,0 +1,104 @@ + + + + + + PayPal JS SDK Advanced Integration + + + + +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ + +
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+

+ +
+

+
+ + + From ecc5ab54f74b424054825b860f91accc76621fbf Mon Sep 17 00:00:00 2001 From: Navin Patil Date: Wed, 10 Jan 2024 15:04:43 -0800 Subject: [PATCH 22/34] Adding changes for devcontainer file for save payment method --- .../advanced-integration-v1/devcontainer.json | 2 +- .../save-payment-method/devcontainer.json | 40 +++++++++++++++++++ .../save-payment-method/welcome-message.sh | 23 +++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/save-payment-method/devcontainer.json create mode 100644 .devcontainer/save-payment-method/welcome-message.sh diff --git a/.devcontainer/advanced-integration-v1/devcontainer.json b/.devcontainer/advanced-integration-v1/devcontainer.json index 62758180..b8f1d538 100644 --- a/.devcontainer/advanced-integration-v1/devcontainer.json +++ b/.devcontainer/advanced-integration-v1/devcontainer.json @@ -31,7 +31,7 @@ }, "customizations": { "vscode": { - "extensions": ["vsls-contrib.codetour"], + "extensions": ["vsls-contrib.codetour","PayPal.vscode-paypal"], "settings": { "git.openRepositoryInParentFolders": "always" } diff --git a/.devcontainer/save-payment-method/devcontainer.json b/.devcontainer/save-payment-method/devcontainer.json new file mode 100644 index 00000000..c6d0ffec --- /dev/null +++ b/.devcontainer/save-payment-method/devcontainer.json @@ -0,0 +1,40 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "PayPal Standard Integration", + "image": "mcr.microsoft.com/devcontainers/javascript-node:20", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/standard-integration", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash ../.devcontainer/standard-integration/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "npm install", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": { + "Start server": "npm start" + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [8888], + "portsAttributes": { + "8888": { + "label": "Preview of Standard Checkout Flow", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "customizations": { + "vscode": { + "extensions": ["vsls-contrib.codetour","PayPal.vscode-paypal"], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + } +} diff --git a/.devcontainer/save-payment-method/welcome-message.sh b/.devcontainer/save-payment-method/welcome-message.sh new file mode 100644 index 00000000..7ed0d59c --- /dev/null +++ b/.devcontainer/save-payment-method/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Save Payment Method Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Save Payment Method Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" \ No newline at end of file From e385dc5a17baac293d6cd26615c422b43fac9406 Mon Sep 17 00:00:00 2001 From: Navin Patil Date: Wed, 10 Jan 2024 16:13:35 -0800 Subject: [PATCH 23/34] Updating Readme file to add Codespaces button --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6a5e4692..daf0636c 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ PayPal codespaces require a client ID and client secret for your app. | Advanced Integration v2 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration-v2%2Fdevcontainer.json)| | Advanced Integration v1 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fadvanced-integration-v1%2Fdevcontainer.json)| | Standard Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fstandard-integration%2Fdevcontainer.json)| +| Save Payment Method Integration | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/paypal-examples/docs-examples?devcontainer_path=.devcontainer%2Fsave-payment-method%2Fdevcontainer.json)| ### Learn more From a354698603378c88eebde44fc27edad8d3e3e78a Mon Sep 17 00:00:00 2001 From: Navin Patil Date: Tue, 16 Jan 2024 15:45:54 -0800 Subject: [PATCH 24/34] Updating the devcontainer file --- .devcontainer/save-payment-method/devcontainer.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.devcontainer/save-payment-method/devcontainer.json b/.devcontainer/save-payment-method/devcontainer.json index c6d0ffec..e3d1cede 100644 --- a/.devcontainer/save-payment-method/devcontainer.json +++ b/.devcontainer/save-payment-method/devcontainer.json @@ -1,10 +1,11 @@ + // For more details, see https://aka.ms/devcontainer.json. { - "name": "PayPal Standard Integration", + "name": "PayPal Save Payment Method", "image": "mcr.microsoft.com/devcontainers/javascript-node:20", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/standard-integration", - // Use 'onCreateCommand' to run commands when creating the container. - "onCreateCommand": "bash ../.devcontainer/standard-integration/welcome-message.sh", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/save-payment-method", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash ../.devcontainer/save-payment-method/welcome-message.sh", // Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "npm install", // Use 'postAttachCommand' to run commands when attaching to the container. @@ -15,7 +16,7 @@ "forwardPorts": [8888], "portsAttributes": { "8888": { - "label": "Preview of Standard Checkout Flow", + "label": "Preview of Save Payment Method Flow", "onAutoForward": "openBrowserOnce" } }, @@ -37,4 +38,4 @@ } } } -} +} \ No newline at end of file From a2074e9e49e0cf0bd8e98d472b0267ddc245b87d Mon Sep 17 00:00:00 2001 From: Navin Patil Date: Tue, 16 Jan 2024 16:23:54 -0800 Subject: [PATCH 25/34] Updating devcontainer file for save payment --- .devcontainer/save-payment-method/devcontainer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.devcontainer/save-payment-method/devcontainer.json b/.devcontainer/save-payment-method/devcontainer.json index e3d1cede..ec88eb6c 100644 --- a/.devcontainer/save-payment-method/devcontainer.json +++ b/.devcontainer/save-payment-method/devcontainer.json @@ -1,10 +1,9 @@ - // For more details, see https://aka.ms/devcontainer.json. { "name": "PayPal Save Payment Method", "image": "mcr.microsoft.com/devcontainers/javascript-node:20", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/save-payment-method", - // Use 'onCreateCommand' to run commands when creating the container. + // Use 'onCreateCommand' to run commands when creating the container. "onCreateCommand": "bash ../.devcontainer/save-payment-method/welcome-message.sh", // Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "npm install", From 633fe7eaca934d3931338754945ea04c8068d6c3 Mon Sep 17 00:00:00 2001 From: Jesse Shawl Date: Thu, 11 Apr 2024 16:07:55 -0500 Subject: [PATCH 26/34] fix one click payment popup issue (#126) --- save-payment-method/server/views/checkout.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/save-payment-method/server/views/checkout.ejs b/save-payment-method/server/views/checkout.ejs index fa995630..69cd3e78 100644 --- a/save-payment-method/server/views/checkout.ejs +++ b/save-payment-method/server/views/checkout.ejs @@ -9,7 +9,7 @@

From bd8f5094f74dc6f7d30271dc4a7c2763dab5f253 Mon Sep 17 00:00:00 2001 From: Jesse Shawl Date: Fri, 12 Apr 2024 09:16:55 -0500 Subject: [PATCH 27/34] fix lint failure (#129) --- .github/workflows/validate.yml | 2 +- advanced-integration/v1/package.json | 2 +- advanced-integration/v2/package.json | 2 +- save-payment-method/package.json | 2 +- standard-integration/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index ba842418..9ae8d9e3 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -29,7 +29,7 @@ jobs: - name: 👕 Lint code with ESLint run: > - find . -name package.json -maxdepth 2 -type f | while read -r file; do + find . -name package.json -maxdepth 3 -type f | while read -r file; do directory=$(dirname "$file") cd "$directory" && npm run lint && cd - done diff --git a/advanced-integration/v1/package.json b/advanced-integration/v1/package.json index ff3f5b41..0e93024f 100644 --- a/advanced-integration/v1/package.json +++ b/advanced-integration/v1/package.json @@ -9,7 +9,7 @@ "start": "nodemon server/server.js", "format": "npx prettier --write **/*.{js,md}", "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + "lint": "npx eslint server/*.js client/*.js --no-config-lookup" }, "license": "Apache-2.0", "dependencies": { diff --git a/advanced-integration/v2/package.json b/advanced-integration/v2/package.json index ff3f5b41..0e93024f 100644 --- a/advanced-integration/v2/package.json +++ b/advanced-integration/v2/package.json @@ -9,7 +9,7 @@ "start": "nodemon server/server.js", "format": "npx prettier --write **/*.{js,md}", "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + "lint": "npx eslint server/*.js client/*.js --no-config-lookup" }, "license": "Apache-2.0", "dependencies": { diff --git a/save-payment-method/package.json b/save-payment-method/package.json index 858c68af..d1596b09 100644 --- a/save-payment-method/package.json +++ b/save-payment-method/package.json @@ -9,7 +9,7 @@ "start": "nodemon server/server.js", "format": "npx prettier --write **/*.{js,md}", "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + "lint": "npx eslint server/*.js client/*.js --no-config-lookup" }, "license": "Apache-2.0", "dependencies": { diff --git a/standard-integration/package.json b/standard-integration/package.json index 5413d87e..f00bfb37 100644 --- a/standard-integration/package.json +++ b/standard-integration/package.json @@ -9,7 +9,7 @@ "start": "nodemon server/server.js", "format": "npx prettier --write **/*.{js,md}", "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser" + "lint": "npx eslint server/*.js client/*.js --no-config-lookup" }, "license": "Apache-2.0", "dependencies": { From a70265b6d4b0212c1d6adda32e49d59e419e1655 Mon Sep 17 00:00:00 2001 From: Mervin Choun <38122192+mchoun@users.noreply.github.com> Date: Mon, 3 Jun 2024 11:53:40 -0400 Subject: [PATCH 28/34] feat: update Card Fields integration with Billing Address (#131) --- advanced-integration/README.md | 4 +-- advanced-integration/v2/README.md | 2 +- advanced-integration/v2/client/checkout.js | 34 +++++++++++++++---- .../v2/server/views/checkout.ejs | 32 +++++++++++++++-- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/advanced-integration/README.md b/advanced-integration/README.md index 96d2c205..ef1dd69d 100644 --- a/advanced-integration/README.md +++ b/advanced-integration/README.md @@ -2,8 +2,8 @@ This folder contains example code for a PayPal advanced Checkout integration using both the JavaScript SDK and Node.js to complete transactions with the PayPal REST API. -* [`v2`](v2/README.md) contains sample code for the current advanced Checkout integration. This includes guidance on using Hosted Card Fields. -* [`v1`](v1/README.md) contains sample code for the legacy advanced Checkout integration. Use `v2` for new integrations. +- [`v2`](v2/README.md) contains sample code for the current advanced Checkout integration. This includes guidance on using Card Fields. +- [`v1`](v1/README.md) contains sample code for the legacy advanced Checkout integration. Use `v2` for new integrations. ## Instructions diff --git a/advanced-integration/v2/README.md b/advanced-integration/v2/README.md index 40cd1bd6..332d0d88 100644 --- a/advanced-integration/v2/README.md +++ b/advanced-integration/v2/README.md @@ -2,7 +2,7 @@ This folder contains example code for [version 2](https://developer.paypal.com/docs/checkout/advanced/integrate/) of a PayPal advanced Checkout integration using the JavaScript SDK and Node.js to complete transactions with the PayPal REST API. -Version 2 is the current advanced Checkout integration, and includes hosted card fields. +Version 2 is the current advanced Checkout integration, and includes Card Fields. ## Instructions diff --git a/advanced-integration/v2/client/checkout.js b/advanced-integration/v2/client/checkout.js index 517edeb8..29d9310c 100644 --- a/advanced-integration/v2/client/checkout.js +++ b/advanced-integration/v2/client/checkout.js @@ -124,13 +124,35 @@ if (cardField.isEligible()) { // Add click listener to submit button and call the submit function on the CardField component document - .getElementById("multi-card-field-button") + .getElementById("card-field-submit-button") .addEventListener("click", () => { - cardField.submit().catch((error) => { - resultMessage( - `Sorry, your transaction could not be processed...

${error}`, - ); - }); + cardField + .submit({ + // From your billing address fields + billingAddress: { + addressLine1: document.getElementById("card-billing-address-line-1") + .value, + addressLine2: document.getElementById("card-billing-address-line-2") + .value, + adminArea1: document.getElementById( + "card-billing-address-admin-area-line-1", + ).value, + adminArea2: document.getElementById( + "card-billing-address-admin-area-line-2", + ).value, + countryCode: document.getElementById( + "card-billing-address-country-code", + ).value, + postalCode: document.getElementById( + "card-billing-address-postal-code", + ).value, + }, + }) + .catch((error) => { + resultMessage( + `Sorry, your transaction could not be processed...

${error}`, + ); + }); }); } else { // Hides card fields if the merchant isn't eligible diff --git a/advanced-integration/v2/server/views/checkout.ejs b/advanced-integration/v2/server/views/checkout.ejs index 2b685ad6..5d129f60 100644 --- a/advanced-integration/v2/server/views/checkout.ejs +++ b/advanced-integration/v2/server/views/checkout.ejs @@ -9,15 +9,43 @@
+
- + +
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+

+

- + \ No newline at end of file From f61c97aed802d7134c53387971ef9d75959e7f12 Mon Sep 17 00:00:00 2001 From: sourav sarkar Date: Tue, 17 Sep 2024 22:31:39 +0530 Subject: [PATCH 29/34] Add multiple language support for Standard & Advanced Integration (#152) --- .../advanced-integration-v1/devcontainer.json | 2 +- .../advanced-integration-v2/devcontainer.json | 12 +- .../standard-integration/devcontainer.json | 12 +- .gitignore | 3 + advanced-integration/v2/.gitignore | 1 - advanced-integration/v2/README.md | 14 - advanced-integration/v2/client/checkout.js | 166 - .../v2/client/html/.env.example | 4 + .../v2/client/html/.gitignore | 2 + advanced-integration/v2/client/html/README.md | 74 + .../v2/client/html/client/app.js | 167 + .../v2/client/html/client/index.html | 86 + .../v2/client/html/package.json | 17 + .../v2/client/html/vite.config.js | 19 + .../v2/client/react/.env.example | 1 + .../v2/client/react/.gitignore | 2 + .../v2/client/react/README.md | 74 + .../v2/client/react/client/App.jsx | 240 + .../v2/client/react/client/index.html | 17 + .../v2/client/react/client/main.jsx | 9 + .../v2/client/react/package.json | 24 + .../v2/client/react/vite.config.js | 20 + advanced-integration/v2/package.json | 24 - .../v2/server/dotnet/.gitignore | 2 + .../dotnet/PayPalAdvancedIntegration.csproj | 11 + .../v2/server/dotnet/README.md | 18 + .../v2/server/dotnet/Server.cs | 200 + .../v2/server/dotnet/appsettings.json | 4 + .../v2/server/java/.gitignore | 1 + advanced-integration/v2/server/java/README.md | 18 + advanced-integration/v2/server/java/pom.xml | 52 + .../paypal/sample/SampleAppApplication.java | 140 + .../src/main/resources/application.properties | 3 + .../v2/{ => server/node}/.env.example | 0 advanced-integration/v2/server/node/README.md | 19 + .../v2/server/node/package.json | 22 + .../v2/server/{ => node/server}/server.js | 8 +- advanced-integration/v2/server/php/.gitignore | 1 + advanced-integration/v2/server/php/README.md | 49 + .../v2/server/php/composer.json | 28 + .../v2/server/php/composer.lock | 4485 +++++++++++++++++ .../v2/server/php/server/.env | 2 + .../v2/server/php/server/.htaccess | 34 + .../v2/server/php/server/index.php | 144 + .../v2/server/views/checkout.ejs | 51 - standard-integration/.gitignore | 1 - standard-integration/README.md | 13 - standard-integration/client/checkout.html | 15 - standard-integration/client/html/.env.example | 4 + standard-integration/client/html/.gitignore | 2 + standard-integration/client/html/README.md | 74 + .../client/{ => html/client}/app.js | 42 +- .../client/html/client/index.html | 20 + standard-integration/client/html/package.json | 17 + .../client/html/vite.config.js | 19 + .../client/react/.env.example | 1 + standard-integration/client/react/.gitignore | 2 + standard-integration/client/react/README.md | 74 + .../client/react/client/App.jsx | 123 + .../client/react/client/index.html | 17 + .../client/react/client/main.jsx | 9 + .../client/react/package.json | 24 + .../client/react/vite.config.js | 20 + standard-integration/package.json | 23 - standard-integration/server/dotnet/.gitignore | 2 + .../dotnet/PayPalAdvancedIntegration.csproj | 11 + standard-integration/server/dotnet/README.md | 18 + standard-integration/server/dotnet/Server.cs | 200 + .../server/dotnet/appsettings.json | 4 + standard-integration/server/java/.gitignore | 1 + standard-integration/server/java/README.md | 18 + standard-integration/server/java/pom.xml | 52 + .../paypal/sample/SampleAppApplication.java | 140 + .../src/main/resources/application.properties | 3 + .../{ => server/node}/.env.example | 0 standard-integration/server/node/.gitignore | 2 + standard-integration/server/node/README.md | 19 + standard-integration/server/node/package.json | 22 + .../server/{ => node/server}/server.js | 20 +- standard-integration/server/php/.gitignore | 1 + standard-integration/server/php/README.md | 49 + standard-integration/server/php/composer.json | 28 + standard-integration/server/php/composer.lock | 4485 +++++++++++++++++ standard-integration/server/php/server/.env | 2 + .../server/php/server/.htaccess | 34 + .../server/php/server/index.php | 144 + 86 files changed, 11686 insertions(+), 351 deletions(-) delete mode 100644 advanced-integration/v2/.gitignore delete mode 100644 advanced-integration/v2/README.md delete mode 100644 advanced-integration/v2/client/checkout.js create mode 100644 advanced-integration/v2/client/html/.env.example create mode 100644 advanced-integration/v2/client/html/.gitignore create mode 100644 advanced-integration/v2/client/html/README.md create mode 100644 advanced-integration/v2/client/html/client/app.js create mode 100644 advanced-integration/v2/client/html/client/index.html create mode 100644 advanced-integration/v2/client/html/package.json create mode 100644 advanced-integration/v2/client/html/vite.config.js create mode 100644 advanced-integration/v2/client/react/.env.example create mode 100644 advanced-integration/v2/client/react/.gitignore create mode 100644 advanced-integration/v2/client/react/README.md create mode 100644 advanced-integration/v2/client/react/client/App.jsx create mode 100644 advanced-integration/v2/client/react/client/index.html create mode 100644 advanced-integration/v2/client/react/client/main.jsx create mode 100644 advanced-integration/v2/client/react/package.json create mode 100644 advanced-integration/v2/client/react/vite.config.js delete mode 100644 advanced-integration/v2/package.json create mode 100644 advanced-integration/v2/server/dotnet/.gitignore create mode 100644 advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj create mode 100644 advanced-integration/v2/server/dotnet/README.md create mode 100644 advanced-integration/v2/server/dotnet/Server.cs create mode 100644 advanced-integration/v2/server/dotnet/appsettings.json create mode 100644 advanced-integration/v2/server/java/.gitignore create mode 100644 advanced-integration/v2/server/java/README.md create mode 100644 advanced-integration/v2/server/java/pom.xml create mode 100644 advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java create mode 100644 advanced-integration/v2/server/java/src/main/resources/application.properties rename advanced-integration/v2/{ => server/node}/.env.example (100%) create mode 100644 advanced-integration/v2/server/node/README.md create mode 100644 advanced-integration/v2/server/node/package.json rename advanced-integration/v2/server/{ => node/server}/server.js (96%) create mode 100644 advanced-integration/v2/server/php/.gitignore create mode 100644 advanced-integration/v2/server/php/README.md create mode 100644 advanced-integration/v2/server/php/composer.json create mode 100644 advanced-integration/v2/server/php/composer.lock create mode 100644 advanced-integration/v2/server/php/server/.env create mode 100644 advanced-integration/v2/server/php/server/.htaccess create mode 100644 advanced-integration/v2/server/php/server/index.php delete mode 100644 advanced-integration/v2/server/views/checkout.ejs delete mode 100644 standard-integration/.gitignore delete mode 100644 standard-integration/README.md delete mode 100644 standard-integration/client/checkout.html create mode 100644 standard-integration/client/html/.env.example create mode 100644 standard-integration/client/html/.gitignore create mode 100644 standard-integration/client/html/README.md rename standard-integration/client/{ => html/client}/app.js (75%) create mode 100644 standard-integration/client/html/client/index.html create mode 100644 standard-integration/client/html/package.json create mode 100644 standard-integration/client/html/vite.config.js create mode 100644 standard-integration/client/react/.env.example create mode 100644 standard-integration/client/react/.gitignore create mode 100644 standard-integration/client/react/README.md create mode 100644 standard-integration/client/react/client/App.jsx create mode 100644 standard-integration/client/react/client/index.html create mode 100644 standard-integration/client/react/client/main.jsx create mode 100644 standard-integration/client/react/package.json create mode 100644 standard-integration/client/react/vite.config.js delete mode 100644 standard-integration/package.json create mode 100644 standard-integration/server/dotnet/.gitignore create mode 100644 standard-integration/server/dotnet/PayPalAdvancedIntegration.csproj create mode 100644 standard-integration/server/dotnet/README.md create mode 100644 standard-integration/server/dotnet/Server.cs create mode 100644 standard-integration/server/dotnet/appsettings.json create mode 100644 standard-integration/server/java/.gitignore create mode 100644 standard-integration/server/java/README.md create mode 100644 standard-integration/server/java/pom.xml create mode 100644 standard-integration/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java create mode 100644 standard-integration/server/java/src/main/resources/application.properties rename standard-integration/{ => server/node}/.env.example (100%) create mode 100644 standard-integration/server/node/.gitignore create mode 100644 standard-integration/server/node/README.md create mode 100644 standard-integration/server/node/package.json rename standard-integration/server/{ => node/server}/server.js (93%) create mode 100644 standard-integration/server/php/.gitignore create mode 100644 standard-integration/server/php/README.md create mode 100644 standard-integration/server/php/composer.json create mode 100644 standard-integration/server/php/composer.lock create mode 100644 standard-integration/server/php/server/.env create mode 100644 standard-integration/server/php/server/.htaccess create mode 100644 standard-integration/server/php/server/index.php diff --git a/.devcontainer/advanced-integration-v1/devcontainer.json b/.devcontainer/advanced-integration-v1/devcontainer.json index b8f1d538..ffb6f41c 100644 --- a/.devcontainer/advanced-integration-v1/devcontainer.json +++ b/.devcontainer/advanced-integration-v1/devcontainer.json @@ -37,4 +37,4 @@ } } } -} +} \ No newline at end of file diff --git a/.devcontainer/advanced-integration-v2/devcontainer.json b/.devcontainer/advanced-integration-v2/devcontainer.json index 9a4ab9ac..6fd991e1 100644 --- a/.devcontainer/advanced-integration-v2/devcontainer.json +++ b/.devcontainer/advanced-integration-v2/devcontainer.json @@ -6,15 +6,19 @@ // Use 'onCreateCommand' to run commands when creating the container. "onCreateCommand": "bash ../../.devcontainer/advanced-integration-v2/welcome-message.sh", // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "npm install", + "postCreateCommand": { + "Install Server Packages": "cd server/node && npm install", + "Install Client Packages": "cd client/html && npm install" + }, // Use 'postAttachCommand' to run commands when attaching to the container. "postAttachCommand": { - "Start server": "npm start" + "Start server": "cd server/node && npm start", + "Start client": "cd client/html && npm start" }, // Use 'forwardPorts' to make a list of ports inside the container available locally. - "forwardPorts": [8888], + "forwardPorts": [3000, 8080], "portsAttributes": { - "8888": { + "3000": { "label": "Preview of Advanced Checkout Flow", "onAutoForward": "openBrowserOnce" } diff --git a/.devcontainer/standard-integration/devcontainer.json b/.devcontainer/standard-integration/devcontainer.json index c6d0ffec..508fb74b 100644 --- a/.devcontainer/standard-integration/devcontainer.json +++ b/.devcontainer/standard-integration/devcontainer.json @@ -6,15 +6,19 @@ // Use 'onCreateCommand' to run commands when creating the container. "onCreateCommand": "bash ../.devcontainer/standard-integration/welcome-message.sh", // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "npm install", + "postCreateCommand": { + "Install Client Packages": "cd client/html && npm install", + "Install Server Packages": "cd server/node && npm install" + }, // Use 'postAttachCommand' to run commands when attaching to the container. "postAttachCommand": { - "Start server": "npm start" + "Start client": "cd client/html && npm start", + "Start server": "cd server/node && npm start" }, // Use 'forwardPorts' to make a list of ports inside the container available locally. - "forwardPorts": [8888], + "forwardPorts": [3000, 8080], "portsAttributes": { - "8888": { + "3000": { "label": "Preview of Standard Checkout Flow", "onAutoForward": "openBrowserOnce" } diff --git a/.gitignore b/.gitignore index 5f9a1890..5df6b051 100644 --- a/.gitignore +++ b/.gitignore @@ -99,3 +99,6 @@ dist # TernJS port file .tern-port + +# dotnet +*.sln diff --git a/advanced-integration/v2/.gitignore b/advanced-integration/v2/.gitignore deleted file mode 100644 index 4c49bd78..00000000 --- a/advanced-integration/v2/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.env diff --git a/advanced-integration/v2/README.md b/advanced-integration/v2/README.md deleted file mode 100644 index 332d0d88..00000000 --- a/advanced-integration/v2/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Advanced Integration Example - -This folder contains example code for [version 2](https://developer.paypal.com/docs/checkout/advanced/integrate/) of a PayPal advanced Checkout integration using the JavaScript SDK and Node.js to complete transactions with the PayPal REST API. - -Version 2 is the current advanced Checkout integration, and includes Card Fields. - -## Instructions - -1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create) -2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET`. -3. Run `npm install` -4. Run `npm start` -5. Open http://localhost:8888 -6. Enter the credit card number provided from one of your [sandbox accounts](https://developer.paypal.com/dashboard/accounts) or [generate a new credit card](https://developer.paypal.com/dashboard/creditCardGenerator) diff --git a/advanced-integration/v2/client/checkout.js b/advanced-integration/v2/client/checkout.js deleted file mode 100644 index 29d9310c..00000000 --- a/advanced-integration/v2/client/checkout.js +++ /dev/null @@ -1,166 +0,0 @@ -async function createOrderCallback() { - try { - const response = await fetch("/api/orders", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - // use the "body" param to optionally pass additional order information - // like product ids and quantities - body: JSON.stringify({ - cart: [ - { - id: "YOUR_PRODUCT_ID", - quantity: "YOUR_PRODUCT_QUANTITY", - }, - ], - }), - }); - - const orderData = await response.json(); - - if (orderData.id) { - return orderData.id; - } else { - const errorDetail = orderData?.details?.[0]; - const errorMessage = errorDetail - ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` - : JSON.stringify(orderData); - - throw new Error(errorMessage); - } - } catch (error) { - console.error(error); - resultMessage(`Could not initiate PayPal Checkout...

${error}`); - } -} - -async function onApproveCallback(data, actions) { - try { - const response = await fetch(`/api/orders/${data.orderID}/capture`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - }); - - const orderData = await response.json(); - // Three cases to handle: - // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() - // (2) Other non-recoverable errors -> Show a failure message - // (3) Successful transaction -> Show confirmation or thank you message - - const transaction = - orderData?.purchase_units?.[0]?.payments?.captures?.[0] || - orderData?.purchase_units?.[0]?.payments?.authorizations?.[0]; - const errorDetail = orderData?.details?.[0]; - - // this actions.restart() behavior only applies to the Buttons component - if (errorDetail?.issue === "INSTRUMENT_DECLINED" && !data.card && actions) { - // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() - // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ - return actions.restart(); - } else if ( - errorDetail || - !transaction || - transaction.status === "DECLINED" - ) { - // (2) Other non-recoverable errors -> Show a failure message - let errorMessage; - if (transaction) { - errorMessage = `Transaction ${transaction.status}: ${transaction.id}`; - } else if (errorDetail) { - errorMessage = `${errorDetail.description} (${orderData.debug_id})`; - } else { - errorMessage = JSON.stringify(orderData); - } - - throw new Error(errorMessage); - } else { - // (3) Successful transaction -> Show confirmation or thank you message - // Or go to another URL: actions.redirect('thank_you.html'); - resultMessage( - `Transaction ${transaction.status}: ${transaction.id}

See console for all available details`, - ); - console.log( - "Capture result", - orderData, - JSON.stringify(orderData, null, 2), - ); - } - } catch (error) { - console.error(error); - resultMessage( - `Sorry, your transaction could not be processed...

${error}`, - ); - } -} - -window.paypal - .Buttons({ - createOrder: createOrderCallback, - onApprove: onApproveCallback, - }) - .render("#paypal-button-container"); - -const cardField = window.paypal.CardFields({ - createOrder: createOrderCallback, - onApprove: onApproveCallback, -}); - -// Render each field after checking for eligibility -if (cardField.isEligible()) { - const nameField = cardField.NameField(); - nameField.render("#card-name-field-container"); - - const numberField = cardField.NumberField(); - numberField.render("#card-number-field-container"); - - const cvvField = cardField.CVVField(); - cvvField.render("#card-cvv-field-container"); - - const expiryField = cardField.ExpiryField(); - expiryField.render("#card-expiry-field-container"); - - // Add click listener to submit button and call the submit function on the CardField component - document - .getElementById("card-field-submit-button") - .addEventListener("click", () => { - cardField - .submit({ - // From your billing address fields - billingAddress: { - addressLine1: document.getElementById("card-billing-address-line-1") - .value, - addressLine2: document.getElementById("card-billing-address-line-2") - .value, - adminArea1: document.getElementById( - "card-billing-address-admin-area-line-1", - ).value, - adminArea2: document.getElementById( - "card-billing-address-admin-area-line-2", - ).value, - countryCode: document.getElementById( - "card-billing-address-country-code", - ).value, - postalCode: document.getElementById( - "card-billing-address-postal-code", - ).value, - }, - }) - .catch((error) => { - resultMessage( - `Sorry, your transaction could not be processed...

${error}`, - ); - }); - }); -} else { - // Hides card fields if the merchant isn't eligible - document.querySelector("#card-form").style = "display: none"; -} - -// Example function to show a result to the user. Your site's UI library can be used instead. -function resultMessage(message) { - const container = document.querySelector("#result-message"); - container.innerHTML = message; -} diff --git a/advanced-integration/v2/client/html/.env.example b/advanced-integration/v2/client/html/.env.example new file mode 100644 index 00000000..dbfed9bd --- /dev/null +++ b/advanced-integration/v2/client/html/.env.example @@ -0,0 +1,4 @@ +# Create an application to obtain credentials at +# https://developer.paypal.com/dashboard/applications/sandbox + +PAYPAL_CLIENT_ID=YOUR_CLIENT_ID_GOES_HERE diff --git a/advanced-integration/v2/client/html/.gitignore b/advanced-integration/v2/client/html/.gitignore new file mode 100644 index 00000000..ed648a05 --- /dev/null +++ b/advanced-integration/v2/client/html/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.local \ No newline at end of file diff --git a/advanced-integration/v2/client/html/README.md b/advanced-integration/v2/client/html/README.md new file mode 100644 index 00000000..0ebb16ac --- /dev/null +++ b/advanced-integration/v2/client/html/README.md @@ -0,0 +1,74 @@ +# Advanced Integration with PayPal : HTML/JS + +## Getting Started + +This guide will walk you through setting up and running the HTML/JS Advanced Integration locally. + +### Before You Code + +1. **Setup a PayPal Account** + + To get started, you'll need a developer, personal, or business account. + + [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer) + + You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts. + +2. **Create an Application** + + Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create). + +### Installation + +```sh +npm install +``` + +### Configuration + +1. Environmental Variables (.env) + + - Rename the .env.example file to .env + - Update the following keys with their actual values - + + ```sh + PAYPAL_CLIENT_ID= + ``` + +2. Connecting the client and server (vite.config.js) + + - Open vite.config.js in the root directory. + - Locate the proxy configuration object. + - Update the proxy key to match the server's address and port. For example: + + ```js + export default defineConfig({ + + server: { + proxy: { + "/api": { + target: "http://localhost:8080", // Replace with your server URL + changeOrigin: true, + }, + }, + }, + }); + ``` + +3. Starting the development server + + - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory. + + - **Start the client**: + + ```sh + npm run dev + ``` + + This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). + +### Additional Notes + +- **Server Setup**: Make sure you have the server up and running before starting the client. +- **Environment Variables**: Carefully configure the environment variables in the .env file to match your setup. +- **Proxy Configuration**: The proxy setting in vite.config.js is crucial for routing API requests from the client to the server during development. diff --git a/advanced-integration/v2/client/html/client/app.js b/advanced-integration/v2/client/html/client/app.js new file mode 100644 index 00000000..02cd182a --- /dev/null +++ b/advanced-integration/v2/client/html/client/app.js @@ -0,0 +1,167 @@ +async function createOrderCallback() { + try { + const response = await fetch("/api/orders", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + // use the "body" param to optionally pass additional order information + // like product ids and quantities + body: JSON.stringify({ + cart: [ + { + id: "YOUR_PRODUCT_ID", + quantity: "YOUR_PRODUCT_QUANTITY", + }, + ], + }), + }); + + const orderData = await response.json(); + + if (orderData.id) { + return orderData.id; + } else { + const errorDetail = orderData?.details?.[0]; + const errorMessage = errorDetail + ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` + : JSON.stringify(orderData); + + throw new Error(errorMessage); + } + } catch (error) { + console.error(error); + resultMessage(`Could not initiate PayPal Checkout...

${error}`); + } + } + + async function onApproveCallback(data, actions) { + try { + const response = await fetch(`/api/orders/${data.orderID}/capture`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }); + + const orderData = await response.json(); + // Three cases to handle: + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // (2) Other non-recoverable errors -> Show a failure message + // (3) Successful transaction -> Show confirmation or thank you message + + const transaction = + orderData?.purchase_units?.[0]?.payments?.captures?.[0] || + orderData?.purchase_units?.[0]?.payments?.authorizations?.[0]; + const errorDetail = orderData?.details?.[0]; + + // this actions.restart() behavior only applies to the Buttons component + if (errorDetail?.issue === "INSTRUMENT_DECLINED" && !data.card && actions) { + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ + return actions.restart(); + } else if ( + errorDetail || + !transaction || + transaction.status === "DECLINED" + ) { + // (2) Other non-recoverable errors -> Show a failure message + let errorMessage; + if (transaction) { + errorMessage = `Transaction ${transaction.status}: ${transaction.id}`; + } else if (errorDetail) { + errorMessage = `${errorDetail.description} (${orderData.debug_id})`; + } else { + errorMessage = JSON.stringify(orderData); + } + + throw new Error(errorMessage); + } else { + // (3) Successful transaction -> Show confirmation or thank you message + // Or go to another URL: actions.redirect('thank_you.html'); + resultMessage( + `Transaction ${transaction.status}: ${transaction.id}

See console for all available details`, + ); + console.log( + "Capture result", + orderData, + JSON.stringify(orderData, null, 2), + ); + } + } catch (error) { + console.error(error); + resultMessage( + `Sorry, your transaction could not be processed...

${error}`, + ); + } + } + + window.paypal + .Buttons({ + createOrder: createOrderCallback, + onApprove: onApproveCallback, + }) + .render("#paypal-button-container"); + + const cardField = window.paypal.CardFields({ + createOrder: createOrderCallback, + onApprove: onApproveCallback, + }); + + // Render each field after checking for eligibility + if (cardField.isEligible()) { + const nameField = cardField.NameField(); + nameField.render("#card-name-field-container"); + + const numberField = cardField.NumberField(); + numberField.render("#card-number-field-container"); + + const cvvField = cardField.CVVField(); + cvvField.render("#card-cvv-field-container"); + + const expiryField = cardField.ExpiryField(); + expiryField.render("#card-expiry-field-container"); + + // Add click listener to submit button and call the submit function on the CardField component + document + .getElementById("card-field-submit-button") + .addEventListener("click", () => { + cardField + .submit({ + // From your billing address fields + billingAddress: { + addressLine1: document.getElementById("card-billing-address-line-1") + .value, + addressLine2: document.getElementById("card-billing-address-line-2") + .value, + adminArea1: document.getElementById( + "card-billing-address-admin-area-line-1", + ).value, + adminArea2: document.getElementById( + "card-billing-address-admin-area-line-2", + ).value, + countryCode: document.getElementById( + "card-billing-address-country-code", + ).value, + postalCode: document.getElementById( + "card-billing-address-postal-code", + ).value, + }, + }) + .catch((error) => { + resultMessage( + `Sorry, your transaction could not be processed...

${error}`, + ); + }); + }); + } else { + // Hides card fields if the merchant isn't eligible + document.querySelector("#card-form").style = "display: none"; + } + + // Example function to show a result to the user. Your site's UI library can be used instead. + function resultMessage(message) { + const container = document.querySelector("#result-message"); + container.innerHTML = message; + } + \ No newline at end of file diff --git a/advanced-integration/v2/client/html/client/index.html b/advanced-integration/v2/client/html/client/index.html new file mode 100644 index 00000000..328d4da4 --- /dev/null +++ b/advanced-integration/v2/client/html/client/index.html @@ -0,0 +1,86 @@ + + + + + + + PayPal JS SDK Advanced Integration - Checkout Flow + + +
+ +
+
+
+
+
+ +
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+

+ +
+

+ + + + diff --git a/advanced-integration/v2/client/html/package.json b/advanced-integration/v2/client/html/package.json new file mode 100644 index 00000000..c14f152f --- /dev/null +++ b/advanced-integration/v2/client/html/package.json @@ -0,0 +1,17 @@ +{ + "name": "paypal-advanced-integration-frontend-html", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "preview": "vite preview", + "start": "vite", + "format": "npx prettier --write **/*.{js,md}", + "format:check": "npx prettier --check **/*.{js,md}" + }, + "devDependencies": { + "dotenv": "^16.4.5", + "vite": "^5.4.2" + } +} diff --git a/advanced-integration/v2/client/html/vite.config.js b/advanced-integration/v2/client/html/vite.config.js new file mode 100644 index 00000000..76921cbb --- /dev/null +++ b/advanced-integration/v2/client/html/vite.config.js @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [], + envDir: "../", + envPrefix: "PAYPAL", + root: "client", + server: { + port: 3000, + proxy: { + "/api": { + target: "http://localhost:8080", + changeOrigin: true, + secure: false, + }, + }, + }, +}) \ No newline at end of file diff --git a/advanced-integration/v2/client/react/.env.example b/advanced-integration/v2/client/react/.env.example new file mode 100644 index 00000000..abea0386 --- /dev/null +++ b/advanced-integration/v2/client/react/.env.example @@ -0,0 +1 @@ +PAYPAL_CLIENT_ID=PAYPAL_CLIENT_ID \ No newline at end of file diff --git a/advanced-integration/v2/client/react/.gitignore b/advanced-integration/v2/client/react/.gitignore new file mode 100644 index 00000000..ed648a05 --- /dev/null +++ b/advanced-integration/v2/client/react/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.local \ No newline at end of file diff --git a/advanced-integration/v2/client/react/README.md b/advanced-integration/v2/client/react/README.md new file mode 100644 index 00000000..6022519f --- /dev/null +++ b/advanced-integration/v2/client/react/README.md @@ -0,0 +1,74 @@ +# Advanced Integration with PayPal : React + +## Getting Started + +This guide will walk you through setting up and running the React Advanced Integration locally. + +### Before You Code + +1. **Setup a PayPal Account** + + To get started, you'll need a developer, personal, or business account. + + [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer) + + You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts. + +2. **Create an Application** + + Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create). + +### Installation + +```sh +npm install +``` + +### Configuration + +1. Environmental Variables (.env) + + - Rename the .env.example file to .env + - Update the following keys with their actual values - + + ```sh + PAYPAL_CLIENT_ID= + ``` + +2. Connecting the client and server (vite.config.js) + + - Open vite.config.js in the root directory. + - Locate the proxy configuration object. + - Update the proxy key to match the server's address and port. For example: + + ```js + export default defineConfig({ + + server: { + proxy: { + "/api": { + target: "http://localhost:8080", // Replace with your server URL + changeOrigin: true, + }, + }, + }, + }); + ``` + +3. Starting the development server + + - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory. + + - **Start the client**: + + ```sh + npm run dev + ``` + + This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). + +### Additional Notes + +- **Server Setup**: Make sure you have the server up and running before starting the client. +- **Environment Variables**: Carefully configure the environment variables in the .env file to match your setup. +- **Proxy Configuration**: The proxy setting in vite.config.js is crucial for routing API requests from the client to the server during development. diff --git a/advanced-integration/v2/client/react/client/App.jsx b/advanced-integration/v2/client/react/client/App.jsx new file mode 100644 index 00000000..bed59906 --- /dev/null +++ b/advanced-integration/v2/client/react/client/App.jsx @@ -0,0 +1,240 @@ +import React, { useState } from "react"; +import { + PayPalScriptProvider, + usePayPalCardFields, + PayPalCardFieldsProvider, + PayPalButtons, + PayPalCardFieldsForm, +} from "@paypal/react-paypal-js"; + +export default function App() { + const [isPaying, setIsPaying] = useState(false); + const initialOptions = { + "client-id": import.meta.env.PAYPAL_CLIENT_ID, + "enable-funding": "venmo", + "buyer-country": "US", + currency: "USD", + components: "buttons,card-fields", + }; + + const [billingAddress, setBillingAddress] = useState({ + addressLine1: "", + addressLine2: "", + adminArea1: "", + adminArea2: "", + countryCode: "", + postalCode: "", + }); + + function handleBillingAddressChange(field, value) { + setBillingAddress((prev) => ({ + ...prev, + [field]: value, + })); + } + + async function createOrder() { + try { + const response = await fetch("/api/orders", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + // use the "body" param to optionally pass additional order information + // like product ids and quantities + body: JSON.stringify({ + cart: [ + { + id: "YOUR_PRODUCT_ID", + quantity: "YOUR_PRODUCT_QUANTITY", + }, + ], + }), + }); + + const orderData = await response.json(); + + if (orderData.id) { + return orderData.id; + } else { + const errorDetail = orderData?.details?.[0]; + const errorMessage = errorDetail + ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` + : JSON.stringify(orderData); + + throw new Error(errorMessage); + } + } catch (error) { + console.error(error); + return `Could not initiate PayPal Checkout...${error}`; + } + } + + async function onApprove(data, actions) { + try { + const response = await fetch(`/api/orders/${data.orderID}/capture`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }); + + const orderData = await response.json(); + // Three cases to handle: + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // (2) Other non-recoverable errors -> Show a failure message + // (3) Successful transaction -> Show confirmation or thank you message + + const transaction = + orderData?.purchase_units?.[0]?.payments?.captures?.[0] || + orderData?.purchase_units?.[0]?.payments?.authorizations?.[0]; + const errorDetail = orderData?.details?.[0]; + + if (errorDetail || !transaction || transaction.status === "DECLINED") { + // (2) Other non-recoverable errors -> Show a failure message + let errorMessage; + if (transaction) { + errorMessage = `Transaction ${transaction.status}: ${transaction.id}`; + } else if (errorDetail) { + errorMessage = `${errorDetail.description} (${orderData.debug_id})`; + } else { + errorMessage = JSON.stringify(orderData); + } + + throw new Error(errorMessage); + } else { + // (3) Successful transaction -> Show confirmation or thank you message + // Or go to another URL: actions.redirect('thank_you.html'); + console.log( + "Capture result", + orderData, + JSON.stringify(orderData, null, 2) + ); + return `Transaction ${transaction.status}: ${transaction.id}. See console for all available details`; + } + } catch (error) { + return `Sorry, your transaction could not be processed...${error}`; + } + } + + function onError(error) { + // Do something with the error from the SDK + } + + return ( +
+ + + + + + + handleBillingAddressChange("addressLine1", e.target.value) + } + /> + + handleBillingAddressChange("addressLine2", e.target.value) + } + /> + + handleBillingAddressChange("adminArea1", e.target.value) + } + /> + + handleBillingAddressChange("adminArea2", e.target.value) + } + /> + + handleBillingAddressChange("countryCode", e.target.value) + } + /> + + handleBillingAddressChange("postalCode", e.target.value) + } + /> + {/* Custom client component to handle card fields submission */} + + + +
+ ); +} + +const SubmitPayment = ({ isPaying, setIsPaying, billingAddress }) => { + const { cardFieldsForm, fields } = usePayPalCardFields(); + + const handleClick = async () => { + if (!cardFieldsForm) { + const childErrorMessage = + "Unable to find any child components in the "; + + throw new Error(childErrorMessage); + } + const formState = await cardFieldsForm.getState(); + + if (!formState.isFormValid) { + return alert("The payment form is invalid"); + } + setIsPaying(true); + + cardFieldsForm.submit({ billingAddress }).catch((err) => { + setIsPaying(false); + }); + }; + + return ( + + ); +}; diff --git a/advanced-integration/v2/client/react/client/index.html b/advanced-integration/v2/client/react/client/index.html new file mode 100644 index 00000000..4330e684 --- /dev/null +++ b/advanced-integration/v2/client/react/client/index.html @@ -0,0 +1,17 @@ + + + + + + React PayPal JS SDK Advanced Integration + + + +
+ + + diff --git a/advanced-integration/v2/client/react/client/main.jsx b/advanced-integration/v2/client/react/client/main.jsx new file mode 100644 index 00000000..569fdf2f --- /dev/null +++ b/advanced-integration/v2/client/react/client/main.jsx @@ -0,0 +1,9 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App.jsx"; + +ReactDOM.createRoot(document.getElementById("root")).render( + + + +); diff --git a/advanced-integration/v2/client/react/package.json b/advanced-integration/v2/client/react/package.json new file mode 100644 index 00000000..b61d3e00 --- /dev/null +++ b/advanced-integration/v2/client/react/package.json @@ -0,0 +1,24 @@ +{ + "name": "paypal-advanced-integration-frontend-react", + "version": "1.0.0", + "private": true, + "type": "module", + "dependencies": { + "@paypal/react-paypal-js": "^8.6.0", + "dotenv": "^16.3.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "scripts": { + "client-dev": "vite", + "client-build": "vite build", + "client-preview": "vite preview", + "start": "npm run client-dev", + "format": "npx prettier --write **/*.{js,jsx,md}", + "format:check": "npx prettier --check **/*.{js,jsx,md}" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.1", + "vite": "^5.4.2" + } +} diff --git a/advanced-integration/v2/client/react/vite.config.js b/advanced-integration/v2/client/react/vite.config.js new file mode 100644 index 00000000..8049384e --- /dev/null +++ b/advanced-integration/v2/client/react/vite.config.js @@ -0,0 +1,20 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + root: "client", + envDir: "../", + envPrefix: "PAYPAL", + server: { + port: 3000, + proxy: { + "/api": { + target: "http://localhost:8080", + changeOrigin: true, + secure: false, + }, + }, + }, +}) \ No newline at end of file diff --git a/advanced-integration/v2/package.json b/advanced-integration/v2/package.json deleted file mode 100644 index 0e93024f..00000000 --- a/advanced-integration/v2/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "paypal-advanced-integration", - "description": "Sample Node.js web app to integrate PayPal Advanced Checkout for online payments", - "version": "1.0.0", - "main": "server/server.js", - "type": "module", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon server/server.js", - "format": "npx prettier --write **/*.{js,md}", - "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server/*.js client/*.js --no-config-lookup" - }, - "license": "Apache-2.0", - "dependencies": { - "dotenv": "^16.3.1", - "ejs": "^3.1.9", - "express": "^4.18.2", - "node-fetch": "^3.3.2" - }, - "devDependencies": { - "nodemon": "^3.0.1" - } -} diff --git a/advanced-integration/v2/server/dotnet/.gitignore b/advanced-integration/v2/server/dotnet/.gitignore new file mode 100644 index 00000000..cbbd0b5c --- /dev/null +++ b/advanced-integration/v2/server/dotnet/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ \ No newline at end of file diff --git a/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj b/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj new file mode 100644 index 00000000..1c9d4604 --- /dev/null +++ b/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj @@ -0,0 +1,11 @@ + + + + net8.0 + PayPalAdvancedIntegration + + + + + + diff --git a/advanced-integration/v2/server/dotnet/README.md b/advanced-integration/v2/server/dotnet/README.md new file mode 100644 index 00000000..92ac1cc2 --- /dev/null +++ b/advanced-integration/v2/server/dotnet/README.md @@ -0,0 +1,18 @@ +# Advanced Integartion .NET Sample +PayPal Advanced Integration sample in .NET + +## Running the sample + +1. Build the server + +~~~ +dotnet restore +~~~ + +2. Run the server + +~~~ +dotnet run +~~~ + +3. Go to [http://localhost:8080/](http://localhost:8080/) \ No newline at end of file diff --git a/advanced-integration/v2/server/dotnet/Server.cs b/advanced-integration/v2/server/dotnet/Server.cs new file mode 100644 index 00000000..c9bab8fc --- /dev/null +++ b/advanced-integration/v2/server/dotnet/Server.cs @@ -0,0 +1,200 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; + +namespace PayPalAdvancedIntegration; + +public class Program +{ + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration( + (context, config) => + { + config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); + } + ) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseUrls("http://localhost:8080"); + webBuilder.UseStartup(); + }); +} + +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddMvc().AddNewtonsoftJson(); + services.AddHttpClient(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + app.UseRouting(); + app.UseStaticFiles(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } +} + +[ApiController] +public class CheckoutController : Controller +{ + private readonly IHttpClientFactory _httpClientFactory; + private IConfiguration _configuration { get; } + private string _paypalClientId + { + get { return _configuration["PAYPAL_CLIENT_ID"]; } + } + private string _paypalClientSecret + { + get { return _configuration["PAYPAL_CLIENT_SECRET"]; } + } + private readonly string _base = "https://api-m.sandbox.paypal.com"; + + public CheckoutController(IHttpClientFactory httpClientFactory, IConfiguration configuration) + { + _httpClientFactory = httpClientFactory; + _configuration = configuration; + } + + [HttpPost("api/orders")] + public async Task CreateOrder([FromBody] dynamic cart) + { + try + { + var result = await _CreateOrder(cart); + return StatusCode((int)result.httpStatusCode, result.jsonResponse); + } + catch (Exception ex) + { + Console.Error.WriteLine("Failed to create order:", ex); + return StatusCode(500, new { error = "Failed to create order." }); + } + } + + [HttpPost("api/orders/{orderID}/capture")] + public async Task CaptureOrder(string orderID) + { + try + { + var result = await _CaptureOrder(orderID); + return StatusCode((int)result.httpStatusCode, result.jsonResponse); + } + catch (Exception ex) + { + Console.Error.WriteLine("Failed to capture order:", ex); + return StatusCode(500, new { error = "Failed to capture order." }); + } + } + + private async Task GenerateAccessToken() + { + if (string.IsNullOrEmpty(_paypalClientId) || string.IsNullOrEmpty(_paypalClientSecret)) + { + throw new Exception("MISSING_API_CREDENTIALS"); + } + + var auth = Convert.ToBase64String( + Encoding.UTF8.GetBytes($"{_paypalClientId}:{_paypalClientSecret}") + ); + var client = _httpClientFactory.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Post, $"{_base}/v1/oauth2/token") + { + Content = new StringContent( + "grant_type=client_credentials", + Encoding.UTF8, + "application/x-www-form-urlencoded" + ) + }; + request.Headers.Add("Authorization", $"Basic {auth}"); + + var response = await client.SendAsync(request); + var data = JsonConvert.DeserializeObject( + await response.Content.ReadAsStringAsync() + ); + return data.access_token; + } + + private async Task _CreateOrder(dynamic cart) + { + var accessToken = await GenerateAccessToken(); + var url = $"{_base}/v2/checkout/orders"; + var payload = new + { + intent = "CAPTURE", + purchase_units = new[] + { + new { amount = new { currency_code = "USD", value = "100.00" } } + } + }; + + var client = _httpClientFactory.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = new StringContent( + JsonConvert.SerializeObject(payload), + Encoding.UTF8, + "application/json" + ) + }; + request.Headers.Add("Authorization", $"Bearer {accessToken}"); + + var response = await client.SendAsync(request); + return await HandleResponse(response); + } + + private async Task _CaptureOrder(string orderID) + { + var accessToken = await GenerateAccessToken(); + var url = $"{_base}/v2/checkout/orders/{orderID}/capture"; + + var client = _httpClientFactory.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = new StringContent("", Encoding.UTF8, "application/json") + }; + request.Headers.Add("Authorization", $"Bearer {accessToken}"); + + var response = await client.SendAsync(request); + return await HandleResponse(response); + } + + private async Task HandleResponse(HttpResponseMessage response) + { + try + { + var jsonResponse = JsonConvert.DeserializeObject( + await response.Content.ReadAsStringAsync() + ); + return new { jsonResponse, httpStatusCode = response.StatusCode }; + } + catch (Exception) + { + var errorMessage = await response.Content.ReadAsStringAsync(); + throw new Exception(errorMessage); + } + } +} diff --git a/advanced-integration/v2/server/dotnet/appsettings.json b/advanced-integration/v2/server/dotnet/appsettings.json new file mode 100644 index 00000000..019194eb --- /dev/null +++ b/advanced-integration/v2/server/dotnet/appsettings.json @@ -0,0 +1,4 @@ +{ + "PAYPAL_CLIENT_ID": "PAYPAL_CLIENT_ID", + "PAYPAL_CLIENT_SECRET": "PAYPAL_CLIENT_SECRET" +} diff --git a/advanced-integration/v2/server/java/.gitignore b/advanced-integration/v2/server/java/.gitignore new file mode 100644 index 00000000..9f970225 --- /dev/null +++ b/advanced-integration/v2/server/java/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/advanced-integration/v2/server/java/README.md b/advanced-integration/v2/server/java/README.md new file mode 100644 index 00000000..578fb9b7 --- /dev/null +++ b/advanced-integration/v2/server/java/README.md @@ -0,0 +1,18 @@ +# Advanced Integartion Java Sample +PayPal Advanced Integration sample in Java + +## Running the sample + +1. Build the server + +~~~ +mvn clean install +~~~ + +2. Run the server + +~~~ +mvn spring-boot:run +~~~ + +3. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/advanced-integration/v2/server/java/pom.xml b/advanced-integration/v2/server/java/pom.xml new file mode 100644 index 00000000..f36d390d --- /dev/null +++ b/advanced-integration/v2/server/java/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.2 + + + com.paypal.sample + advanced-integration + 0.0.1-SNAPSHOT + PayPal Advanced Integration + Sample Java demo application for PayPal JS SDK Advanced Integration + + + + + + + + + + + + + + + 22 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java b/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java new file mode 100644 index 00000000..b4f3b4ae --- /dev/null +++ b/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java @@ -0,0 +1,140 @@ +package com.paypal.sample; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.util.Base64; +import java.util.Map; + +@SpringBootApplication +public class SampleAppApplication { + + @Value("${PAYPAL_CLIENT_ID}") + private String PAYPAL_CLIENT_ID; + + @Value("${PAYPAL_CLIENT_SECRET}") + private String PAYPAL_CLIENT_SECRET; + + private final String BASE_URL = "https://api-m.sandbox.paypal.com"; + + public static void main(String[] args) { + SpringApplication.run(SampleAppApplication.class, args); + } + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + @Controller + @RequestMapping("/") + public class CheckoutController { + + private final RestTemplate restTemplate; + private final ObjectMapper objectMapper; + + public CheckoutController(RestTemplate restTemplate, ObjectMapper objectMapper) { + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + } + + @PostMapping("/api/orders") + public ResponseEntity createOrder(@RequestBody Map request) { + try { + String cart = objectMapper.writeValueAsString(request.get("cart")); + JsonNode response = createOrder(cart); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + e.printStackTrace(); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @PostMapping("/api/orders/{orderID}/capture") + public ResponseEntity captureOrder(@PathVariable String orderID) { + try { + JsonNode response = captureOrders(orderID); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + e.printStackTrace(); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + private String generateAccessToken() throws IOException { + if (PAYPAL_CLIENT_ID == null || PAYPAL_CLIENT_SECRET == null) { + throw new IllegalArgumentException("MISSING_API_CREDENTIALS"); + } + String auth = Base64.getEncoder().encodeToString((PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET).getBytes()); + HttpHeaders headers = new HttpHeaders(); + headers.setBasicAuth(auth); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("grant_type", "client_credentials"); + + ResponseEntity response = restTemplate.postForEntity(BASE_URL + "/v1/oauth2/token", new HttpEntity<>(body, headers), JsonNode.class); + return response.getBody().get("access_token").asText(); + } + + private JsonNode createOrder(String cart) throws IOException { + String accessToken = generateAccessToken(); + String url = BASE_URL + "/v2/checkout/orders"; + + ObjectNode payload = objectMapper.createObjectNode(); + payload.put("intent", "CAPTURE"); + ObjectNode purchaseUnit = payload.putArray("purchase_units").addObject(); + ObjectNode amount = purchaseUnit.putObject("amount"); + amount.put("currency_code", "USD"); + amount.put("value", "100.00"); + + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(accessToken); + headers.setContentType(MediaType.APPLICATION_JSON); + + ResponseEntity response = restTemplate.postForEntity(url, new HttpEntity<>(payload, headers), JsonNode.class); + return handleResponse(response); + } + + private JsonNode captureOrders(String orderID) throws IOException { + String accessToken = generateAccessToken(); + String url = BASE_URL + "/v2/checkout/orders/" + orderID + "/capture"; + + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(accessToken); + headers.setContentType(MediaType.APPLICATION_JSON); + + ResponseEntity response = restTemplate.postForEntity(url, new HttpEntity<>(headers), JsonNode.class); + return handleResponse(response); + } + + private JsonNode handleResponse(ResponseEntity response) throws IOException { + if (response.getStatusCode().is2xxSuccessful()) { + return response.getBody(); + } else { + throw new IOException(response.getBody().toString()); + } + } + } +} diff --git a/advanced-integration/v2/server/java/src/main/resources/application.properties b/advanced-integration/v2/server/java/src/main/resources/application.properties new file mode 100644 index 00000000..88089970 --- /dev/null +++ b/advanced-integration/v2/server/java/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.application.name=v2-java +PAYPAL_CLIENT_ID= +PAYPAL_CLIENT_SECRET= diff --git a/advanced-integration/v2/.env.example b/advanced-integration/v2/server/node/.env.example similarity index 100% rename from advanced-integration/v2/.env.example rename to advanced-integration/v2/server/node/.env.example diff --git a/advanced-integration/v2/server/node/README.md b/advanced-integration/v2/server/node/README.md new file mode 100644 index 00000000..8a3c0250 --- /dev/null +++ b/advanced-integration/v2/server/node/README.md @@ -0,0 +1,19 @@ +# Advanced Integartion Node.js Sample + +PayPal Advanced Integration sample in Node.js + +## Running the sample + +1. Install the packages + + ```sh + npm install + ``` + +2. Run the server + + ```sh + npm run start + ``` + +3. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/advanced-integration/v2/server/node/package.json b/advanced-integration/v2/server/node/package.json new file mode 100644 index 00000000..f24544de --- /dev/null +++ b/advanced-integration/v2/server/node/package.json @@ -0,0 +1,22 @@ +{ + "name": "paypal-advanced-integration-backend-node", + "version": "1.0.0", + "private": true, + "type": "module", + "dependencies": { + "dotenv": "^16.3.1", + "express": "^4.18.2", + "node-fetch": "^3.3.2" + }, + "scripts": { + "server-dev": "nodemon server/server.js", + "start": "npm run server-dev", + "prod": "node server/server.js", + "format": "npx prettier --write **/*.{js,jsx,md}", + "format:check": "npx prettier --check **/*.{js,jsx,md}" + }, + "devDependencies": { + "concurrently": "^8.2.1", + "nodemon": "^3.0.1" + } +} diff --git a/advanced-integration/v2/server/server.js b/advanced-integration/v2/server/node/server/server.js similarity index 96% rename from advanced-integration/v2/server/server.js rename to advanced-integration/v2/server/node/server/server.js index f1188758..1e2f9d4a 100644 --- a/advanced-integration/v2/server/server.js +++ b/advanced-integration/v2/server/node/server/server.js @@ -2,16 +2,10 @@ import express from "express"; import fetch from "node-fetch"; import "dotenv/config"; -const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8888 } = process.env; +const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8080 } = process.env; const base = "https://api-m.sandbox.paypal.com"; const app = express(); -app.set("view engine", "ejs"); -app.set("views", "./server/views"); - -// host static files -app.use(express.static("client")); - // parse post params sent in body in json format app.use(express.json()); diff --git a/advanced-integration/v2/server/php/.gitignore b/advanced-integration/v2/server/php/.gitignore new file mode 100644 index 00000000..a725465a --- /dev/null +++ b/advanced-integration/v2/server/php/.gitignore @@ -0,0 +1 @@ +vendor/ \ No newline at end of file diff --git a/advanced-integration/v2/server/php/README.md b/advanced-integration/v2/server/php/README.md new file mode 100644 index 00000000..2f162d42 --- /dev/null +++ b/advanced-integration/v2/server/php/README.md @@ -0,0 +1,49 @@ +# Advanced Integration Sample Application - PHP + +This sample app demonstrates how to integrate with ACDC using PayPal's REST APIs. + +## Before You Code + +1. **Setup a PayPal Account** + + To get started, you'll need a developer, personal, or business account. + + [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer) + + You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts. + +2. **Create an Application** + + Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create). + +## How to Run Locally + +1. Replace your Client ID & Client Secret in the server/.env file: +2. Open the `.env` file in a text editor and replace the placeholders with the appropriate values. +3. Follow the below instructions to setup & run server. + +## Install the Composer + +We'll be using Composer (https://getcomposer.org/) for dependency management. To install Composer on a Mac, run the following command in the terminal: + +```bash +brew install composer +``` + +Composer can be downloaded for Windows from this link: https://getcomposer.org/download/. + +## To install the dependencies + +```bash +composer install +``` + +## To run the application in development, you can run this command + +```bash +composer start +``` + +Afterward, open http://localhost:8080 in your browser. + +That's it! diff --git a/advanced-integration/v2/server/php/composer.json b/advanced-integration/v2/server/php/composer.json new file mode 100644 index 00000000..5adaa5aa --- /dev/null +++ b/advanced-integration/v2/server/php/composer.json @@ -0,0 +1,28 @@ +{ + "description": "PayPal JS SDK Advanced Integration - Checkout Flow", + "license": "MIT", + "require": { + "php": "^7.4 || ^8.0", + "ext-json": "*", + "guzzlehttp/guzzle": "^7.9", + "monolog/monolog": "^2.8", + "php-di/php-di": "^6.4" + }, + "require-dev": { + "jangregor/phpstan-prophecy": "^1.0.0", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^9.5.26", + "squizlabs/php_codesniffer": "^3.7" + }, + "scripts": { + "start": "php -S localhost:8080 -t server", + "test": "phpunit" + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true + } + } +} \ No newline at end of file diff --git a/advanced-integration/v2/server/php/composer.lock b/advanced-integration/v2/server/php/composer.lock new file mode 100644 index 00000000..351abe8e --- /dev/null +++ b/advanced-integration/v2/server/php/composer.lock @@ -0,0 +1,4485 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "215478eda9b5efd723cd51c11808902f", + "packages": [ + { + "name": "fig/http-message-util", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "time": "2020-11-24T22:02:12+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:45:45+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2024-07-24T11:22:20+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2024-07-18T10:29:17+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2024-07-18T11:15:46+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v1.3.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", + "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "nesbot/carbon": "^2.61", + "pestphp/pest": "^1.21.3", + "phpstan/phpstan": "^1.8.2", + "symfony/var-dumper": "^5.4.11" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2023-11-08T14:08:06+00:00" + }, + { + "name": "monolog/monolog", + "version": "2.9.3", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/a30bfe2e142720dfa990d0a7e573997f5d884215", + "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.38 || ^9.6.19", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.9.3" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2024-04-12T20:52:51+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "FastRoute\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "support": { + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/master" + }, + "time": "2018-02-13T20:26:39+00:00" + }, + { + "name": "php-di/invoker", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2023-09-08T09:24:21+00:00" + }, + { + "name": "php-di/php-di", + "version": "6.4.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/ae0f1b3b03d8b29dff81747063cbfd6276246cc4", + "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4", + "shasum": "" + }, + "require": { + "laravel/serializable-closure": "^1.0", + "php": ">=7.4.0", + "php-di/invoker": "^2.0", + "php-di/phpdoc-reader": "^2.0.1", + "psr/container": "^1.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "doctrine/annotations": "~1.10", + "friendsofphp/php-cs-fixer": "^2.4", + "mnapoli/phpunit-easymock": "^1.2", + "ocramius/proxy-manager": "^2.11.2", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "DI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/6.4.0" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "time": "2022-04-09T16:46:38+00:00" + }, + { + "name": "php-di/phpdoc-reader", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PhpDocReader.git", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^8.5|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpDocReader\\": "src/PhpDocReader" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", + "keywords": [ + "phpdoc", + "reflection" + ], + "support": { + "issues": "https://github.com/PHP-DI/PhpDocReader/issues", + "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" + }, + "time": "2020-10-12T12:39:22+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:41:07+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" + }, + "time": "2023-04-10T20:06:20+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" + }, + "time": "2023-04-11T06:14:47+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "slim/http", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Http.git", + "reference": "a8def7b8e9eabd0cdc21654ad4a82606942e066a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Http/zipball/a8def7b8e9eabd0cdc21654ad4a82606942e066a", + "reference": "a8def7b8e9eabd0cdc21654ad4a82606942e066a", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "php": "^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "doctrine/instantiator": "^1.3.1", + "laminas/laminas-diactoros": "^3.1.0", + "nyholm/psr7": "^1.8.1", + "php-http/psr7-integration-tests": "^1.3.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Http\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + } + ], + "description": "Slim PSR-7 Object Decorators", + "homepage": "http://slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Http/issues", + "source": "https://github.com/slimphp/Slim-Http/tree/1.4.0" + }, + "time": "2024-06-24T18:27:41+00:00" + }, + { + "name": "slim/middleware", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Middleware.git", + "reference": "1190251a89a3044eda9d16dcb456dc92dba2d0c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Middleware/zipball/1190251a89a3044eda9d16dcb456dc92dba2d0c8", + "reference": "1190251a89a3044eda9d16dcb456dc92dba2d0c8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "slim/slim": ">=2.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Slim": "./src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "info@joshlockhart.com", + "homepage": "http://www.joshlockhart.com/" + } + ], + "description": "Slim Framework middleware", + "homepage": "http://github.com/codeguy/Slim", + "keywords": [ + "middleware", + "slim" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Middleware/issues", + "source": "https://github.com/slimphp/Slim-Middleware/tree/1.0.0" + }, + "abandoned": true, + "time": "2013-09-18T18:13:40+00:00" + }, + { + "name": "slim/psr7", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Psr7.git", + "reference": "753e9646def5ff4db1a06e5cf4ef539bfd30f467" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/753e9646def5ff4db1a06e5cf4ef539bfd30f467", + "reference": "753e9646def5ff4db1a06e5cf4ef539bfd30f467", + "shasum": "" + }, + "require": { + "fig/http-message-util": "^1.1.5", + "php": "^8.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.0 || ^2.0", + "ralouphie/getallheaders": "^3.0", + "symfony/polyfill-php80": "^1.29" + }, + "provide": { + "psr/http-factory-implementation": "^1.0", + "psr/http-message-implementation": "^1.0 || ^2.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "ext-json": "*", + "http-interop/http-factory-tests": "^1.1.0", + "php-http/psr7-integration-tests": "1.3.0", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.2", + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Psr7\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + } + ], + "description": "Strict PSR-7 implementation", + "homepage": "https://www.slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Psr7/issues", + "source": "https://github.com/slimphp/Slim-Psr7/tree/1.7.0" + }, + "time": "2024-06-08T14:48:17+00:00" + }, + { + "name": "slim/slim", + "version": "4.14.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "5943393b88716eb9e82c4161caa956af63423913" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/5943393b88716eb9e82c4161caa956af63423913", + "reference": "5943393b88716eb9e82c4161caa956af63423913", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/fast-route": "^1.3", + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "ext-simplexml": "*", + "guzzlehttp/psr7": "^2.6", + "httpsoft/http-message": "^1.1", + "httpsoft/http-server-request": "^1.1", + "laminas/laminas-diactoros": "^2.17 || ^3", + "nyholm/psr7": "^1.8", + "nyholm/psr7-server": "^1.1", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.1", + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^9.6", + "slim/http": "^1.3", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.10", + "vimeo/psalm": "^5.24" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://www.slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "support": { + "docs": "https://www.slimframework.com/docs/v4/", + "forum": "https://discourse.slimframework.com/", + "irc": "irc://irc.freenode.net:6667/slimphp", + "issues": "https://github.com/slimphp/Slim/issues", + "rss": "https://www.slimframework.com/blog/feed.rss", + "slack": "https://slimphp.slack.com/", + "source": "https://github.com/slimphp/Slim", + "wiki": "https://github.com/slimphp/Slim/wiki" + }, + "funding": [ + { + "url": "https://opencollective.com/slimphp", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slim/slim", + "type": "tidelift" + } + ], + "time": "2024-06-13T08:54:48+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:52:34+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/deprecations", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" + }, + "time": "2024-01-30T19:34:25+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "jangregor/phpstan-prophecy", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/Jan0707/phpstan-prophecy.git", + "reference": "5ee56c7db1d58f0578c82a35e3c1befe840e85a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jan0707/phpstan-prophecy/zipball/5ee56c7db1d58f0578c82a35e3c1befe840e85a9", + "reference": "5ee56c7db1d58f0578c82a35e3c1befe840e85a9", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "phpstan/phpstan": "^1.0.0" + }, + "conflict": { + "phpspec/prophecy": "<1.7.0 || >=2.0.0", + "phpunit/phpunit": "<6.0.0 || >=12.0.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.1.1", + "ergebnis/license": "^1.0.0", + "ergebnis/php-cs-fixer-config": "~2.2.0", + "phpspec/prophecy": "^1.7.0", + "phpunit/phpunit": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "JanGregor\\Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Gregor Emge-Triebel", + "email": "jan@jangregor.me" + } + ], + "description": "Provides a phpstan/phpstan extension for phpspec/prophecy", + "support": { + "issues": "https://github.com/Jan0707/phpstan-prophecy/issues", + "source": "https://github.com/Jan0707/phpstan-prophecy/tree/1.0.2" + }, + "time": "2024-04-03T08:15:54+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.12.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2024-06-12T14:39:25+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.1.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" + }, + "time": "2024-07-01T20:03:41+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.4.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.1", + "ext-filter": "*", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" + }, + "time": "2024-05-21T05:55:05+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "153ae662783729388a584b4361f2545e4d841e3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", + "reference": "153ae662783729388a584b4361f2545e4d841e3c", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.3 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" + }, + "time": "2024-02-23T11:10:43+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/67a759e7d8746d501c41536ba40cd9c0a07d6a87", + "reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2 || ^2.0", + "php": "^7.2 || 8.0.* || 8.1.* || 8.2.* || 8.3.*", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0 || ^5.0 || ^6.0", + "sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0 || ^6.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "dev", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.19.0" + }, + "time": "2024-02-29T11:52:51+00:00" + }, + { + "name": "phpspec/prophecy-phpunit", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "16e1247e139434bce0bac09848bc5c8d882940fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/16e1247e139434bce0bac09848bc5c8d882940fc", + "reference": "16e1247e139434bce0bac09848bc5c8d882940fc", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.18", + "phpunit/phpunit": "^9.1 || ^10.1 || ^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy-phpunit/issues", + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.2.0" + }, + "time": "2024-03-01T08:33:58+00:00" + }, + { + "name": "phpstan/extension-installer", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "f6b87faf9fc7978eab2f7919a8760bc9f58f9203" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f6b87faf9fc7978eab2f7919a8760bc9f58f9203", + "reference": "f6b87faf9fc7978eab2f7919a8760bc9f58f9203", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.1" + }, + "time": "2024-06-10T08:20:49+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.29.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" + }, + "time": "2024-05-31T08:52:43+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.11.8", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", + "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-07-24T07:01:22+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.31", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:37:42+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.20", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "49d7820565836236411f5dc002d16dd689cde42f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", + "reference": "49d7820565836236411f5dc002d16dd689cde42f", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.5.0 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.12.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2024-07-10T11:45:39+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:27:43+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:19:30+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:30:58+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:33:00+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:35:11+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:20:34+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-14T16:00:52+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.10.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-07-21T23:26:44+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^7.4 || ^8.0", + "ext-json": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/advanced-integration/v2/server/php/server/.env b/advanced-integration/v2/server/php/server/.env new file mode 100644 index 00000000..96d3bc76 --- /dev/null +++ b/advanced-integration/v2/server/php/server/.env @@ -0,0 +1,2 @@ +PAYPAL_CLIENT_ID= +PAYPAL_CLIENT_SECRET= \ No newline at end of file diff --git a/advanced-integration/v2/server/php/server/.htaccess b/advanced-integration/v2/server/php/server/.htaccess new file mode 100644 index 00000000..fe74ec5b --- /dev/null +++ b/advanced-integration/v2/server/php/server/.htaccess @@ -0,0 +1,34 @@ +Options All -Indexes + + +order allow,deny +deny from all + + + + RewriteEngine On + + # Redirect to HTTPS + # RewriteEngine On + # RewriteCond %{HTTPS} off + # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] + + # Some hosts may require you to use the `RewriteBase` directive. + # Determine the RewriteBase automatically and set it as environment variable. + # If you are using Apache aliases to do mass virtual hosting or installed the + # project in a subdirectory, the base path will be prepended to allow proper + # resolution of the index.php file and to redirect to the correct URI. It will + # work in environments without path prefix as well, providing a safe, one-size + # fits all solution. But as you do not need it in this case, you can comment + # the following 2 lines to eliminate the overhead. + RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ + RewriteRule ^(.*) - [E=BASE:%1] + + # If the above doesn't work you might need to set the `RewriteBase` directive manually, it should be the + # absolute physical path to the directory that contains this htaccess file. + # RewriteBase / + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [QSA,L] + diff --git a/advanced-integration/v2/server/php/server/index.php b/advanced-integration/v2/server/php/server/index.php new file mode 100644 index 00000000..81a25ada --- /dev/null +++ b/advanced-integration/v2/server/php/server/index.php @@ -0,0 +1,144 @@ + false]); + $response = $client->post("$base/v1/oauth2/token", [ + 'form_params' => [ + 'grant_type' => 'client_credentials' + ], + 'headers' => [ + 'Authorization' => "Basic $auth" + ] + ]); + + $data = json_decode($response->getBody(), true); + return $data['access_token']; +} + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +function createOrder($cart) { + global $base; + + $accessToken = generateAccessToken(); + + // Disabling certificate validation for local development + $client = new Client(['verify' => false]); + $payload = [ + 'intent' => 'CAPTURE', + 'purchase_units' => [ + [ + 'amount' => [ + 'currency_code' => 'USD', + 'value' => '100.00' + ] + ] + ], + ]; + + $response = $client->post("$base/v2/checkout/orders", [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer $accessToken" + ], + 'json' => $payload + ]); + + return handleResponse($response); +} + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +function captureOrder($orderID) { + global $base; + + $accessToken = generateAccessToken(); + + // Disabling certificate validation for local development + $client = new Client(['verify' => false]); + $response = $client->post("$base/v2/checkout/orders/$orderID/capture", [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer $accessToken" + ] + ]); + + return handleResponse($response); +} + +function handleResponse($response) { + $jsonResponse = json_decode($response->getBody(), true); + return [ + 'jsonResponse' => $jsonResponse, + 'httpStatusCode' => $response->getStatusCode() + ]; +} + +$endpoint = $_SERVER['REQUEST_URI']; +if($endpoint === '/') { + try { + $response = [ + "message" => "Server is running" + ]; + header('Content-Type: application/json'); + echo json_encode($response); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + +if($endpoint === '/api/orders') { + $data = json_decode(file_get_contents('php://input'), true); + $cart = $data['cart']; + header('Content-Type: application/json'); + try { + $orderResponse = createOrder($cart); + echo json_encode($orderResponse['jsonResponse']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + + +if(str_ends_with($endpoint, '/capture')) { + $urlSegments = explode('/', $endpoint); + end($urlSegments); // Will set the pointer to the end of array + $orderID = prev($urlSegments); + header('Content-Type: application/json'); + try { + $captureResponse = captureOrder($orderID); + echo json_encode($captureResponse['jsonResponse']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} +?> \ No newline at end of file diff --git a/advanced-integration/v2/server/views/checkout.ejs b/advanced-integration/v2/server/views/checkout.ejs deleted file mode 100644 index 5d129f60..00000000 --- a/advanced-integration/v2/server/views/checkout.ejs +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - PayPal JS SDK Advanced Integration - Checkout Flow - - -
- -
-
-
-
-
- -
- - -
-
- -
-
- -
-
- -
-
- -
-
- -
-

- -
-

- - - - \ No newline at end of file diff --git a/standard-integration/.gitignore b/standard-integration/.gitignore deleted file mode 100644 index 4c49bd78..00000000 --- a/standard-integration/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.env diff --git a/standard-integration/README.md b/standard-integration/README.md deleted file mode 100644 index 408396b8..00000000 --- a/standard-integration/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Standard Integration Example - -This folder contains example code for a Standard PayPal integration using both the JS SDK and Node.js to complete transactions with the PayPal REST API. - -## Instructions - -1. [Create an application](https://developer.paypal.com/dashboard/applications/sandbox/create) -2. Rename `.env.example` to `.env` and update `PAYPAL_CLIENT_ID` and `PAYPAL_CLIENT_SECRET` -3. Replace `test` in [client/checkout.html](client/checkout.html) with your app's client-id -4. Run `npm install` -5. Run `npm start` -6. Open http://localhost:8888 -7. Click "PayPal" and log in with one of your [Sandbox test accounts](https://developer.paypal.com/dashboard/accounts) diff --git a/standard-integration/client/checkout.html b/standard-integration/client/checkout.html deleted file mode 100644 index 7b959c2f..00000000 --- a/standard-integration/client/checkout.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - PayPal JS SDK Standard Integration - - -
-

- - - - - diff --git a/standard-integration/client/html/.env.example b/standard-integration/client/html/.env.example new file mode 100644 index 00000000..dbfed9bd --- /dev/null +++ b/standard-integration/client/html/.env.example @@ -0,0 +1,4 @@ +# Create an application to obtain credentials at +# https://developer.paypal.com/dashboard/applications/sandbox + +PAYPAL_CLIENT_ID=YOUR_CLIENT_ID_GOES_HERE diff --git a/standard-integration/client/html/.gitignore b/standard-integration/client/html/.gitignore new file mode 100644 index 00000000..ed648a05 --- /dev/null +++ b/standard-integration/client/html/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.local \ No newline at end of file diff --git a/standard-integration/client/html/README.md b/standard-integration/client/html/README.md new file mode 100644 index 00000000..5c79b001 --- /dev/null +++ b/standard-integration/client/html/README.md @@ -0,0 +1,74 @@ +# Standard Integration with PayPal : HTML/JS + +## Getting Started + +This guide will walk you through setting up and running the HTML/JS Standard Integration locally. + +### Before You Code + +1. **Setup a PayPal Account** + + To get started, you'll need a developer, personal, or business account. + + [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer) + + You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts. + +2. **Create an Application** + + Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create). + +### Installation + +```sh +npm install +``` + +### Configuration + +1. Environmental Variables (.env) + + - Rename the .env.example file to .env + - Update the following keys with their actual values - + + ```sh + PAYPAL_CLIENT_ID= + ``` + +2. Connecting the client and server (vite.config.js) + + - Open vite.config.js in the root directory. + - Locate the proxy configuration object. + - Update the proxy key to match the server's address and port. For example: + + ```js + export default defineConfig({ + + server: { + proxy: { + "/api": { + target: "http://localhost:8080", // Replace with your server URL + changeOrigin: true, + }, + }, + }, + }); + ``` + +3. Starting the development server + + - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory. + + - **Start the client**: + + ```sh + npm run dev + ``` + + This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). + +### Additional Notes + +- **Server Setup**: Make sure you have the server up and running before starting the client. +- **Environment Variables**: Carefully configure the environment variables in the .env file to match your setup. +- **Proxy Configuration**: The proxy setting in vite.config.js is crucial for routing API requests from the client to the server during development. diff --git a/standard-integration/client/app.js b/standard-integration/client/html/client/app.js similarity index 75% rename from standard-integration/client/app.js rename to standard-integration/client/html/client/app.js index cab942a0..4c70688e 100644 --- a/standard-integration/client/app.js +++ b/standard-integration/client/html/client/app.js @@ -1,5 +1,15 @@ window.paypal .Buttons({ + style: { + shape: "rect", + layout: "vertical", + color: "gold", + label: "paypal", + }, + message: { + amount: 100, + }, + async createOrder() { try { const response = await fetch("/api/orders", { @@ -23,19 +33,19 @@ window.paypal if (orderData.id) { return orderData.id; - } else { - const errorDetail = orderData?.details?.[0]; - const errorMessage = errorDetail - ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` - : JSON.stringify(orderData); - - throw new Error(errorMessage); } + const errorDetail = orderData?.details?.[0]; + const errorMessage = errorDetail + ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` + : JSON.stringify(orderData); + + throw new Error(errorMessage); } catch (error) { console.error(error); - resultMessage(`Could not initiate PayPal Checkout...

${error}`); + // resultMessage(`Could not initiate PayPal Checkout...

${error}`); } }, + async onApprove(data, actions) { try { const response = await fetch(`/api/orders/${data.orderID}/capture`, { @@ -55,7 +65,8 @@ window.paypal if (errorDetail?.issue === "INSTRUMENT_DECLINED") { // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() - // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ + // recoverable state, per + // https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ return actions.restart(); } else if (errorDetail) { // (2) Other non-recoverable errors -> Show a failure message @@ -69,26 +80,21 @@ window.paypal orderData?.purchase_units?.[0]?.payments?.captures?.[0] || orderData?.purchase_units?.[0]?.payments?.authorizations?.[0]; resultMessage( - `Transaction ${transaction.status}: ${transaction.id}

See console for all available details`, + `Transaction ${transaction.status}: ${transaction.id}
+
See console for all available details` ); console.log( "Capture result", orderData, - JSON.stringify(orderData, null, 2), + JSON.stringify(orderData, null, 2) ); } } catch (error) { console.error(error); resultMessage( - `Sorry, your transaction could not be processed...

${error}`, + `Sorry, your transaction could not be processed...

${error}` ); } }, }) .render("#paypal-button-container"); - -// Example function to show a result to the user. Your site's UI library can be used instead. -function resultMessage(message) { - const container = document.querySelector("#result-message"); - container.innerHTML = message; -} diff --git a/standard-integration/client/html/client/index.html b/standard-integration/client/html/client/index.html new file mode 100644 index 00000000..f993cfc1 --- /dev/null +++ b/standard-integration/client/html/client/index.html @@ -0,0 +1,20 @@ + + + + + + PayPal JS SDK Standard Integration + + + +
+

+ + + + + diff --git a/standard-integration/client/html/package.json b/standard-integration/client/html/package.json new file mode 100644 index 00000000..4685f847 --- /dev/null +++ b/standard-integration/client/html/package.json @@ -0,0 +1,17 @@ +{ + "name": "paypal-standard-integration-frontend-html", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "preview": "vite preview", + "start": "vite", + "format": "npx prettier --write **/*.{js,md}", + "format:check": "npx prettier --check **/*.{js,md}" + }, + "devDependencies": { + "dotenv": "^16.4.5", + "vite": "^5.4.2" + } +} diff --git a/standard-integration/client/html/vite.config.js b/standard-integration/client/html/vite.config.js new file mode 100644 index 00000000..76921cbb --- /dev/null +++ b/standard-integration/client/html/vite.config.js @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [], + envDir: "../", + envPrefix: "PAYPAL", + root: "client", + server: { + port: 3000, + proxy: { + "/api": { + target: "http://localhost:8080", + changeOrigin: true, + secure: false, + }, + }, + }, +}) \ No newline at end of file diff --git a/standard-integration/client/react/.env.example b/standard-integration/client/react/.env.example new file mode 100644 index 00000000..abea0386 --- /dev/null +++ b/standard-integration/client/react/.env.example @@ -0,0 +1 @@ +PAYPAL_CLIENT_ID=PAYPAL_CLIENT_ID \ No newline at end of file diff --git a/standard-integration/client/react/.gitignore b/standard-integration/client/react/.gitignore new file mode 100644 index 00000000..ed648a05 --- /dev/null +++ b/standard-integration/client/react/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.local \ No newline at end of file diff --git a/standard-integration/client/react/README.md b/standard-integration/client/react/README.md new file mode 100644 index 00000000..fdf7d214 --- /dev/null +++ b/standard-integration/client/react/README.md @@ -0,0 +1,74 @@ +# Standard Integration with PayPal : React + +## Getting Started + +This guide will walk you through setting up and running the React Standard Integration locally. + +### Before You Code + +1. **Setup a PayPal Account** + + To get started, you'll need a developer, personal, or business account. + + [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer) + + You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts. + +2. **Create an Application** + + Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create). + +### Installation + +```sh +npm install +``` + +### Configuration + +1. Environmental Variables (.env) + + - Rename the .env.example file to .env + - Update the following keys with their actual values - + + ```sh + PAYPAL_CLIENT_ID= + ``` + +2. Connecting the client and server (vite.config.js) + + - Open vite.config.js in the root directory. + - Locate the proxy configuration object. + - Update the proxy key to match the server's address and port. For example: + + ```js + export default defineConfig({ + + server: { + proxy: { + "/api": { + target: "http://localhost:8080", // Replace with your server URL + changeOrigin: true, + }, + }, + }, + }); + ``` + +3. Starting the development server + + - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory. + + - **Start the client**: + + ```sh + npm run dev + ``` + + This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). + +### Additional Notes + +- **Server Setup**: Make sure you have the server up and running before starting the client. +- **Environment Variables**: Carefully configure the environment variables in the .env file to match your setup. +- **Proxy Configuration**: The proxy setting in vite.config.js is crucial for routing API requests from the client to the server during development. diff --git a/standard-integration/client/react/client/App.jsx b/standard-integration/client/react/client/App.jsx new file mode 100644 index 00000000..ec740440 --- /dev/null +++ b/standard-integration/client/react/client/App.jsx @@ -0,0 +1,123 @@ +import React, { useState } from "react"; +import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js"; + +// Renders errors or successfull transactions on the screen. +function Message({ content }) { + return

{content}

; +} + +function App() { + const initialOptions = { + "client-id": import.meta.env.PAYPAL_CLIENT_ID, + "enable-funding": "venmo", + "buyer-country": "US", + currency: "USD", + components: "buttons", + }; + + const [message, setMessage] = useState(""); + + return ( +
+ + { + try { + const response = await fetch("/api/orders", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + // use the "body" param to optionally pass additional order information + // like product ids and quantities + body: JSON.stringify({ + cart: [ + { + id: "YOUR_PRODUCT_ID", + quantity: "YOUR_PRODUCT_QUANTITY", + }, + ], + }), + }); + + const orderData = await response.json(); + + if (orderData.id) { + return orderData.id; + } else { + const errorDetail = orderData?.details?.[0]; + const errorMessage = errorDetail + ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})` + : JSON.stringify(orderData); + + throw new Error(errorMessage); + } + } catch (error) { + console.error(error); + setMessage(`Could not initiate PayPal Checkout...${error}`); + } + }} + onApprove={async (data, actions) => { + try { + const response = await fetch( + `/api/orders/${data.orderID}/capture`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + } + ); + + const orderData = await response.json(); + // Three cases to handle: + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // (2) Other non-recoverable errors -> Show a failure message + // (3) Successful transaction -> Show confirmation or thank you message + + const errorDetail = orderData?.details?.[0]; + + if (errorDetail?.issue === "INSTRUMENT_DECLINED") { + // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart() + // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/ + return actions.restart(); + } else if (errorDetail) { + // (2) Other non-recoverable errors -> Show a failure message + throw new Error( + `${errorDetail.description} (${orderData.debug_id})` + ); + } else { + // (3) Successful transaction -> Show confirmation or thank you message + // Or go to another URL: actions.redirect('thank_you.html'); + const transaction = + orderData.purchase_units[0].payments.captures[0]; + setMessage( + `Transaction ${transaction.status}: ${transaction.id}. See console for all available details` + ); + console.log( + "Capture result", + orderData, + JSON.stringify(orderData, null, 2) + ); + } + } catch (error) { + console.error(error); + setMessage( + `Sorry, your transaction could not be processed...${error}` + ); + } + }} + /> + + +
+ ); +} + +export default App; diff --git a/standard-integration/client/react/client/index.html b/standard-integration/client/react/client/index.html new file mode 100644 index 00000000..1de16dbb --- /dev/null +++ b/standard-integration/client/react/client/index.html @@ -0,0 +1,17 @@ + + + + + + React PayPal JS SDK Standard Integration + + + +
+ + + diff --git a/standard-integration/client/react/client/main.jsx b/standard-integration/client/react/client/main.jsx new file mode 100644 index 00000000..569fdf2f --- /dev/null +++ b/standard-integration/client/react/client/main.jsx @@ -0,0 +1,9 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App.jsx"; + +ReactDOM.createRoot(document.getElementById("root")).render( + + + +); diff --git a/standard-integration/client/react/package.json b/standard-integration/client/react/package.json new file mode 100644 index 00000000..2ce526a8 --- /dev/null +++ b/standard-integration/client/react/package.json @@ -0,0 +1,24 @@ +{ + "name": "paypal-standard-integration-frontend-react", + "version": "1.0.0", + "private": true, + "type": "module", + "dependencies": { + "@paypal/react-paypal-js": "^8.6.0", + "dotenv": "^16.3.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "scripts": { + "client-dev": "vite", + "client-build": "vite build", + "client-preview": "vite preview", + "start": "npm run client-dev", + "format": "npx prettier --write **/*.{js,jsx,md}", + "format:check": "npx prettier --check **/*.{js,jsx,md}" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.1", + "vite": "^5.4.2" + } +} diff --git a/standard-integration/client/react/vite.config.js b/standard-integration/client/react/vite.config.js new file mode 100644 index 00000000..8049384e --- /dev/null +++ b/standard-integration/client/react/vite.config.js @@ -0,0 +1,20 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + root: "client", + envDir: "../", + envPrefix: "PAYPAL", + server: { + port: 3000, + proxy: { + "/api": { + target: "http://localhost:8080", + changeOrigin: true, + secure: false, + }, + }, + }, +}) \ No newline at end of file diff --git a/standard-integration/package.json b/standard-integration/package.json deleted file mode 100644 index f00bfb37..00000000 --- a/standard-integration/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "paypal-standard-integration", - "description": "Sample Node.js web app to integrate PayPal Standard Checkout for online payments", - "version": "1.0.0", - "main": "server/server.js", - "type": "module", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon server/server.js", - "format": "npx prettier --write **/*.{js,md}", - "format:check": "npx prettier --check **/*.{js,md}", - "lint": "npx eslint server/*.js client/*.js --no-config-lookup" - }, - "license": "Apache-2.0", - "dependencies": { - "dotenv": "^16.3.1", - "express": "^4.18.2", - "node-fetch": "^3.3.2" - }, - "devDependencies": { - "nodemon": "^3.0.1" - } -} diff --git a/standard-integration/server/dotnet/.gitignore b/standard-integration/server/dotnet/.gitignore new file mode 100644 index 00000000..cbbd0b5c --- /dev/null +++ b/standard-integration/server/dotnet/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ \ No newline at end of file diff --git a/standard-integration/server/dotnet/PayPalAdvancedIntegration.csproj b/standard-integration/server/dotnet/PayPalAdvancedIntegration.csproj new file mode 100644 index 00000000..6b5a7d0e --- /dev/null +++ b/standard-integration/server/dotnet/PayPalAdvancedIntegration.csproj @@ -0,0 +1,11 @@ + + + + net8.0 + PayPalStandardIntegration + + + + + + diff --git a/standard-integration/server/dotnet/README.md b/standard-integration/server/dotnet/README.md new file mode 100644 index 00000000..9dca45c3 --- /dev/null +++ b/standard-integration/server/dotnet/README.md @@ -0,0 +1,18 @@ +# Standard Integartion .NET Sample +PayPal Standard Integration sample in .NET + +## Running the sample + +1. Build the server + +~~~ +dotnet restore +~~~ + +2. Run the server + +~~~ +dotnet run +~~~ + +3. Go to [http://localhost:8080/](http://localhost:8080/) \ No newline at end of file diff --git a/standard-integration/server/dotnet/Server.cs b/standard-integration/server/dotnet/Server.cs new file mode 100644 index 00000000..eb24f0e8 --- /dev/null +++ b/standard-integration/server/dotnet/Server.cs @@ -0,0 +1,200 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; + +namespace PayPalStandardIntegration; + +public class Program +{ + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration( + (context, config) => + { + config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); + } + ) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseUrls("http://localhost:8080"); + webBuilder.UseStartup(); + }); +} + +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddMvc().AddNewtonsoftJson(); + services.AddHttpClient(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + app.UseRouting(); + app.UseStaticFiles(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } +} + +[ApiController] +public class CheckoutController : Controller +{ + private readonly IHttpClientFactory _httpClientFactory; + private IConfiguration _configuration { get; } + private string _paypalClientId + { + get { return _configuration["PAYPAL_CLIENT_ID"]; } + } + private string _paypalClientSecret + { + get { return _configuration["PAYPAL_CLIENT_SECRET"]; } + } + private readonly string _base = "https://api-m.sandbox.paypal.com"; + + public CheckoutController(IHttpClientFactory httpClientFactory, IConfiguration configuration) + { + _httpClientFactory = httpClientFactory; + _configuration = configuration; + } + + [HttpPost("api/orders")] + public async Task CreateOrder([FromBody] dynamic cart) + { + try + { + var result = await _CreateOrder(cart); + return StatusCode((int)result.httpStatusCode, result.jsonResponse); + } + catch (Exception ex) + { + Console.Error.WriteLine("Failed to create order:", ex); + return StatusCode(500, new { error = "Failed to create order." }); + } + } + + [HttpPost("api/orders/{orderID}/capture")] + public async Task CaptureOrder(string orderID) + { + try + { + var result = await _CaptureOrder(orderID); + return StatusCode((int)result.httpStatusCode, result.jsonResponse); + } + catch (Exception ex) + { + Console.Error.WriteLine("Failed to capture order:", ex); + return StatusCode(500, new { error = "Failed to capture order." }); + } + } + + private async Task GenerateAccessToken() + { + if (string.IsNullOrEmpty(_paypalClientId) || string.IsNullOrEmpty(_paypalClientSecret)) + { + throw new Exception("MISSING_API_CREDENTIALS"); + } + + var auth = Convert.ToBase64String( + Encoding.UTF8.GetBytes($"{_paypalClientId}:{_paypalClientSecret}") + ); + var client = _httpClientFactory.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Post, $"{_base}/v1/oauth2/token") + { + Content = new StringContent( + "grant_type=client_credentials", + Encoding.UTF8, + "application/x-www-form-urlencoded" + ) + }; + request.Headers.Add("Authorization", $"Basic {auth}"); + + var response = await client.SendAsync(request); + var data = JsonConvert.DeserializeObject( + await response.Content.ReadAsStringAsync() + ); + return data.access_token; + } + + private async Task _CreateOrder(dynamic cart) + { + var accessToken = await GenerateAccessToken(); + var url = $"{_base}/v2/checkout/orders"; + var payload = new + { + intent = "CAPTURE", + purchase_units = new[] + { + new { amount = new { currency_code = "USD", value = "100.00" } } + } + }; + + var client = _httpClientFactory.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = new StringContent( + JsonConvert.SerializeObject(payload), + Encoding.UTF8, + "application/json" + ) + }; + request.Headers.Add("Authorization", $"Bearer {accessToken}"); + + var response = await client.SendAsync(request); + return await HandleResponse(response); + } + + private async Task _CaptureOrder(string orderID) + { + var accessToken = await GenerateAccessToken(); + var url = $"{_base}/v2/checkout/orders/{orderID}/capture"; + + var client = _httpClientFactory.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = new StringContent("", Encoding.UTF8, "application/json") + }; + request.Headers.Add("Authorization", $"Bearer {accessToken}"); + + var response = await client.SendAsync(request); + return await HandleResponse(response); + } + + private async Task HandleResponse(HttpResponseMessage response) + { + try + { + var jsonResponse = JsonConvert.DeserializeObject( + await response.Content.ReadAsStringAsync() + ); + return new { jsonResponse, httpStatusCode = response.StatusCode }; + } + catch (Exception) + { + var errorMessage = await response.Content.ReadAsStringAsync(); + throw new Exception(errorMessage); + } + } +} diff --git a/standard-integration/server/dotnet/appsettings.json b/standard-integration/server/dotnet/appsettings.json new file mode 100644 index 00000000..019194eb --- /dev/null +++ b/standard-integration/server/dotnet/appsettings.json @@ -0,0 +1,4 @@ +{ + "PAYPAL_CLIENT_ID": "PAYPAL_CLIENT_ID", + "PAYPAL_CLIENT_SECRET": "PAYPAL_CLIENT_SECRET" +} diff --git a/standard-integration/server/java/.gitignore b/standard-integration/server/java/.gitignore new file mode 100644 index 00000000..9f970225 --- /dev/null +++ b/standard-integration/server/java/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/standard-integration/server/java/README.md b/standard-integration/server/java/README.md new file mode 100644 index 00000000..343200e7 --- /dev/null +++ b/standard-integration/server/java/README.md @@ -0,0 +1,18 @@ +# Standard Integartion Java Sample +PayPal Standard Integration sample in Java + +## Running the sample + +1. Build the server + +~~~ +mvn clean install +~~~ + +2. Run the server + +~~~ +mvn spring-boot:run +~~~ + +3. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/standard-integration/server/java/pom.xml b/standard-integration/server/java/pom.xml new file mode 100644 index 00000000..48e7a01c --- /dev/null +++ b/standard-integration/server/java/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.2 + + + com.paypal.sample + advanced-integration + 0.0.1-SNAPSHOT + PayPal Standard Integration + Sample Java demo application for PayPal JS SDK Standard Integration + + + + + + + + + + + + + + + 22 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/standard-integration/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java b/standard-integration/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java new file mode 100644 index 00000000..b4f3b4ae --- /dev/null +++ b/standard-integration/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java @@ -0,0 +1,140 @@ +package com.paypal.sample; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.util.Base64; +import java.util.Map; + +@SpringBootApplication +public class SampleAppApplication { + + @Value("${PAYPAL_CLIENT_ID}") + private String PAYPAL_CLIENT_ID; + + @Value("${PAYPAL_CLIENT_SECRET}") + private String PAYPAL_CLIENT_SECRET; + + private final String BASE_URL = "https://api-m.sandbox.paypal.com"; + + public static void main(String[] args) { + SpringApplication.run(SampleAppApplication.class, args); + } + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + @Controller + @RequestMapping("/") + public class CheckoutController { + + private final RestTemplate restTemplate; + private final ObjectMapper objectMapper; + + public CheckoutController(RestTemplate restTemplate, ObjectMapper objectMapper) { + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + } + + @PostMapping("/api/orders") + public ResponseEntity createOrder(@RequestBody Map request) { + try { + String cart = objectMapper.writeValueAsString(request.get("cart")); + JsonNode response = createOrder(cart); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + e.printStackTrace(); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @PostMapping("/api/orders/{orderID}/capture") + public ResponseEntity captureOrder(@PathVariable String orderID) { + try { + JsonNode response = captureOrders(orderID); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + e.printStackTrace(); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + private String generateAccessToken() throws IOException { + if (PAYPAL_CLIENT_ID == null || PAYPAL_CLIENT_SECRET == null) { + throw new IllegalArgumentException("MISSING_API_CREDENTIALS"); + } + String auth = Base64.getEncoder().encodeToString((PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET).getBytes()); + HttpHeaders headers = new HttpHeaders(); + headers.setBasicAuth(auth); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("grant_type", "client_credentials"); + + ResponseEntity response = restTemplate.postForEntity(BASE_URL + "/v1/oauth2/token", new HttpEntity<>(body, headers), JsonNode.class); + return response.getBody().get("access_token").asText(); + } + + private JsonNode createOrder(String cart) throws IOException { + String accessToken = generateAccessToken(); + String url = BASE_URL + "/v2/checkout/orders"; + + ObjectNode payload = objectMapper.createObjectNode(); + payload.put("intent", "CAPTURE"); + ObjectNode purchaseUnit = payload.putArray("purchase_units").addObject(); + ObjectNode amount = purchaseUnit.putObject("amount"); + amount.put("currency_code", "USD"); + amount.put("value", "100.00"); + + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(accessToken); + headers.setContentType(MediaType.APPLICATION_JSON); + + ResponseEntity response = restTemplate.postForEntity(url, new HttpEntity<>(payload, headers), JsonNode.class); + return handleResponse(response); + } + + private JsonNode captureOrders(String orderID) throws IOException { + String accessToken = generateAccessToken(); + String url = BASE_URL + "/v2/checkout/orders/" + orderID + "/capture"; + + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(accessToken); + headers.setContentType(MediaType.APPLICATION_JSON); + + ResponseEntity response = restTemplate.postForEntity(url, new HttpEntity<>(headers), JsonNode.class); + return handleResponse(response); + } + + private JsonNode handleResponse(ResponseEntity response) throws IOException { + if (response.getStatusCode().is2xxSuccessful()) { + return response.getBody(); + } else { + throw new IOException(response.getBody().toString()); + } + } + } +} diff --git a/standard-integration/server/java/src/main/resources/application.properties b/standard-integration/server/java/src/main/resources/application.properties new file mode 100644 index 00000000..88089970 --- /dev/null +++ b/standard-integration/server/java/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.application.name=v2-java +PAYPAL_CLIENT_ID= +PAYPAL_CLIENT_SECRET= diff --git a/standard-integration/.env.example b/standard-integration/server/node/.env.example similarity index 100% rename from standard-integration/.env.example rename to standard-integration/server/node/.env.example diff --git a/standard-integration/server/node/.gitignore b/standard-integration/server/node/.gitignore new file mode 100644 index 00000000..21ee8d3d --- /dev/null +++ b/standard-integration/server/node/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +*.local \ No newline at end of file diff --git a/standard-integration/server/node/README.md b/standard-integration/server/node/README.md new file mode 100644 index 00000000..a9ddb604 --- /dev/null +++ b/standard-integration/server/node/README.md @@ -0,0 +1,19 @@ +# Standard Integartion Node.js Sample + +PayPal Standard Integration sample in Node.js + +## Running the sample + +1. Install the packages + + ```sh + npm install + ``` + +2. Run the server + + ```sh + npm run start + ``` + +3. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/standard-integration/server/node/package.json b/standard-integration/server/node/package.json new file mode 100644 index 00000000..006a766d --- /dev/null +++ b/standard-integration/server/node/package.json @@ -0,0 +1,22 @@ +{ + "name": "paypal-standard-integration-backend-node", + "version": "1.0.0", + "private": true, + "type": "module", + "dependencies": { + "dotenv": "^16.3.1", + "express": "^4.18.2", + "node-fetch": "^3.3.2" + }, + "scripts": { + "server-dev": "nodemon server/server.js", + "start": "npm run server-dev", + "prod": "node server/server.js", + "format": "npx prettier --write **/*.{js,jsx,md}", + "format:check": "npx prettier --check **/*.{js,jsx,md}" + }, + "devDependencies": { + "concurrently": "^8.2.1", + "nodemon": "^3.0.1" + } +} diff --git a/standard-integration/server/server.js b/standard-integration/server/node/server/server.js similarity index 93% rename from standard-integration/server/server.js rename to standard-integration/server/node/server/server.js index fba19829..1e2f9d4a 100644 --- a/standard-integration/server/server.js +++ b/standard-integration/server/node/server/server.js @@ -1,15 +1,11 @@ import express from "express"; import fetch from "node-fetch"; import "dotenv/config"; -import path from "path"; -const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8888 } = process.env; +const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8080 } = process.env; const base = "https://api-m.sandbox.paypal.com"; const app = express(); -// host static files -app.use(express.static("client")); - // parse post params sent in body in json format app.use(express.json()); @@ -59,7 +55,7 @@ const createOrder = async (cart) => { { amount: { currency_code: "USD", - value: "110.00", + value: "100.00", }, }, ], @@ -142,9 +138,15 @@ app.post("/api/orders/:orderID/capture", async (req, res) => { } }); -// serve index.html -app.get("/", (req, res) => { - res.sendFile(path.resolve("./client/checkout.html")); +// render checkout page with client id & unique client token +app.get("/", async (req, res) => { + try { + res.render("checkout", { + clientId: PAYPAL_CLIENT_ID, + }); + } catch (err) { + res.status(500).send(err.message); + } }); app.listen(PORT, () => { diff --git a/standard-integration/server/php/.gitignore b/standard-integration/server/php/.gitignore new file mode 100644 index 00000000..a725465a --- /dev/null +++ b/standard-integration/server/php/.gitignore @@ -0,0 +1 @@ +vendor/ \ No newline at end of file diff --git a/standard-integration/server/php/README.md b/standard-integration/server/php/README.md new file mode 100644 index 00000000..5c5b5ed6 --- /dev/null +++ b/standard-integration/server/php/README.md @@ -0,0 +1,49 @@ +# Standard Integration Sample Application - PHP + +This sample app demonstrates how to integrate with ACDC using PayPal's REST APIs. + +## Before You Code + +1. **Setup a PayPal Account** + + To get started, you'll need a developer, personal, or business account. + + [Sign Up](https://www.paypal.com/signin/client?flow=provisionUser) or [Log In](https://www.paypal.com/signin?returnUri=https%253A%252F%252Fdeveloper.paypal.com%252Fdashboard&intent=developer) + + You'll then need to visit the [Developer Dashboard](https://developer.paypal.com/dashboard/) to obtain credentials and to make sandbox accounts. + +2. **Create an Application** + + Once you've setup a PayPal account, you'll need to obtain a **Client ID** and **Secret**. [Create a sandbox application](https://developer.paypal.com/dashboard/applications/sandbox/create). + +## How to Run Locally + +1. Replace your Client ID & Client Secret in the server/.env file: +2. Open the `.env` file in a text editor and replace the placeholders with the appropriate values. +3. Follow the below instructions to setup & run server. + +## Install the Composer + +We'll be using Composer (https://getcomposer.org/) for dependency management. To install Composer on a Mac, run the following command in the terminal: + +```bash +brew install composer +``` + +Composer can be downloaded for Windows from this link: https://getcomposer.org/download/. + +## To install the dependencies + +```bash +composer install +``` + +## To run the application in development, you can run this command + +```bash +composer start +``` + +Afterward, open http://localhost:8080 in your browser. + +That's it! diff --git a/standard-integration/server/php/composer.json b/standard-integration/server/php/composer.json new file mode 100644 index 00000000..7f87a9c2 --- /dev/null +++ b/standard-integration/server/php/composer.json @@ -0,0 +1,28 @@ +{ + "description": "PayPal JS SDK Standard Integration - Checkout Flow", + "license": "MIT", + "require": { + "php": "^7.4 || ^8.0", + "ext-json": "*", + "guzzlehttp/guzzle": "^7.9", + "monolog/monolog": "^2.8", + "php-di/php-di": "^6.4" + }, + "require-dev": { + "jangregor/phpstan-prophecy": "^1.0.0", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^9.5.26", + "squizlabs/php_codesniffer": "^3.7" + }, + "scripts": { + "start": "php -S localhost:8080 -t server", + "test": "phpunit" + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true + } + } +} \ No newline at end of file diff --git a/standard-integration/server/php/composer.lock b/standard-integration/server/php/composer.lock new file mode 100644 index 00000000..351abe8e --- /dev/null +++ b/standard-integration/server/php/composer.lock @@ -0,0 +1,4485 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "215478eda9b5efd723cd51c11808902f", + "packages": [ + { + "name": "fig/http-message-util", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "time": "2020-11-24T22:02:12+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:45:45+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2024-07-24T11:22:20+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2024-07-18T10:29:17+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2024-07-18T11:15:46+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v1.3.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", + "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "nesbot/carbon": "^2.61", + "pestphp/pest": "^1.21.3", + "phpstan/phpstan": "^1.8.2", + "symfony/var-dumper": "^5.4.11" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2023-11-08T14:08:06+00:00" + }, + { + "name": "monolog/monolog", + "version": "2.9.3", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/a30bfe2e142720dfa990d0a7e573997f5d884215", + "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.38 || ^9.6.19", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.9.3" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2024-04-12T20:52:51+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "FastRoute\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "support": { + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/master" + }, + "time": "2018-02-13T20:26:39+00:00" + }, + { + "name": "php-di/invoker", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2023-09-08T09:24:21+00:00" + }, + { + "name": "php-di/php-di", + "version": "6.4.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/ae0f1b3b03d8b29dff81747063cbfd6276246cc4", + "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4", + "shasum": "" + }, + "require": { + "laravel/serializable-closure": "^1.0", + "php": ">=7.4.0", + "php-di/invoker": "^2.0", + "php-di/phpdoc-reader": "^2.0.1", + "psr/container": "^1.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "doctrine/annotations": "~1.10", + "friendsofphp/php-cs-fixer": "^2.4", + "mnapoli/phpunit-easymock": "^1.2", + "ocramius/proxy-manager": "^2.11.2", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "DI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/6.4.0" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "time": "2022-04-09T16:46:38+00:00" + }, + { + "name": "php-di/phpdoc-reader", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PhpDocReader.git", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^8.5|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpDocReader\\": "src/PhpDocReader" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", + "keywords": [ + "phpdoc", + "reflection" + ], + "support": { + "issues": "https://github.com/PHP-DI/PhpDocReader/issues", + "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" + }, + "time": "2020-10-12T12:39:22+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:41:07+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" + }, + "time": "2023-04-10T20:06:20+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" + }, + "time": "2023-04-11T06:14:47+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "slim/http", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Http.git", + "reference": "a8def7b8e9eabd0cdc21654ad4a82606942e066a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Http/zipball/a8def7b8e9eabd0cdc21654ad4a82606942e066a", + "reference": "a8def7b8e9eabd0cdc21654ad4a82606942e066a", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "php": "^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "doctrine/instantiator": "^1.3.1", + "laminas/laminas-diactoros": "^3.1.0", + "nyholm/psr7": "^1.8.1", + "php-http/psr7-integration-tests": "^1.3.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Http\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + } + ], + "description": "Slim PSR-7 Object Decorators", + "homepage": "http://slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Http/issues", + "source": "https://github.com/slimphp/Slim-Http/tree/1.4.0" + }, + "time": "2024-06-24T18:27:41+00:00" + }, + { + "name": "slim/middleware", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Middleware.git", + "reference": "1190251a89a3044eda9d16dcb456dc92dba2d0c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Middleware/zipball/1190251a89a3044eda9d16dcb456dc92dba2d0c8", + "reference": "1190251a89a3044eda9d16dcb456dc92dba2d0c8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "slim/slim": ">=2.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Slim": "./src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "info@joshlockhart.com", + "homepage": "http://www.joshlockhart.com/" + } + ], + "description": "Slim Framework middleware", + "homepage": "http://github.com/codeguy/Slim", + "keywords": [ + "middleware", + "slim" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Middleware/issues", + "source": "https://github.com/slimphp/Slim-Middleware/tree/1.0.0" + }, + "abandoned": true, + "time": "2013-09-18T18:13:40+00:00" + }, + { + "name": "slim/psr7", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Psr7.git", + "reference": "753e9646def5ff4db1a06e5cf4ef539bfd30f467" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/753e9646def5ff4db1a06e5cf4ef539bfd30f467", + "reference": "753e9646def5ff4db1a06e5cf4ef539bfd30f467", + "shasum": "" + }, + "require": { + "fig/http-message-util": "^1.1.5", + "php": "^8.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.0 || ^2.0", + "ralouphie/getallheaders": "^3.0", + "symfony/polyfill-php80": "^1.29" + }, + "provide": { + "psr/http-factory-implementation": "^1.0", + "psr/http-message-implementation": "^1.0 || ^2.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "ext-json": "*", + "http-interop/http-factory-tests": "^1.1.0", + "php-http/psr7-integration-tests": "1.3.0", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.2", + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Psr7\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + } + ], + "description": "Strict PSR-7 implementation", + "homepage": "https://www.slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Psr7/issues", + "source": "https://github.com/slimphp/Slim-Psr7/tree/1.7.0" + }, + "time": "2024-06-08T14:48:17+00:00" + }, + { + "name": "slim/slim", + "version": "4.14.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "5943393b88716eb9e82c4161caa956af63423913" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/5943393b88716eb9e82c4161caa956af63423913", + "reference": "5943393b88716eb9e82c4161caa956af63423913", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/fast-route": "^1.3", + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "ext-simplexml": "*", + "guzzlehttp/psr7": "^2.6", + "httpsoft/http-message": "^1.1", + "httpsoft/http-server-request": "^1.1", + "laminas/laminas-diactoros": "^2.17 || ^3", + "nyholm/psr7": "^1.8", + "nyholm/psr7-server": "^1.1", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.1", + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^9.6", + "slim/http": "^1.3", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.10", + "vimeo/psalm": "^5.24" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://www.slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "support": { + "docs": "https://www.slimframework.com/docs/v4/", + "forum": "https://discourse.slimframework.com/", + "irc": "irc://irc.freenode.net:6667/slimphp", + "issues": "https://github.com/slimphp/Slim/issues", + "rss": "https://www.slimframework.com/blog/feed.rss", + "slack": "https://slimphp.slack.com/", + "source": "https://github.com/slimphp/Slim", + "wiki": "https://github.com/slimphp/Slim/wiki" + }, + "funding": [ + { + "url": "https://opencollective.com/slimphp", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slim/slim", + "type": "tidelift" + } + ], + "time": "2024-06-13T08:54:48+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:52:34+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/deprecations", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" + }, + "time": "2024-01-30T19:34:25+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "jangregor/phpstan-prophecy", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/Jan0707/phpstan-prophecy.git", + "reference": "5ee56c7db1d58f0578c82a35e3c1befe840e85a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jan0707/phpstan-prophecy/zipball/5ee56c7db1d58f0578c82a35e3c1befe840e85a9", + "reference": "5ee56c7db1d58f0578c82a35e3c1befe840e85a9", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "phpstan/phpstan": "^1.0.0" + }, + "conflict": { + "phpspec/prophecy": "<1.7.0 || >=2.0.0", + "phpunit/phpunit": "<6.0.0 || >=12.0.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.1.1", + "ergebnis/license": "^1.0.0", + "ergebnis/php-cs-fixer-config": "~2.2.0", + "phpspec/prophecy": "^1.7.0", + "phpunit/phpunit": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "JanGregor\\Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Gregor Emge-Triebel", + "email": "jan@jangregor.me" + } + ], + "description": "Provides a phpstan/phpstan extension for phpspec/prophecy", + "support": { + "issues": "https://github.com/Jan0707/phpstan-prophecy/issues", + "source": "https://github.com/Jan0707/phpstan-prophecy/tree/1.0.2" + }, + "time": "2024-04-03T08:15:54+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.12.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2024-06-12T14:39:25+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.1.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" + }, + "time": "2024-07-01T20:03:41+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.4.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.1", + "ext-filter": "*", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" + }, + "time": "2024-05-21T05:55:05+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "153ae662783729388a584b4361f2545e4d841e3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", + "reference": "153ae662783729388a584b4361f2545e4d841e3c", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.3 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" + }, + "time": "2024-02-23T11:10:43+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/67a759e7d8746d501c41536ba40cd9c0a07d6a87", + "reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2 || ^2.0", + "php": "^7.2 || 8.0.* || 8.1.* || 8.2.* || 8.3.*", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0 || ^5.0 || ^6.0", + "sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0 || ^6.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "dev", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.19.0" + }, + "time": "2024-02-29T11:52:51+00:00" + }, + { + "name": "phpspec/prophecy-phpunit", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "16e1247e139434bce0bac09848bc5c8d882940fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/16e1247e139434bce0bac09848bc5c8d882940fc", + "reference": "16e1247e139434bce0bac09848bc5c8d882940fc", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.18", + "phpunit/phpunit": "^9.1 || ^10.1 || ^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy-phpunit/issues", + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.2.0" + }, + "time": "2024-03-01T08:33:58+00:00" + }, + { + "name": "phpstan/extension-installer", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "f6b87faf9fc7978eab2f7919a8760bc9f58f9203" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f6b87faf9fc7978eab2f7919a8760bc9f58f9203", + "reference": "f6b87faf9fc7978eab2f7919a8760bc9f58f9203", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.1" + }, + "time": "2024-06-10T08:20:49+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.29.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" + }, + "time": "2024-05-31T08:52:43+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.11.8", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", + "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-07-24T07:01:22+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.31", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:37:42+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.20", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "49d7820565836236411f5dc002d16dd689cde42f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", + "reference": "49d7820565836236411f5dc002d16dd689cde42f", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.5.0 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.12.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2024-07-10T11:45:39+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:27:43+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:19:30+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:30:58+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:33:00+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:35:11+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:20:34+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-14T16:00:52+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.10.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-07-21T23:26:44+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^7.4 || ^8.0", + "ext-json": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/standard-integration/server/php/server/.env b/standard-integration/server/php/server/.env new file mode 100644 index 00000000..96d3bc76 --- /dev/null +++ b/standard-integration/server/php/server/.env @@ -0,0 +1,2 @@ +PAYPAL_CLIENT_ID= +PAYPAL_CLIENT_SECRET= \ No newline at end of file diff --git a/standard-integration/server/php/server/.htaccess b/standard-integration/server/php/server/.htaccess new file mode 100644 index 00000000..fe74ec5b --- /dev/null +++ b/standard-integration/server/php/server/.htaccess @@ -0,0 +1,34 @@ +Options All -Indexes + + +order allow,deny +deny from all + + + + RewriteEngine On + + # Redirect to HTTPS + # RewriteEngine On + # RewriteCond %{HTTPS} off + # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] + + # Some hosts may require you to use the `RewriteBase` directive. + # Determine the RewriteBase automatically and set it as environment variable. + # If you are using Apache aliases to do mass virtual hosting or installed the + # project in a subdirectory, the base path will be prepended to allow proper + # resolution of the index.php file and to redirect to the correct URI. It will + # work in environments without path prefix as well, providing a safe, one-size + # fits all solution. But as you do not need it in this case, you can comment + # the following 2 lines to eliminate the overhead. + RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ + RewriteRule ^(.*) - [E=BASE:%1] + + # If the above doesn't work you might need to set the `RewriteBase` directive manually, it should be the + # absolute physical path to the directory that contains this htaccess file. + # RewriteBase / + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [QSA,L] + diff --git a/standard-integration/server/php/server/index.php b/standard-integration/server/php/server/index.php new file mode 100644 index 00000000..81a25ada --- /dev/null +++ b/standard-integration/server/php/server/index.php @@ -0,0 +1,144 @@ + false]); + $response = $client->post("$base/v1/oauth2/token", [ + 'form_params' => [ + 'grant_type' => 'client_credentials' + ], + 'headers' => [ + 'Authorization' => "Basic $auth" + ] + ]); + + $data = json_decode($response->getBody(), true); + return $data['access_token']; +} + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +function createOrder($cart) { + global $base; + + $accessToken = generateAccessToken(); + + // Disabling certificate validation for local development + $client = new Client(['verify' => false]); + $payload = [ + 'intent' => 'CAPTURE', + 'purchase_units' => [ + [ + 'amount' => [ + 'currency_code' => 'USD', + 'value' => '100.00' + ] + ] + ], + ]; + + $response = $client->post("$base/v2/checkout/orders", [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer $accessToken" + ], + 'json' => $payload + ]); + + return handleResponse($response); +} + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +function captureOrder($orderID) { + global $base; + + $accessToken = generateAccessToken(); + + // Disabling certificate validation for local development + $client = new Client(['verify' => false]); + $response = $client->post("$base/v2/checkout/orders/$orderID/capture", [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer $accessToken" + ] + ]); + + return handleResponse($response); +} + +function handleResponse($response) { + $jsonResponse = json_decode($response->getBody(), true); + return [ + 'jsonResponse' => $jsonResponse, + 'httpStatusCode' => $response->getStatusCode() + ]; +} + +$endpoint = $_SERVER['REQUEST_URI']; +if($endpoint === '/') { + try { + $response = [ + "message" => "Server is running" + ]; + header('Content-Type: application/json'); + echo json_encode($response); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + +if($endpoint === '/api/orders') { + $data = json_decode(file_get_contents('php://input'), true); + $cart = $data['cart']; + header('Content-Type: application/json'); + try { + $orderResponse = createOrder($cart); + echo json_encode($orderResponse['jsonResponse']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + + +if(str_ends_with($endpoint, '/capture')) { + $urlSegments = explode('/', $endpoint); + end($urlSegments); // Will set the pointer to the end of array + $orderID = prev($urlSegments); + header('Content-Type: application/json'); + try { + $captureResponse = captureOrder($orderID); + echo json_encode($captureResponse['jsonResponse']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} +?> \ No newline at end of file From bb12328c7c76ac27b8239463b77e01fabf2a10ce Mon Sep 17 00:00:00 2001 From: rekhaabaidipati <130034318+rekhaabaidipati@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:11:26 -0700 Subject: [PATCH 30/34] Add client and server language selection while launching code spaces (#159) --- .../advanced-integration-v1/devcontainer.json | 2 +- .../devcontainer.json | 56 +++++++ .../welcome-message.sh | 0 .../devcontainer.json | 57 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 56 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 56 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 56 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 57 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 56 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 56 +++++++ .../welcome-message.sh | 23 +++ .devcontainer/post-commands.sh | 104 +++++++++++++ .../save-payment-method/devcontainer.json | 2 +- .../devcontainer.json | 55 +++++++ .../welcome-message.sh | 0 .../devcontainer.json | 56 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 37 +++-- .../welcome-message.sh | 23 +++ .../devcontainer.json | 55 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 55 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 56 +++++++ .../welcome-message.sh | 23 +++ .../devcontainer.json | 37 +++-- .../welcome-message.sh | 23 +++ .../devcontainer.json | 55 +++++++ .../welcome-message.sh | 23 +++ .devcontainer/update_settings.sh | 140 ++++++++++++++++++ .gitignore | 7 + README.md | 13 +- advanced-integration/v2/client/html/README.md | 6 +- .../v2/client/react/README.md | 6 +- .../v2/client/react/client/App.jsx | 12 +- .../v2/server/dotnet/README.md | 35 +++-- .../v2/server/dotnet/Server.cs | 10 +- .../v2/server/dotnet/appsettings.json | 4 - advanced-integration/v2/server/java/README.md | 35 +++-- advanced-integration/v2/server/java/pom.xml | 2 +- .../src/main/resources/application.properties | 4 +- advanced-integration/v2/server/node/README.md | 34 +++-- advanced-integration/v2/server/php/README.md | 20 ++- .../v2/server/php/server/.env | 2 - .../v2/server/php/server/index.php | 31 ++-- standard-integration/client/html/README.md | 6 +- .../client/html/client/app.js | 8 +- standard-integration/client/react/README.md | 6 +- standard-integration/server/dotnet/README.md | 35 +++-- standard-integration/server/dotnet/Server.cs | 10 +- .../server/dotnet/appsettings.json | 4 - standard-integration/server/java/README.md | 35 +++-- standard-integration/server/java/pom.xml | 2 +- .../src/main/resources/application.properties | 4 +- standard-integration/server/node/README.md | 34 +++-- standard-integration/server/php/README.md | 20 ++- standard-integration/server/php/server/.env | 2 - .../server/php/server/index.php | 31 ++-- 64 files changed, 1674 insertions(+), 170 deletions(-) create mode 100644 .devcontainer/advanced-integration-v2-html-dotnet/devcontainer.json rename .devcontainer/{advanced-integration-v2 => advanced-integration-v2-html-dotnet}/welcome-message.sh (100%) create mode 100644 .devcontainer/advanced-integration-v2-html-java/devcontainer.json create mode 100644 .devcontainer/advanced-integration-v2-html-java/welcome-message.sh create mode 100644 .devcontainer/advanced-integration-v2-html-node/devcontainer.json create mode 100644 .devcontainer/advanced-integration-v2-html-node/welcome-message.sh create mode 100644 .devcontainer/advanced-integration-v2-html-php/devcontainer.json create mode 100644 .devcontainer/advanced-integration-v2-html-php/welcome-message.sh create mode 100644 .devcontainer/advanced-integration-v2-react-dotnet/devcontainer.json create mode 100644 .devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh create mode 100644 .devcontainer/advanced-integration-v2-react-java/devcontainer.json create mode 100644 .devcontainer/advanced-integration-v2-react-java/welcome-message.sh create mode 100644 .devcontainer/advanced-integration-v2-react-node/devcontainer.json create mode 100644 .devcontainer/advanced-integration-v2-react-node/welcome-message.sh create mode 100644 .devcontainer/advanced-integration-v2-react-php/devcontainer.json create mode 100644 .devcontainer/advanced-integration-v2-react-php/welcome-message.sh create mode 100755 .devcontainer/post-commands.sh create mode 100644 .devcontainer/standard-integration-html-dotnet/devcontainer.json rename .devcontainer/{standard-integration => standard-integration-html-dotnet}/welcome-message.sh (100%) create mode 100644 .devcontainer/standard-integration-html-java/devcontainer.json create mode 100644 .devcontainer/standard-integration-html-java/welcome-message.sh rename .devcontainer/{advanced-integration-v2 => standard-integration-html-node}/devcontainer.json (55%) create mode 100644 .devcontainer/standard-integration-html-node/welcome-message.sh create mode 100644 .devcontainer/standard-integration-html-php/devcontainer.json create mode 100644 .devcontainer/standard-integration-html-php/welcome-message.sh create mode 100644 .devcontainer/standard-integration-react-dotnet/devcontainer.json create mode 100644 .devcontainer/standard-integration-react-dotnet/welcome-message.sh create mode 100644 .devcontainer/standard-integration-react-java/devcontainer.json create mode 100644 .devcontainer/standard-integration-react-java/welcome-message.sh rename .devcontainer/{standard-integration => standard-integration-react-node}/devcontainer.json (55%) create mode 100644 .devcontainer/standard-integration-react-node/welcome-message.sh create mode 100644 .devcontainer/standard-integration-react-php/devcontainer.json create mode 100644 .devcontainer/standard-integration-react-php/welcome-message.sh create mode 100755 .devcontainer/update_settings.sh delete mode 100644 advanced-integration/v2/server/dotnet/appsettings.json delete mode 100644 advanced-integration/v2/server/php/server/.env delete mode 100644 standard-integration/server/dotnet/appsettings.json delete mode 100644 standard-integration/server/php/server/.env diff --git a/.devcontainer/advanced-integration-v1/devcontainer.json b/.devcontainer/advanced-integration-v1/devcontainer.json index ffb6f41c..9ce61d30 100644 --- a/.devcontainer/advanced-integration-v1/devcontainer.json +++ b/.devcontainer/advanced-integration-v1/devcontainer.json @@ -1,6 +1,6 @@ // For more details, see https://aka.ms/devcontainer.json. { - "name": "PayPal Advanced Integration (v1)", + "name": "advanced-integration-v1", "image": "mcr.microsoft.com/devcontainers/javascript-node:20", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/v1", // Use 'onCreateCommand' to run commands when creating the container. diff --git a/.devcontainer/advanced-integration-v2-html-dotnet/devcontainer.json b/.devcontainer/advanced-integration-v2-html-dotnet/devcontainer.json new file mode 100644 index 00000000..2ef1ead0 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-html-dotnet/devcontainer.json @@ -0,0 +1,56 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "advanced-integration-v2/html/dotnet", + "image": "mcr.microsoft.com/devcontainers/dotnet:8.0", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/advanced-integration-v2-html-dotnet/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Advanced Checkout Flow" + }, + "3000": { + "label": "HTML", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "dotnet", + "VISIBLE_FOLDER_CLIENT": "html", + "VISIBLE_FOLDER_PROJECT": "advanced-integration", + "VISIBLE_FOLDER_VERSION": "v2" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "ms-dotnettools.csharp" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} diff --git a/.devcontainer/advanced-integration-v2/welcome-message.sh b/.devcontainer/advanced-integration-v2-html-dotnet/welcome-message.sh similarity index 100% rename from .devcontainer/advanced-integration-v2/welcome-message.sh rename to .devcontainer/advanced-integration-v2-html-dotnet/welcome-message.sh diff --git a/.devcontainer/advanced-integration-v2-html-java/devcontainer.json b/.devcontainer/advanced-integration-v2-html-java/devcontainer.json new file mode 100644 index 00000000..3dcae617 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-html-java/devcontainer.json @@ -0,0 +1,57 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "advanced-integration-v2/html/java", + "image": "mcr.microsoft.com/devcontainers/java:21", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/advanced-integration-v2-html-java/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Advanced Checkout Flow" + }, + "3000": { + "label": "HTML", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "java", + "VISIBLE_FOLDER_CLIENT": "html", + "VISIBLE_FOLDER_PROJECT": "advanced-integration", + "VISIBLE_FOLDER_VERSION": "v2" + }, + "customizations": { + "vscode": { + "extensions": ["vsls-contrib.codetour", "PayPal.vscode-paypal"], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "22", + "jdkDistro": "tem", + "installMaven": "true" + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} \ No newline at end of file diff --git a/.devcontainer/advanced-integration-v2-html-java/welcome-message.sh b/.devcontainer/advanced-integration-v2-html-java/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-html-java/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/advanced-integration-v2-html-node/devcontainer.json b/.devcontainer/advanced-integration-v2-html-node/devcontainer.json new file mode 100644 index 00000000..f5f00400 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-html-node/devcontainer.json @@ -0,0 +1,56 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "advanced-integration-v2/html/node", + "image": "mcr.microsoft.com/devcontainers/javascript-node:20", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/advanced-integration-v2-html-node/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Advanced Checkout Flow" + }, + "3000": { + "label": "HTML", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "node", + "VISIBLE_FOLDER_CLIENT": "html", + "VISIBLE_FOLDER_PROJECT": "advanced-integration", + "VISIBLE_FOLDER_VERSION": "v2" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "dbaeumer.vscode-eslint" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} diff --git a/.devcontainer/advanced-integration-v2-html-node/welcome-message.sh b/.devcontainer/advanced-integration-v2-html-node/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-html-node/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/advanced-integration-v2-html-php/devcontainer.json b/.devcontainer/advanced-integration-v2-html-php/devcontainer.json new file mode 100644 index 00000000..6afcc17b --- /dev/null +++ b/.devcontainer/advanced-integration-v2-html-php/devcontainer.json @@ -0,0 +1,56 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "advanced-integration-v2/html/php", + "image": "mcr.microsoft.com/devcontainers/php:8", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/advanced-integration-v2-html-php/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Advanced Checkout Flow" + }, + "3000": { + "label": "HTML", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "php", + "VISIBLE_FOLDER_CLIENT": "html", + "VISIBLE_FOLDER_PROJECT": "advanced-integration", + "VISIBLE_FOLDER_VERSION": "v2" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "xdebug.php-debug" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} \ No newline at end of file diff --git a/.devcontainer/advanced-integration-v2-html-php/welcome-message.sh b/.devcontainer/advanced-integration-v2-html-php/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-html-php/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/advanced-integration-v2-react-dotnet/devcontainer.json b/.devcontainer/advanced-integration-v2-react-dotnet/devcontainer.json new file mode 100644 index 00000000..a4911ab0 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-react-dotnet/devcontainer.json @@ -0,0 +1,56 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": " advanced-integration-v2/react/dotnet", + "image": "mcr.microsoft.com/devcontainers/dotnet:8.0", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Advanced Checkout Flow" + }, + "3000": { + "label": "React", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "dotnet", + "VISIBLE_FOLDER_CLIENT": "react", + "VISIBLE_FOLDER_PROJECT": "advanced-integration", + "VISIBLE_FOLDER_VERSION": "v2" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "ms-dotnettools.csharp" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} diff --git a/.devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh b/.devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-react-dotnet/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/advanced-integration-v2-react-java/devcontainer.json b/.devcontainer/advanced-integration-v2-react-java/devcontainer.json new file mode 100644 index 00000000..e55feb54 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-react-java/devcontainer.json @@ -0,0 +1,57 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "advanced-integration-v2/react/java", + "image": "mcr.microsoft.com/devcontainers/java:21", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/advanced-integration-v2-react-java/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Advanced Checkout Flow" + }, + "3000": { + "label": "React", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "java", + "VISIBLE_FOLDER_CLIENT": "react", + "VISIBLE_FOLDER_PROJECT": "advanced-integration", + "VISIBLE_FOLDER_VERSION": "v2" + }, + "customizations": { + "vscode": { + "extensions": ["vsls-contrib.codetour", "PayPal.vscode-paypal"], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "22", + "jdkDistro": "tem", + "installMaven": "true" + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} \ No newline at end of file diff --git a/.devcontainer/advanced-integration-v2-react-java/welcome-message.sh b/.devcontainer/advanced-integration-v2-react-java/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-react-java/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/advanced-integration-v2-react-node/devcontainer.json b/.devcontainer/advanced-integration-v2-react-node/devcontainer.json new file mode 100644 index 00000000..2efab718 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-react-node/devcontainer.json @@ -0,0 +1,56 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "advanced-integration-v2/react/node", + "image": "mcr.microsoft.com/devcontainers/javascript-node:20", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/advanced-integration-v2-react-node/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Advanced Checkout Flow" + }, + "3000": { + "label": "React", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "node", + "VISIBLE_FOLDER_CLIENT": "react", + "VISIBLE_FOLDER_PROJECT": "advanced-integration", + "VISIBLE_FOLDER_VERSION": "v2" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "dbaeumer.vscode-eslint" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} diff --git a/.devcontainer/advanced-integration-v2-react-node/welcome-message.sh b/.devcontainer/advanced-integration-v2-react-node/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-react-node/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/advanced-integration-v2-react-php/devcontainer.json b/.devcontainer/advanced-integration-v2-react-php/devcontainer.json new file mode 100644 index 00000000..4980fd30 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-react-php/devcontainer.json @@ -0,0 +1,56 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "advanced-integration-v2/react/php", + "image": "mcr.microsoft.com/devcontainers/php:8", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/advanced-integration-v2-react-php/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Advanced Checkout Flow" + }, + "3000": { + "label": "React", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "php", + "VISIBLE_FOLDER_CLIENT": "react", + "VISIBLE_FOLDER_PROJECT": "advanced-integration", + "VISIBLE_FOLDER_VERSION": "v2" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "xdebug.php-debug" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} \ No newline at end of file diff --git a/.devcontainer/advanced-integration-v2-react-php/welcome-message.sh b/.devcontainer/advanced-integration-v2-react-php/welcome-message.sh new file mode 100644 index 00000000..ae9a72f9 --- /dev/null +++ b/.devcontainer/advanced-integration-v2-react-php/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Advanced Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/post-commands.sh b/.devcontainer/post-commands.sh new file mode 100755 index 00000000..ffdf0fc3 --- /dev/null +++ b/.devcontainer/post-commands.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +set -e + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +WORKSPACE_DIR="$( cd "$SCRIPT_DIR/.." &> /dev/null && pwd )" + +VISIBLE_FOLDER_SERVER="${VISIBLE_FOLDER_SERVER}" +VISIBLE_FOLDER_CLIENT="${VISIBLE_FOLDER_CLIENT}" +VISIBLE_FOLDER_PROJECT="${VISIBLE_FOLDER_PROJECT}" +VISIBLE_FOLDER_VERSION="${VISIBLE_FOLDER_VERSION}" + +# Set up SERVER_DIR & CLIENT_DIR +if [ -z "$VISIBLE_FOLDER_VERSION" ]; then + SERVER_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/server" + CLIENT_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/client/${VISIBLE_FOLDER_CLIENT}" +else + SERVER_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/${VISIBLE_FOLDER_VERSION}/server" + CLIENT_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/${VISIBLE_FOLDER_VERSION}/client/${VISIBLE_FOLDER_CLIENT}/client" +fi + +# Backend setup functions +setup_backend() { + case "$VISIBLE_FOLDER_SERVER" in + node) + cd "$SERVER_DIR/node" && npm install + ;; + java) + cd "$SERVER_DIR" && cd java && mvn clean install + ;; + dotnet) + cd "$SERVER_DIR/dotnet" && dotnet restore + ;; + php) + cd "$SERVER_DIR" && cd php && composer install + ;; + *) + echo "Unknown server: $VISIBLE_FOLDER_SERVER" + exit 1 + ;; + esac +} + +# Frontend setup functions +setup_frontend() { + cd "$CLIENT_DIR" && npm install +} + +# Backend start functions +start_backend() { + case "$VISIBLE_FOLDER_SERVER" in + node) + cd "$SERVER_DIR/node" && npm start + ;; + java) + cd "$SERVER_DIR/java" && mvn spring-boot:run + ;; + dotnet) + cd "$SERVER_DIR/dotnet" && dotnet run + ;; + php) + cd "$SERVER_DIR/php" && composer start + ;; + *) + echo "Unknown server: $VISIBLE_FOLDER_SERVER" + exit 1 + ;; + esac +} + +# Frontend start functions +start_frontend() { + cd "$CLIENT_DIR" && npm run start --no-analytics +} + +# Post-create commands +post_create() { + echo "Running post-create commands..." + setup_backend + setup_frontend +} + +# Post-attach commands +post_attach() { + echo "Running post-attach commands..." + start_backend & + start_frontend +} + +# Main execution +case "$1" in + post-create) + post_create + ;; + post-attach) + post_attach + ;; + *) + echo "Usage: $0 {post-create|post-attach}" + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/.devcontainer/save-payment-method/devcontainer.json b/.devcontainer/save-payment-method/devcontainer.json index ec88eb6c..88b05faa 100644 --- a/.devcontainer/save-payment-method/devcontainer.json +++ b/.devcontainer/save-payment-method/devcontainer.json @@ -1,6 +1,6 @@ // For more details, see https://aka.ms/devcontainer.json. { - "name": "PayPal Save Payment Method", + "name": "save-payment-metthod", "image": "mcr.microsoft.com/devcontainers/javascript-node:20", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/save-payment-method", // Use 'onCreateCommand' to run commands when creating the container. diff --git a/.devcontainer/standard-integration-html-dotnet/devcontainer.json b/.devcontainer/standard-integration-html-dotnet/devcontainer.json new file mode 100644 index 00000000..810ffa39 --- /dev/null +++ b/.devcontainer/standard-integration-html-dotnet/devcontainer.json @@ -0,0 +1,55 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "standard-integration/html/dotnet", + "image": "mcr.microsoft.com/devcontainers/dotnet:8.0", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/standard-integration-html-dotnet/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Standard Checkout Flow" + }, + "3000": { + "label": "HTML", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "dotnet", + "VISIBLE_FOLDER_CLIENT": "html", + "VISIBLE_FOLDER_PROJECT": "standard-integration" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "ms-dotnettools.csharp" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} diff --git a/.devcontainer/standard-integration/welcome-message.sh b/.devcontainer/standard-integration-html-dotnet/welcome-message.sh similarity index 100% rename from .devcontainer/standard-integration/welcome-message.sh rename to .devcontainer/standard-integration-html-dotnet/welcome-message.sh diff --git a/.devcontainer/standard-integration-html-java/devcontainer.json b/.devcontainer/standard-integration-html-java/devcontainer.json new file mode 100644 index 00000000..88f7280a --- /dev/null +++ b/.devcontainer/standard-integration-html-java/devcontainer.json @@ -0,0 +1,56 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "standard-integration/html/java", + "image": "mcr.microsoft.com/devcontainers/java:21", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/standard-integration-html-java/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Standard Checkout Flow" + }, + "3000": { + "label": "Html", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "java", + "VISIBLE_FOLDER_CLIENT": "html", + "VISIBLE_FOLDER_PROJECT": "standard-integration" + }, + "customizations": { + "vscode": { + "extensions": ["vsls-contrib.codetour", "PayPal.vscode-paypal"], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "22", + "jdkDistro": "tem", + "installMaven": "true" + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} \ No newline at end of file diff --git a/.devcontainer/standard-integration-html-java/welcome-message.sh b/.devcontainer/standard-integration-html-java/welcome-message.sh new file mode 100644 index 00000000..78cce216 --- /dev/null +++ b/.devcontainer/standard-integration-html-java/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/advanced-integration-v2/devcontainer.json b/.devcontainer/standard-integration-html-node/devcontainer.json similarity index 55% rename from .devcontainer/advanced-integration-v2/devcontainer.json rename to .devcontainer/standard-integration-html-node/devcontainer.json index 6fd991e1..beaa4863 100644 --- a/.devcontainer/advanced-integration-v2/devcontainer.json +++ b/.devcontainer/standard-integration-html-node/devcontainer.json @@ -1,25 +1,22 @@ // For more details, see https://aka.ms/devcontainer.json. { - "name": "PayPal Advanced Integration (v2)", + "name": "standard-integration/html/node", "image": "mcr.microsoft.com/devcontainers/javascript-node:20", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/advanced-integration/v2", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", // Use 'onCreateCommand' to run commands when creating the container. - "onCreateCommand": "bash ../../.devcontainer/advanced-integration-v2/welcome-message.sh", + "onCreateCommand": "bash .devcontainer/standard-integration-html-node/welcome-message.sh", // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": { - "Install Server Packages": "cd server/node && npm install", - "Install Client Packages": "cd client/html && npm install" - }, + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", // Use 'postAttachCommand' to run commands when attaching to the container. - "postAttachCommand": { - "Start server": "cd server/node && npm start", - "Start client": "cd client/html && npm start" - }, + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", // Use 'forwardPorts' to make a list of ports inside the container available locally. "forwardPorts": [3000, 8080], "portsAttributes": { + "8080": { + "label": "Preview of Standard Checkout Flow" + }, "3000": { - "label": "Preview of Advanced Checkout Flow", + "label": "HTML", "onAutoForward": "openBrowserOnce" } }, @@ -33,12 +30,26 @@ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" } }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "node", + "VISIBLE_FOLDER_CLIENT": "html", + "VISIBLE_FOLDER_PROJECT": "standard-integration" + }, "customizations": { "vscode": { - "extensions": ["vsls-contrib.codetour","PayPal.vscode-paypal"], + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "dbaeumer.vscode-eslint" + ], "settings": { "git.openRepositoryInParentFolders": "always" } } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } } } diff --git a/.devcontainer/standard-integration-html-node/welcome-message.sh b/.devcontainer/standard-integration-html-node/welcome-message.sh new file mode 100644 index 00000000..78cce216 --- /dev/null +++ b/.devcontainer/standard-integration-html-node/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/standard-integration-html-php/devcontainer.json b/.devcontainer/standard-integration-html-php/devcontainer.json new file mode 100644 index 00000000..fc60c8f7 --- /dev/null +++ b/.devcontainer/standard-integration-html-php/devcontainer.json @@ -0,0 +1,55 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "standard-integration/html/php", + "image": "mcr.microsoft.com/devcontainers/php:8", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/standard-integration-html-php/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Standard Checkout Flow" + }, + "3000": { + "label": "HTML", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "php", + "VISIBLE_FOLDER_CLIENT": "html", + "VISIBLE_FOLDER_PROJECT": "standard-integration" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "xdebug.php-debug" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} \ No newline at end of file diff --git a/.devcontainer/standard-integration-html-php/welcome-message.sh b/.devcontainer/standard-integration-html-php/welcome-message.sh new file mode 100644 index 00000000..78cce216 --- /dev/null +++ b/.devcontainer/standard-integration-html-php/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/standard-integration-react-dotnet/devcontainer.json b/.devcontainer/standard-integration-react-dotnet/devcontainer.json new file mode 100644 index 00000000..d2a2e587 --- /dev/null +++ b/.devcontainer/standard-integration-react-dotnet/devcontainer.json @@ -0,0 +1,55 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "standard-integration/react/dotnet", + "image": "mcr.microsoft.com/devcontainers/dotnet:8.0", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/standard-integration-react-dotnet/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Standard Checkout Flow" + }, + "3000": { + "label": "React", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "dotnet", + "VISIBLE_FOLDER_CLIENT": "react", + "VISIBLE_FOLDER_PROJECT": "standard-integration" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "ms-dotnettools.csharp" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} diff --git a/.devcontainer/standard-integration-react-dotnet/welcome-message.sh b/.devcontainer/standard-integration-react-dotnet/welcome-message.sh new file mode 100644 index 00000000..78cce216 --- /dev/null +++ b/.devcontainer/standard-integration-react-dotnet/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/standard-integration-react-java/devcontainer.json b/.devcontainer/standard-integration-react-java/devcontainer.json new file mode 100644 index 00000000..d9f5d333 --- /dev/null +++ b/.devcontainer/standard-integration-react-java/devcontainer.json @@ -0,0 +1,56 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "standard-integration/react/java", + "image": "mcr.microsoft.com/devcontainers/java:21", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/standard-integration-react-java/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Standard Checkout Flow" + }, + "3000": { + "label": "React", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "java", + "VISIBLE_FOLDER_CLIENT": "react", + "VISIBLE_FOLDER_PROJECT": "standard-integration" + }, + "customizations": { + "vscode": { + "extensions": ["vsls-contrib.codetour", "PayPal.vscode-paypal"], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "22", + "jdkDistro": "tem", + "installMaven": "true" + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} \ No newline at end of file diff --git a/.devcontainer/standard-integration-react-java/welcome-message.sh b/.devcontainer/standard-integration-react-java/welcome-message.sh new file mode 100644 index 00000000..78cce216 --- /dev/null +++ b/.devcontainer/standard-integration-react-java/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/standard-integration/devcontainer.json b/.devcontainer/standard-integration-react-node/devcontainer.json similarity index 55% rename from .devcontainer/standard-integration/devcontainer.json rename to .devcontainer/standard-integration-react-node/devcontainer.json index 508fb74b..fa64ab68 100644 --- a/.devcontainer/standard-integration/devcontainer.json +++ b/.devcontainer/standard-integration-react-node/devcontainer.json @@ -1,25 +1,22 @@ // For more details, see https://aka.ms/devcontainer.json. { - "name": "PayPal Standard Integration", + "name": "standard-integration/react/node", "image": "mcr.microsoft.com/devcontainers/javascript-node:20", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/standard-integration", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", // Use 'onCreateCommand' to run commands when creating the container. - "onCreateCommand": "bash ../.devcontainer/standard-integration/welcome-message.sh", + "onCreateCommand": "bash .devcontainer/standard-integration-react-node/welcome-message.sh", // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": { - "Install Client Packages": "cd client/html && npm install", - "Install Server Packages": "cd server/node && npm install" - }, + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", // Use 'postAttachCommand' to run commands when attaching to the container. - "postAttachCommand": { - "Start client": "cd client/html && npm start", - "Start server": "cd server/node && npm start" - }, + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", // Use 'forwardPorts' to make a list of ports inside the container available locally. "forwardPorts": [3000, 8080], "portsAttributes": { + "8080": { + "label": "Preview of Standard Checkout Flow" + }, "3000": { - "label": "Preview of Standard Checkout Flow", + "label": "React", "onAutoForward": "openBrowserOnce" } }, @@ -33,12 +30,26 @@ "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" } }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "node", + "VISIBLE_FOLDER_CLIENT": "react", + "VISIBLE_FOLDER_PROJECT": "standard-integration" + }, "customizations": { "vscode": { - "extensions": ["vsls-contrib.codetour","PayPal.vscode-paypal"], + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "dbaeumer.vscode-eslint" + ], "settings": { "git.openRepositoryInParentFolders": "always" } } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } } } diff --git a/.devcontainer/standard-integration-react-node/welcome-message.sh b/.devcontainer/standard-integration-react-node/welcome-message.sh new file mode 100644 index 00000000..78cce216 --- /dev/null +++ b/.devcontainer/standard-integration-react-node/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/standard-integration-react-php/devcontainer.json b/.devcontainer/standard-integration-react-php/devcontainer.json new file mode 100644 index 00000000..e5bfcf12 --- /dev/null +++ b/.devcontainer/standard-integration-react-php/devcontainer.json @@ -0,0 +1,55 @@ +// For more details, see https://aka.ms/devcontainer.json. +{ + "name": "standard-integration/react/php", + "image": "mcr.microsoft.com/devcontainers/php:8", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Use 'onCreateCommand' to run commands when creating the container. + "onCreateCommand": "bash .devcontainer/standard-integration-react-php/welcome-message.sh", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "chmod +x .devcontainer/update_settings.sh && .devcontainer/update_settings.sh && chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-create", + // Use 'postAttachCommand' to run commands when attaching to the container. + "postAttachCommand": "chmod +x .devcontainer/post-commands.sh && .devcontainer/post-commands.sh post-attach", + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000, 8080], + "portsAttributes": { + "8080": { + "label": "Preview of Standard Checkout Flow" + }, + "3000": { + "label": "React", + "onAutoForward": "openBrowserOnce" + } + }, + "secrets": { + "PAYPAL_CLIENT_ID": { + "description": "Sandbox client ID of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + }, + "PAYPAL_CLIENT_SECRET": { + "description": "Sandbox secret of the application.", + "documentationUrl": "https://developer.paypal.com/dashboard/applications/sandbox" + } + }, + "containerEnv": { + "VISIBLE_FOLDER_SERVER": "php", + "VISIBLE_FOLDER_CLIENT": "react", + "VISIBLE_FOLDER_PROJECT": "standard-integration" + }, + "customizations": { + "vscode": { + "extensions": [ + "vsls-contrib.codetour", + "PayPal.vscode-paypal", + "xdebug.php-debug" + ], + "settings": { + "git.openRepositoryInParentFolders": "always" + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + } +} \ No newline at end of file diff --git a/.devcontainer/standard-integration-react-php/welcome-message.sh b/.devcontainer/standard-integration-react-php/welcome-message.sh new file mode 100644 index 00000000..78cce216 --- /dev/null +++ b/.devcontainer/standard-integration-react-php/welcome-message.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 Once you rename the \".env.example\" file to \".env\" and update \"PAYPAL_CLIENT_ID\" and \"PAYPAL_CLIENT_SECRET\", the checkout page will automatically open in the browser after the server is restarted." + +ALTERNATE_WELCOME_MESSAGE=" +👋 Welcome to the \"PayPal Standard Checkout Integration Example\" + +🛠️ Your environment is fully setup with all the required software. + +🚀 The checkout page will automatically open in the browser after the server is started." + +if [ -n "$PAYPAL_CLIENT_ID" ] && [ -n "$PAYPAL_CLIENT_SECRET" ]; then + WELCOME_MESSAGE="${ALTERNATE_WELCOME_MESSAGE}" +fi + +sudo bash -c "echo \"${WELCOME_MESSAGE}\" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt" diff --git a/.devcontainer/update_settings.sh b/.devcontainer/update_settings.sh new file mode 100755 index 00000000..736b30ff --- /dev/null +++ b/.devcontainer/update_settings.sh @@ -0,0 +1,140 @@ +#!/bin/bash + +set -e + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +WORKSPACE_DIR="$( cd "$SCRIPT_DIR/.." &> /dev/null && pwd )" + +VISIBLE_FOLDER_SERVER="$VISIBLE_FOLDER_SERVER" +VISIBLE_FOLDER_CLIENT="$VISIBLE_FOLDER_CLIENT" +VISIBLE_FOLDER_PROJECT="$VISIBLE_FOLDER_PROJECT" +VISIBLE_FOLDER_VERSION="$VISIBLE_FOLDER_VERSION" + +DEVCONTAINER_WORKSPACE="$WORKSPACE_DIR/.devcontainer" +SETTINGS_FILE="$WORKSPACE_DIR/.vscode/settings.json" +PROJECT_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT" + + +if [ -z "$VISIBLE_FOLDER_CLIENT" ]; then + echo "Error: VISIBLE_FOLDER_CLIENT is not set, setting it to default" + VISIBLE_FOLDER_CLIENT="DEFAULT" +fi + +if [ -z "$VISIBLE_FOLDER_VERSION" ]; then + SERVER_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT/server" + CLIENT_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT/client" + VERSION_WORKSPACE="$PROJECT_WORKSPACE" + VISIBLE_FOLDER_DEVCONTAINER="$VISIBLE_FOLDER_PROJECT-$VISIBLE_FOLDER_CLIENT-$VISIBLE_FOLDER_SERVER" + PROJECT_DIR="$VISIBLE_FOLDER_PROJECT" +else + SERVER_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT/$VISIBLE_FOLDER_VERSION/server" + CLIENT_WORKSPACE="$WORKSPACE_DIR/$VISIBLE_FOLDER_PROJECT/$VISIBLE_FOLDER_VERSION/client" + VERSION_WORKSPACE="$PROJECT_WORKSPACE/$VISIBLE_FOLDER_VERSION" + VISIBLE_FOLDER_DEVCONTAINER="$VISIBLE_FOLDER_PROJECT-$VISIBLE_FOLDER_VERSION-$VISIBLE_FOLDER_CLIENT-$VISIBLE_FOLDER_SERVER" + PROJECT_DIR="$VISIBLE_FOLDER_PROJECT/$VISIBLE_FOLDER_VERSION" + +fi +echo "SERVER_WORKSPACE:$SERVER_WORKSPACE" +echo "CLIENT_WORKSPACE:$CLIENT_WORKSPACE" +echo "VISIBLE_FOLDER_DEVCONTAINER:$VISIBLE_FOLDER_DEVCONTAINER" +echo "PROJECT_WORKSPACE:$PROJECT_WORKSPACE" + + +echo "Workspace directory: $WORKSPACE_DIR" +echo "Server directory: $SERVER_WORKSPACE" +echo "Visible server folder: $VISIBLE_FOLDER_SERVER" +echo "Visible client folder: $VISIBLE_FOLDER_CLIENT" +echo "Visible project folder: $VISIBLE_FOLDER_PROJECT" +echo "Visible version: $VISIBLE_FOLDER_VERSION" +echo "Visible devcontainer: $DEVCONTAINER_WORKSPACE" +if [ ! -d "$SERVER_WORKSPACE" ]; then + echo "Error: Server directory not found at $SERVER_WORKSPACE" + exit 1 +fi + +if [ ! -d "$DEVCONTAINER_WORKSPACE" ]; then + echo "Error: .devcontainer directory not found at $DEVCONTAINER_WORKSPACE" + exit 1 +fi + +if [ -z "$VISIBLE_FOLDER_SERVER" ]; then + echo "Error: VISIBLE_FOLDER_SERVER is not set" + exit 1 +fi + +mkdir -p "$(dirname "$SETTINGS_FILE")" + +echo "{ + \"files.exclude\": {" > "$SETTINGS_FILE" + +first=true + +for dir in "$WORKSPACE_DIR"/*/ ; do + dir_name=$(basename "$dir") + if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_PROJECT" ]; then + if [ "$first" = true ] ; then + first=false + else + echo "," >> "$SETTINGS_FILE" + fi + echo -n " \"**/$dir_name\": true" >> "$SETTINGS_FILE" + fi +done + +if [ -n "$VISIBLE_FOLDER_VERSION" ]; then + for dir in "$PROJECT_WORKSPACE"/*/ ; do + dir_name=$(basename "$dir") + if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_VERSION" ]; then + if [ "$first" = true ] ; then + first=false + else + echo "," >> "$SETTINGS_FILE" + fi + echo -n " \"**/$VISIBLE_FOLDER_PROJECT/$dir_name\": true" >> "$SETTINGS_FILE" + fi + done +fi + +for dir in "$DEVCONTAINER_WORKSPACE"/*/ ; do + dir_name=$(basename "$dir") + if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_DEVCONTAINER" ]; then + if [ "$first" = true ] ; then + first=false + else + echo "," >> "$SETTINGS_FILE" + fi + echo -n " \"**/.devcontainer/$dir_name\": true" >> "$SETTINGS_FILE" + fi +done + +for dir in "$SERVER_WORKSPACE"/*/ ; do + dir_name=$(basename "$dir") + if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_SERVER" ]; then + if [ "$first" = true ] ; then + first=false + else + echo "," >> "$SETTINGS_FILE" + fi + echo -n " \"**/$PROJECT_DIR/server/$dir_name\": true" >> "$SETTINGS_FILE" + fi +done + +for dir in "$CLIENT_WORKSPACE"/*/ ; do + dir_name=$(basename "$dir") + if [ -d "$dir" ] && [ "$dir_name" != "$VISIBLE_FOLDER_CLIENT" ]; then + if [ "$first" = true ] ; then + first=false + else + echo "," >> "$SETTINGS_FILE" + fi + echo -n " \"**/$PROJECT_DIR/client/$dir_name\": true" >> "$SETTINGS_FILE" + fi +done + +echo " + } +}" >> "$SETTINGS_FILE" + +echo "VS Code settings updated to show only $VISIBLE_FOLDER_SERVER and $VISIBLE_FOLDER_CLIENT folder in server directory." +echo "Contents of $SETTINGS_FILE:" +cat "$SETTINGS_FILE" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5df6b051..c889f486 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,10 @@ dist # dotnet *.sln + +# env +*.local + +#Codespace +.vscode/settings.json +.devcontainer/update_settings.sh diff --git a/README.md b/README.md index daf0636c..98fbede3 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,18 @@ These examples will ask you to run commands like `npm install` and `npm start`. You'll need a version of node >= 16 which can be downloaded from the [Node.js website](https://nodejs.org/en/download/). -## PayPal Codespaces +# Running on Codespaces +Follow below steps to use Codespaces. + +1) Click "New with options..." to open a page where you can choose the Dev container to run. +![image](https://github.com/user-attachments/assets/0d4bf202-0c94-42ec-aa2e-d8ccb6da9eb8) + +2) Choose the Dev container to run +![image](https://github.com/user-attachments/assets/b612467d-9fdc-4666-8dfa-0d99af6a2d39) + +3) Client ID and Client Secrets are required for running the application in codespace. +![image](https://github.com/user-attachments/assets/cbbc4521-aa43-403f-9243-e3c555e67f4a) -PayPal codespaces require a client ID and client secret for your app. ### Link to codespaces diff --git a/advanced-integration/v2/client/html/README.md b/advanced-integration/v2/client/html/README.md index 0ebb16ac..a98bb13f 100644 --- a/advanced-integration/v2/client/html/README.md +++ b/advanced-integration/v2/client/html/README.md @@ -20,7 +20,7 @@ This guide will walk you through setting up and running the HTML/JS Advanced Int ### Installation -```sh +```bash npm install ``` @@ -31,7 +31,7 @@ npm install - Rename the .env.example file to .env - Update the following keys with their actual values - - ```sh + ```bash PAYPAL_CLIENT_ID= ``` @@ -61,7 +61,7 @@ npm install - **Start the client**: - ```sh + ```bash npm run dev ``` diff --git a/advanced-integration/v2/client/react/README.md b/advanced-integration/v2/client/react/README.md index 6022519f..70f5f11e 100644 --- a/advanced-integration/v2/client/react/README.md +++ b/advanced-integration/v2/client/react/README.md @@ -20,7 +20,7 @@ This guide will walk you through setting up and running the React Advanced Integ ### Installation -```sh +```bash npm install ``` @@ -31,7 +31,7 @@ npm install - Rename the .env.example file to .env - Update the following keys with their actual values - - ```sh + ```bash PAYPAL_CLIENT_ID= ``` @@ -61,7 +61,7 @@ npm install - **Start the client**: - ```sh + ```bash npm run dev ``` diff --git a/advanced-integration/v2/client/react/client/App.jsx b/advanced-integration/v2/client/react/client/App.jsx index bed59906..fc670070 100644 --- a/advanced-integration/v2/client/react/client/App.jsx +++ b/advanced-integration/v2/client/react/client/App.jsx @@ -9,6 +9,7 @@ import { export default function App() { const [isPaying, setIsPaying] = useState(false); + const [message, setMessage] = useState(""); const initialOptions = { "client-id": import.meta.env.PAYPAL_CLIENT_ID, "enable-funding": "venmo", @@ -126,7 +127,7 @@ export default function App() { setMessage(await onApprove(data))} onError={onError} style={{ shape: "rect", @@ -138,7 +139,7 @@ export default function App() { setMessage(await onApprove(data))} > +
); } @@ -224,7 +226,7 @@ const SubmitPayment = ({ isPaying, setIsPaying, billingAddress }) => { } setIsPaying(true); - cardFieldsForm.submit({ billingAddress }).catch((err) => { + cardFieldsForm.submit({ billingAddress }).finally((err) => { setIsPaying(false); }); }; @@ -238,3 +240,7 @@ const SubmitPayment = ({ isPaying, setIsPaying, billingAddress }) => { ); }; + +const Message = ({ content }) => { + return

{content}

; +}; diff --git a/advanced-integration/v2/server/dotnet/README.md b/advanced-integration/v2/server/dotnet/README.md index 92ac1cc2..52ed7c55 100644 --- a/advanced-integration/v2/server/dotnet/README.md +++ b/advanced-integration/v2/server/dotnet/README.md @@ -1,18 +1,35 @@ # Advanced Integartion .NET Sample + PayPal Advanced Integration sample in .NET ## Running the sample -1. Build the server +1. **Add your API credentials to the environment:** + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +2. **Build the server** -~~~ -dotnet restore -~~~ + ```bash + dotnet restore + ``` -2. Run the server +3. **Run the server** -~~~ -dotnet run -~~~ + ```bash + dotnet run + ``` -3. Go to [http://localhost:8080/](http://localhost:8080/) \ No newline at end of file +4. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/advanced-integration/v2/server/dotnet/Server.cs b/advanced-integration/v2/server/dotnet/Server.cs index c9bab8fc..dcd334fb 100644 --- a/advanced-integration/v2/server/dotnet/Server.cs +++ b/advanced-integration/v2/server/dotnet/Server.cs @@ -23,12 +23,6 @@ public static void Main(string[] args) public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration( - (context, config) => - { - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - } - ) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseUrls("http://localhost:8080"); @@ -66,11 +60,11 @@ public class CheckoutController : Controller private IConfiguration _configuration { get; } private string _paypalClientId { - get { return _configuration["PAYPAL_CLIENT_ID"]; } + get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); } } private string _paypalClientSecret { - get { return _configuration["PAYPAL_CLIENT_SECRET"]; } + get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); } } private readonly string _base = "https://api-m.sandbox.paypal.com"; diff --git a/advanced-integration/v2/server/dotnet/appsettings.json b/advanced-integration/v2/server/dotnet/appsettings.json deleted file mode 100644 index 019194eb..00000000 --- a/advanced-integration/v2/server/dotnet/appsettings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "PAYPAL_CLIENT_ID": "PAYPAL_CLIENT_ID", - "PAYPAL_CLIENT_SECRET": "PAYPAL_CLIENT_SECRET" -} diff --git a/advanced-integration/v2/server/java/README.md b/advanced-integration/v2/server/java/README.md index 578fb9b7..8e330262 100644 --- a/advanced-integration/v2/server/java/README.md +++ b/advanced-integration/v2/server/java/README.md @@ -1,18 +1,35 @@ # Advanced Integartion Java Sample + PayPal Advanced Integration sample in Java ## Running the sample -1. Build the server +1. Add your API credentials to the environment: + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +2. Build the server -~~~ -mvn clean install -~~~ + ```bash + mvn clean install + ``` -2. Run the server +3. Run the server -~~~ -mvn spring-boot:run -~~~ + ```bash + mvn spring-boot:run + ``` -3. Go to [http://localhost:8080/](http://localhost:8080/) +4. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/advanced-integration/v2/server/java/pom.xml b/advanced-integration/v2/server/java/pom.xml index f36d390d..a8c8f8f9 100644 --- a/advanced-integration/v2/server/java/pom.xml +++ b/advanced-integration/v2/server/java/pom.xml @@ -27,7 +27,7 @@ - 22 + 21 diff --git a/advanced-integration/v2/server/java/src/main/resources/application.properties b/advanced-integration/v2/server/java/src/main/resources/application.properties index 88089970..103551b3 100644 --- a/advanced-integration/v2/server/java/src/main/resources/application.properties +++ b/advanced-integration/v2/server/java/src/main/resources/application.properties @@ -1,3 +1,3 @@ spring.application.name=v2-java -PAYPAL_CLIENT_ID= -PAYPAL_CLIENT_SECRET= +PAYPAL_CLIENT_ID=${PAYPAL_CLIENT_ID} +PAYPAL_CLIENT_SECRET=${PAYPAL_CLIENT_SECRET} diff --git a/advanced-integration/v2/server/node/README.md b/advanced-integration/v2/server/node/README.md index 8a3c0250..2a224db8 100644 --- a/advanced-integration/v2/server/node/README.md +++ b/advanced-integration/v2/server/node/README.md @@ -4,16 +4,32 @@ PayPal Advanced Integration sample in Node.js ## Running the sample -1. Install the packages +1. Add your API credentials to the environment: - ```sh - npm install - ``` + - **Windows** -2. Run the server + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` - ```sh - npm run start - ``` + - **Unix** -3. Go to [http://localhost:8080/](http://localhost:8080/) + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +2. Install the packages + + ```bash + npm install + ``` + +3. Run the server + + ```bash + npm run start + ``` + +4. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/advanced-integration/v2/server/php/README.md b/advanced-integration/v2/server/php/README.md index 2f162d42..a789b6bf 100644 --- a/advanced-integration/v2/server/php/README.md +++ b/advanced-integration/v2/server/php/README.md @@ -18,9 +18,23 @@ This sample app demonstrates how to integrate with ACDC using PayPal's REST APIs ## How to Run Locally -1. Replace your Client ID & Client Secret in the server/.env file: -2. Open the `.env` file in a text editor and replace the placeholders with the appropriate values. -3. Follow the below instructions to setup & run server. +1. Add your API credentials to the environment: + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +2. Follow the below instructions to setup & run server. ## Install the Composer diff --git a/advanced-integration/v2/server/php/server/.env b/advanced-integration/v2/server/php/server/.env deleted file mode 100644 index 96d3bc76..00000000 --- a/advanced-integration/v2/server/php/server/.env +++ /dev/null @@ -1,2 +0,0 @@ -PAYPAL_CLIENT_ID= -PAYPAL_CLIENT_SECRET= \ No newline at end of file diff --git a/advanced-integration/v2/server/php/server/index.php b/advanced-integration/v2/server/php/server/index.php index 81a25ada..e99a2841 100644 --- a/advanced-integration/v2/server/php/server/index.php +++ b/advanced-integration/v2/server/php/server/index.php @@ -3,17 +3,16 @@ use GuzzleHttp\Client; -$env = parse_ini_file('.env'); - -$PAYPAL_CLIENT_ID = $env['PAYPAL_CLIENT_ID']; -$PAYPAL_CLIENT_SECRET = $env['PAYPAL_CLIENT_SECRET']; +$PAYPAL_CLIENT_ID = getenv('PAYPAL_CLIENT_ID'); +$PAYPAL_CLIENT_SECRET = getenv('PAYPAL_CLIENT_SECRET'); $base = "https://api-m.sandbox.paypal.com"; /** * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs. * @see https://developer.paypal.com/api/rest/authentication/ */ -function generateAccessToken() { +function generateAccessToken() +{ global $PAYPAL_CLIENT_ID, $PAYPAL_CLIENT_SECRET, $base; if (!$PAYPAL_CLIENT_ID || !$PAYPAL_CLIENT_SECRET) { @@ -21,7 +20,7 @@ function generateAccessToken() { } $auth = base64_encode($PAYPAL_CLIENT_ID . ":" . $PAYPAL_CLIENT_SECRET); - + // Disabling certificate validation for local development $client = new Client(['verify' => false]); $response = $client->post("$base/v1/oauth2/token", [ @@ -41,11 +40,12 @@ function generateAccessToken() { * Create an order to start the transaction. * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create */ -function createOrder($cart) { +function createOrder($cart) +{ global $base; $accessToken = generateAccessToken(); - + // Disabling certificate validation for local development $client = new Client(['verify' => false]); $payload = [ @@ -75,7 +75,8 @@ function createOrder($cart) { * Capture payment for the created order to complete the transaction. * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture */ -function captureOrder($orderID) { +function captureOrder($orderID) +{ global $base; $accessToken = generateAccessToken(); @@ -92,7 +93,8 @@ function captureOrder($orderID) { return handleResponse($response); } -function handleResponse($response) { +function handleResponse($response) +{ $jsonResponse = json_decode($response->getBody(), true); return [ 'jsonResponse' => $jsonResponse, @@ -101,7 +103,7 @@ function handleResponse($response) { } $endpoint = $_SERVER['REQUEST_URI']; -if($endpoint === '/') { +if ($endpoint === '/') { try { $response = [ "message" => "Server is running" @@ -114,7 +116,7 @@ function handleResponse($response) { } } -if($endpoint === '/api/orders') { +if ($endpoint === '/api/orders') { $data = json_decode(file_get_contents('php://input'), true); $cart = $data['cart']; header('Content-Type: application/json'); @@ -128,7 +130,7 @@ function handleResponse($response) { } -if(str_ends_with($endpoint, '/capture')) { +if (str_ends_with($endpoint, '/capture')) { $urlSegments = explode('/', $endpoint); end($urlSegments); // Will set the pointer to the end of array $orderID = prev($urlSegments); @@ -140,5 +142,4 @@ function handleResponse($response) { echo json_encode(['error' => $e->getMessage()]); http_response_code(500); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/standard-integration/client/html/README.md b/standard-integration/client/html/README.md index 5c79b001..302fcb42 100644 --- a/standard-integration/client/html/README.md +++ b/standard-integration/client/html/README.md @@ -20,7 +20,7 @@ This guide will walk you through setting up and running the HTML/JS Standard Int ### Installation -```sh +```bash npm install ``` @@ -31,7 +31,7 @@ npm install - Rename the .env.example file to .env - Update the following keys with their actual values - - ```sh + ```bash PAYPAL_CLIENT_ID= ``` @@ -61,7 +61,7 @@ npm install - **Start the client**: - ```sh + ```bash npm run dev ``` diff --git a/standard-integration/client/html/client/app.js b/standard-integration/client/html/client/app.js index 4c70688e..685b2c46 100644 --- a/standard-integration/client/html/client/app.js +++ b/standard-integration/client/html/client/app.js @@ -42,7 +42,7 @@ window.paypal throw new Error(errorMessage); } catch (error) { console.error(error); - // resultMessage(`Could not initiate PayPal Checkout...

${error}`); + resultMessage(`Could not initiate PayPal Checkout...

${error}`); } }, @@ -98,3 +98,9 @@ window.paypal }, }) .render("#paypal-button-container"); + +// Example function to show a result to the user. Your site's UI library can be used instead. +function resultMessage(message) { + const container = document.querySelector("#result-message"); + container.innerHTML = message; +} diff --git a/standard-integration/client/react/README.md b/standard-integration/client/react/README.md index fdf7d214..da8ec278 100644 --- a/standard-integration/client/react/README.md +++ b/standard-integration/client/react/README.md @@ -20,7 +20,7 @@ This guide will walk you through setting up and running the React Standard Integ ### Installation -```sh +```bash npm install ``` @@ -31,7 +31,7 @@ npm install - Rename the .env.example file to .env - Update the following keys with their actual values - - ```sh + ```bash PAYPAL_CLIENT_ID= ``` @@ -61,7 +61,7 @@ npm install - **Start the client**: - ```sh + ```bash npm run dev ``` diff --git a/standard-integration/server/dotnet/README.md b/standard-integration/server/dotnet/README.md index 9dca45c3..d1f5fd91 100644 --- a/standard-integration/server/dotnet/README.md +++ b/standard-integration/server/dotnet/README.md @@ -1,18 +1,35 @@ # Standard Integartion .NET Sample + PayPal Standard Integration sample in .NET ## Running the sample -1. Build the server +1. **Add your API credentials to the environment:** + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +2. **Build the server** -~~~ -dotnet restore -~~~ + ```bash + dotnet restore + ``` -2. Run the server +3. **Run the server** -~~~ -dotnet run -~~~ + ```bash + dotnet run + ``` -3. Go to [http://localhost:8080/](http://localhost:8080/) \ No newline at end of file +4. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/standard-integration/server/dotnet/Server.cs b/standard-integration/server/dotnet/Server.cs index eb24f0e8..9be4f5e5 100644 --- a/standard-integration/server/dotnet/Server.cs +++ b/standard-integration/server/dotnet/Server.cs @@ -23,12 +23,6 @@ public static void Main(string[] args) public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration( - (context, config) => - { - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - } - ) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseUrls("http://localhost:8080"); @@ -66,11 +60,11 @@ public class CheckoutController : Controller private IConfiguration _configuration { get; } private string _paypalClientId { - get { return _configuration["PAYPAL_CLIENT_ID"]; } + get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); } } private string _paypalClientSecret { - get { return _configuration["PAYPAL_CLIENT_SECRET"]; } + get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); } } private readonly string _base = "https://api-m.sandbox.paypal.com"; diff --git a/standard-integration/server/dotnet/appsettings.json b/standard-integration/server/dotnet/appsettings.json deleted file mode 100644 index 019194eb..00000000 --- a/standard-integration/server/dotnet/appsettings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "PAYPAL_CLIENT_ID": "PAYPAL_CLIENT_ID", - "PAYPAL_CLIENT_SECRET": "PAYPAL_CLIENT_SECRET" -} diff --git a/standard-integration/server/java/README.md b/standard-integration/server/java/README.md index 343200e7..a9fcce21 100644 --- a/standard-integration/server/java/README.md +++ b/standard-integration/server/java/README.md @@ -1,18 +1,35 @@ # Standard Integartion Java Sample + PayPal Standard Integration sample in Java ## Running the sample -1. Build the server +1. Add your API credentials to the environment: + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +2. Build the server -~~~ -mvn clean install -~~~ + ```bash + mvn clean install + ``` -2. Run the server +3. Run the server -~~~ -mvn spring-boot:run -~~~ + ```bash + mvn spring-boot:run + ``` -3. Go to [http://localhost:8080/](http://localhost:8080/) +4. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/standard-integration/server/java/pom.xml b/standard-integration/server/java/pom.xml index 48e7a01c..ab4c30bc 100644 --- a/standard-integration/server/java/pom.xml +++ b/standard-integration/server/java/pom.xml @@ -27,7 +27,7 @@ - 22 + 21 diff --git a/standard-integration/server/java/src/main/resources/application.properties b/standard-integration/server/java/src/main/resources/application.properties index 88089970..103551b3 100644 --- a/standard-integration/server/java/src/main/resources/application.properties +++ b/standard-integration/server/java/src/main/resources/application.properties @@ -1,3 +1,3 @@ spring.application.name=v2-java -PAYPAL_CLIENT_ID= -PAYPAL_CLIENT_SECRET= +PAYPAL_CLIENT_ID=${PAYPAL_CLIENT_ID} +PAYPAL_CLIENT_SECRET=${PAYPAL_CLIENT_SECRET} diff --git a/standard-integration/server/node/README.md b/standard-integration/server/node/README.md index a9ddb604..0fce05d5 100644 --- a/standard-integration/server/node/README.md +++ b/standard-integration/server/node/README.md @@ -4,16 +4,32 @@ PayPal Standard Integration sample in Node.js ## Running the sample -1. Install the packages +1. Add your API credentials to the environment: - ```sh - npm install - ``` + - **Windows** -2. Run the server + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` - ```sh - npm run start - ``` + - **Unix** -3. Go to [http://localhost:8080/](http://localhost:8080/) + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +2. Install the packages + + ```bash + npm install + ``` + +3. Run the server + + ```bash + npm run start + ``` + +4. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/standard-integration/server/php/README.md b/standard-integration/server/php/README.md index 5c5b5ed6..53284b42 100644 --- a/standard-integration/server/php/README.md +++ b/standard-integration/server/php/README.md @@ -18,9 +18,23 @@ This sample app demonstrates how to integrate with ACDC using PayPal's REST APIs ## How to Run Locally -1. Replace your Client ID & Client Secret in the server/.env file: -2. Open the `.env` file in a text editor and replace the placeholders with the appropriate values. -3. Follow the below instructions to setup & run server. +1. Add your API credentials to the environment: + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +2. Follow the below instructions to setup & run server. ## Install the Composer diff --git a/standard-integration/server/php/server/.env b/standard-integration/server/php/server/.env deleted file mode 100644 index 96d3bc76..00000000 --- a/standard-integration/server/php/server/.env +++ /dev/null @@ -1,2 +0,0 @@ -PAYPAL_CLIENT_ID= -PAYPAL_CLIENT_SECRET= \ No newline at end of file diff --git a/standard-integration/server/php/server/index.php b/standard-integration/server/php/server/index.php index 81a25ada..e99a2841 100644 --- a/standard-integration/server/php/server/index.php +++ b/standard-integration/server/php/server/index.php @@ -3,17 +3,16 @@ use GuzzleHttp\Client; -$env = parse_ini_file('.env'); - -$PAYPAL_CLIENT_ID = $env['PAYPAL_CLIENT_ID']; -$PAYPAL_CLIENT_SECRET = $env['PAYPAL_CLIENT_SECRET']; +$PAYPAL_CLIENT_ID = getenv('PAYPAL_CLIENT_ID'); +$PAYPAL_CLIENT_SECRET = getenv('PAYPAL_CLIENT_SECRET'); $base = "https://api-m.sandbox.paypal.com"; /** * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs. * @see https://developer.paypal.com/api/rest/authentication/ */ -function generateAccessToken() { +function generateAccessToken() +{ global $PAYPAL_CLIENT_ID, $PAYPAL_CLIENT_SECRET, $base; if (!$PAYPAL_CLIENT_ID || !$PAYPAL_CLIENT_SECRET) { @@ -21,7 +20,7 @@ function generateAccessToken() { } $auth = base64_encode($PAYPAL_CLIENT_ID . ":" . $PAYPAL_CLIENT_SECRET); - + // Disabling certificate validation for local development $client = new Client(['verify' => false]); $response = $client->post("$base/v1/oauth2/token", [ @@ -41,11 +40,12 @@ function generateAccessToken() { * Create an order to start the transaction. * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create */ -function createOrder($cart) { +function createOrder($cart) +{ global $base; $accessToken = generateAccessToken(); - + // Disabling certificate validation for local development $client = new Client(['verify' => false]); $payload = [ @@ -75,7 +75,8 @@ function createOrder($cart) { * Capture payment for the created order to complete the transaction. * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture */ -function captureOrder($orderID) { +function captureOrder($orderID) +{ global $base; $accessToken = generateAccessToken(); @@ -92,7 +93,8 @@ function captureOrder($orderID) { return handleResponse($response); } -function handleResponse($response) { +function handleResponse($response) +{ $jsonResponse = json_decode($response->getBody(), true); return [ 'jsonResponse' => $jsonResponse, @@ -101,7 +103,7 @@ function handleResponse($response) { } $endpoint = $_SERVER['REQUEST_URI']; -if($endpoint === '/') { +if ($endpoint === '/') { try { $response = [ "message" => "Server is running" @@ -114,7 +116,7 @@ function handleResponse($response) { } } -if($endpoint === '/api/orders') { +if ($endpoint === '/api/orders') { $data = json_decode(file_get_contents('php://input'), true); $cart = $data['cart']; header('Content-Type: application/json'); @@ -128,7 +130,7 @@ function handleResponse($response) { } -if(str_ends_with($endpoint, '/capture')) { +if (str_ends_with($endpoint, '/capture')) { $urlSegments = explode('/', $endpoint); end($urlSegments); // Will set the pointer to the end of array $orderID = prev($urlSegments); @@ -140,5 +142,4 @@ function handleResponse($response) { echo json_encode(['error' => $e->getMessage()]); http_response_code(500); } -} -?> \ No newline at end of file +} \ No newline at end of file From 4f9852f2b81a2ba9195531a702f4e6189072c854 Mon Sep 17 00:00:00 2001 From: sourav sarkar Date: Thu, 10 Oct 2024 21:15:21 +0530 Subject: [PATCH 31/34] feat: add support for php and java server sdk (#158) --- advanced-integration/v2/client/html/README.md | 4 +- .../v2/client/html/{client => src}/app.js | 0 .../v2/client/html/{client => src}/index.html | 0 .../v2/client/html/vite.config.js | 2 +- .../v2/client/react/.env.example | 3 + .../v2/client/react/README.md | 4 +- .../v2/client/react/{client => src}/App.jsx | 0 .../client/react/{client => src}/index.html | 0 .../v2/client/react/{client => src}/main.jsx | 0 .../v2/client/react/vite.config.js | 2 +- .../v2/server/dotnet/README.md | 6 +- .../v2/server/java/.tool-versions | 1 + advanced-integration/v2/server/java/README.md | 6 +- advanced-integration/v2/server/java/pom.xml | 16 +- .../paypal/sample/SampleAppApplication.java | 133 +- advanced-integration/v2/server/node/README.md | 6 +- .../v2/server/node/package.json | 9 +- advanced-integration/v2/server/node/server.js | 127 + .../v2/server/node/server/server.js | 154 - advanced-integration/v2/server/php/README.md | 4 +- .../v2/server/php/composer.json | 18 +- .../v2/server/php/composer.lock | 4428 +---------------- .../v2/server/php/server/index.php | 145 - .../v2/server/php/{server => src}/.htaccess | 0 .../v2/server/php/src/index.php | 117 + standard-integration/client/html/README.md | 6 +- .../client/html/{client => src}/app.js | 0 .../client/html/{client => src}/index.html | 0 .../client/html/vite.config.js | 2 +- standard-integration/client/react/README.md | 6 +- .../client/react/{client => src}/App.jsx | 0 .../client/react/{client => src}/index.html | 0 .../client/react/{client => src}/main.jsx | 0 .../client/react/vite.config.js | 2 +- ...sproj => PayPalStandardIntegration.csproj} | 0 standard-integration/server/dotnet/README.md | 6 +- standard-integration/server/java/README.md | 6 +- standard-integration/server/java/pom.xml | 11 + .../paypal/sample/SampleAppApplication.java | 133 +- standard-integration/server/node/README.md | 6 +- standard-integration/server/node/package.json | 9 +- standard-integration/server/node/server.js | 127 + .../server/node/server/server.js | 154 - standard-integration/server/php/README.md | 4 +- standard-integration/server/php/composer.json | 16 +- standard-integration/server/php/composer.lock | 4428 +---------------- .../server/php/server/index.php | 145 - .../server/php/{server => src}/.htaccess | 0 standard-integration/server/php/src/index.php | 118 + 49 files changed, 1034 insertions(+), 9330 deletions(-) rename advanced-integration/v2/client/html/{client => src}/app.js (100%) rename advanced-integration/v2/client/html/{client => src}/index.html (100%) rename advanced-integration/v2/client/react/{client => src}/App.jsx (100%) rename advanced-integration/v2/client/react/{client => src}/index.html (100%) rename advanced-integration/v2/client/react/{client => src}/main.jsx (100%) create mode 100644 advanced-integration/v2/server/java/.tool-versions create mode 100644 advanced-integration/v2/server/node/server.js delete mode 100644 advanced-integration/v2/server/node/server/server.js delete mode 100644 advanced-integration/v2/server/php/server/index.php rename advanced-integration/v2/server/php/{server => src}/.htaccess (100%) create mode 100644 advanced-integration/v2/server/php/src/index.php rename standard-integration/client/html/{client => src}/app.js (100%) rename standard-integration/client/html/{client => src}/index.html (100%) rename standard-integration/client/react/{client => src}/App.jsx (100%) rename standard-integration/client/react/{client => src}/index.html (100%) rename standard-integration/client/react/{client => src}/main.jsx (100%) rename standard-integration/server/dotnet/{PayPalAdvancedIntegration.csproj => PayPalStandardIntegration.csproj} (100%) create mode 100644 standard-integration/server/node/server.js delete mode 100644 standard-integration/server/node/server/server.js delete mode 100644 standard-integration/server/php/server/index.php rename standard-integration/server/php/{server => src}/.htaccess (100%) create mode 100644 standard-integration/server/php/src/index.php diff --git a/advanced-integration/v2/client/html/README.md b/advanced-integration/v2/client/html/README.md index a98bb13f..08187da8 100644 --- a/advanced-integration/v2/client/html/README.md +++ b/advanced-integration/v2/client/html/README.md @@ -57,12 +57,12 @@ npm install 3. Starting the development server - - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory. + - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory. - **Start the client**: ```bash - npm run dev + npm run start ``` This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). diff --git a/advanced-integration/v2/client/html/client/app.js b/advanced-integration/v2/client/html/src/app.js similarity index 100% rename from advanced-integration/v2/client/html/client/app.js rename to advanced-integration/v2/client/html/src/app.js diff --git a/advanced-integration/v2/client/html/client/index.html b/advanced-integration/v2/client/html/src/index.html similarity index 100% rename from advanced-integration/v2/client/html/client/index.html rename to advanced-integration/v2/client/html/src/index.html diff --git a/advanced-integration/v2/client/html/vite.config.js b/advanced-integration/v2/client/html/vite.config.js index 76921cbb..0a14da0e 100644 --- a/advanced-integration/v2/client/html/vite.config.js +++ b/advanced-integration/v2/client/html/vite.config.js @@ -5,7 +5,7 @@ export default defineConfig({ plugins: [], envDir: "../", envPrefix: "PAYPAL", - root: "client", + root: "src", server: { port: 3000, proxy: { diff --git a/advanced-integration/v2/client/react/.env.example b/advanced-integration/v2/client/react/.env.example index abea0386..9ce40285 100644 --- a/advanced-integration/v2/client/react/.env.example +++ b/advanced-integration/v2/client/react/.env.example @@ -1 +1,4 @@ +# Create an application to obtain credentials at +# https://developer.paypal.com/dashboard/applications/sandbox + PAYPAL_CLIENT_ID=PAYPAL_CLIENT_ID \ No newline at end of file diff --git a/advanced-integration/v2/client/react/README.md b/advanced-integration/v2/client/react/README.md index 70f5f11e..107c6b55 100644 --- a/advanced-integration/v2/client/react/README.md +++ b/advanced-integration/v2/client/react/README.md @@ -57,12 +57,12 @@ npm install 3. Starting the development server - - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory. + - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory. - **Start the client**: ```bash - npm run dev + npm run start ``` This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). diff --git a/advanced-integration/v2/client/react/client/App.jsx b/advanced-integration/v2/client/react/src/App.jsx similarity index 100% rename from advanced-integration/v2/client/react/client/App.jsx rename to advanced-integration/v2/client/react/src/App.jsx diff --git a/advanced-integration/v2/client/react/client/index.html b/advanced-integration/v2/client/react/src/index.html similarity index 100% rename from advanced-integration/v2/client/react/client/index.html rename to advanced-integration/v2/client/react/src/index.html diff --git a/advanced-integration/v2/client/react/client/main.jsx b/advanced-integration/v2/client/react/src/main.jsx similarity index 100% rename from advanced-integration/v2/client/react/client/main.jsx rename to advanced-integration/v2/client/react/src/main.jsx diff --git a/advanced-integration/v2/client/react/vite.config.js b/advanced-integration/v2/client/react/vite.config.js index 8049384e..274f8cf5 100644 --- a/advanced-integration/v2/client/react/vite.config.js +++ b/advanced-integration/v2/client/react/vite.config.js @@ -4,7 +4,7 @@ import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], - root: "client", + root: "src", envDir: "../", envPrefix: "PAYPAL", server: { diff --git a/advanced-integration/v2/server/dotnet/README.md b/advanced-integration/v2/server/dotnet/README.md index 52ed7c55..6170999e 100644 --- a/advanced-integration/v2/server/dotnet/README.md +++ b/advanced-integration/v2/server/dotnet/README.md @@ -1,4 +1,4 @@ -# Advanced Integartion .NET Sample +# Advanced Integration .NET Sample PayPal Advanced Integration sample in .NET @@ -6,14 +6,14 @@ PayPal Advanced Integration sample in .NET 1. **Add your API credentials to the environment:** - - **Windows** + - **Windows (powershell)** ```powershell $env:PAYPAL_CLIENT_ID = "" $env:PAYPAL_CLIENT_SECRET = "" ``` - - **Unix** + - **Linux / MacOS** ```bash export PAYPAL_CLIENT_ID="" diff --git a/advanced-integration/v2/server/java/.tool-versions b/advanced-integration/v2/server/java/.tool-versions new file mode 100644 index 00000000..edcd84e6 --- /dev/null +++ b/advanced-integration/v2/server/java/.tool-versions @@ -0,0 +1 @@ +java zulu-21.36.19 diff --git a/advanced-integration/v2/server/java/README.md b/advanced-integration/v2/server/java/README.md index 8e330262..d88ad4a2 100644 --- a/advanced-integration/v2/server/java/README.md +++ b/advanced-integration/v2/server/java/README.md @@ -1,4 +1,4 @@ -# Advanced Integartion Java Sample +# Advanced Integration Java Sample PayPal Advanced Integration sample in Java @@ -6,14 +6,14 @@ PayPal Advanced Integration sample in Java 1. Add your API credentials to the environment: - - **Windows** + - **Windows (powershell)** ```powershell $env:PAYPAL_CLIENT_ID = "" $env:PAYPAL_CLIENT_SECRET = "" ``` - - **Unix** + - **Linux / MacOS** ```bash export PAYPAL_CLIENT_ID="" diff --git a/advanced-integration/v2/server/java/pom.xml b/advanced-integration/v2/server/java/pom.xml index a8c8f8f9..11002ca9 100644 --- a/advanced-integration/v2/server/java/pom.xml +++ b/advanced-integration/v2/server/java/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.3.2 + 3.3.3 com.paypal.sample @@ -33,10 +33,23 @@ org.springframework.boot spring-boot-starter-thymeleaf + 3.3.3 org.springframework.boot spring-boot-starter-web + 3.3.3 + + + + com.paypal.sdk + + + paypal-server-sdk + + + 0.5.1 + @@ -45,6 +58,7 @@ org.springframework.boot spring-boot-maven-plugin + 3.3.3 diff --git a/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java b/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java index b4f3b4ae..f34fef3a 100644 --- a/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java +++ b/advanced-integration/v2/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java @@ -1,30 +1,37 @@ package com.paypal.sample; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.client.RestTemplate; +import com.paypal.sdk.Environment; +import com.paypal.sdk.PaypalServerSDKClient; +import com.paypal.sdk.authentication.ClientCredentialsAuthModel; +import com.paypal.sdk.controllers.OrdersController; +import com.paypal.sdk.exceptions.ApiException; +import com.paypal.sdk.http.response.ApiResponse; +import com.paypal.sdk.models.AmountWithBreakdown; +import com.paypal.sdk.models.CheckoutPaymentIntent; +import com.paypal.sdk.models.Order; +import com.paypal.sdk.models.OrderRequest; +import com.paypal.sdk.models.OrdersCaptureInput; +import com.paypal.sdk.models.OrdersCreateInput; +import com.paypal.sdk.models.PurchaseUnitRequest; +import java.util.Arrays; +import org.slf4j.event.Level; + import java.io.IOException; -import java.util.Base64; import java.util.Map; @SpringBootApplication @@ -36,8 +43,6 @@ public class SampleAppApplication { @Value("${PAYPAL_CLIENT_SECRET}") private String PAYPAL_CLIENT_SECRET; - private final String BASE_URL = "https://api-m.sandbox.paypal.com"; - public static void main(String[] args) { SpringApplication.run(SampleAppApplication.class, args); } @@ -47,23 +52,41 @@ public RestTemplate restTemplate() { return new RestTemplate(); } + @Bean + public PaypalServerSDKClient paypalClient() { + return new PaypalServerSDKClient.Builder() + .loggingConfig(builder -> builder + .level(Level.DEBUG) + .requestConfig(logConfigBuilder -> logConfigBuilder.body(true)) + .responseConfig(logConfigBuilder -> logConfigBuilder.headers(true))) + .httpClientConfig(configBuilder -> configBuilder + .timeout(0)) + .environment(Environment.SANDBOX) + .clientCredentialsAuth(new ClientCredentialsAuthModel.Builder( + PAYPAL_CLIENT_ID, + PAYPAL_CLIENT_SECRET) + .build()) + .build(); + } + + @Controller @RequestMapping("/") public class CheckoutController { - private final RestTemplate restTemplate; private final ObjectMapper objectMapper; + private final PaypalServerSDKClient client; - public CheckoutController(RestTemplate restTemplate, ObjectMapper objectMapper) { - this.restTemplate = restTemplate; + public CheckoutController(ObjectMapper objectMapper, PaypalServerSDKClient client) { this.objectMapper = objectMapper; + this.client = client; } @PostMapping("/api/orders") - public ResponseEntity createOrder(@RequestBody Map request) { + public ResponseEntity createOrder(@RequestBody Map request) { try { String cart = objectMapper.writeValueAsString(request.get("cart")); - JsonNode response = createOrder(cart); + Order response = createOrder(cart); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { e.printStackTrace(); @@ -72,69 +95,47 @@ public ResponseEntity createOrder(@RequestBody Map req } @PostMapping("/api/orders/{orderID}/capture") - public ResponseEntity captureOrder(@PathVariable String orderID) { + public ResponseEntity captureOrder(@PathVariable String orderID) { try { - JsonNode response = captureOrders(orderID); - return new ResponseEntity<>(response, HttpStatus.OK); + Order response = captureOrders(orderID); + return new ResponseEntity(response, HttpStatus.OK); } catch (Exception e) { e.printStackTrace(); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } - private String generateAccessToken() throws IOException { - if (PAYPAL_CLIENT_ID == null || PAYPAL_CLIENT_SECRET == null) { - throw new IllegalArgumentException("MISSING_API_CREDENTIALS"); - } - String auth = Base64.getEncoder().encodeToString((PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET).getBytes()); - HttpHeaders headers = new HttpHeaders(); - headers.setBasicAuth(auth); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - - MultiValueMap body = new LinkedMultiValueMap<>(); - body.add("grant_type", "client_credentials"); - - ResponseEntity response = restTemplate.postForEntity(BASE_URL + "/v1/oauth2/token", new HttpEntity<>(body, headers), JsonNode.class); - return response.getBody().get("access_token").asText(); - } - - private JsonNode createOrder(String cart) throws IOException { - String accessToken = generateAccessToken(); - String url = BASE_URL + "/v2/checkout/orders"; + private Order createOrder(String cart) throws IOException, ApiException { - ObjectNode payload = objectMapper.createObjectNode(); - payload.put("intent", "CAPTURE"); - ObjectNode purchaseUnit = payload.putArray("purchase_units").addObject(); - ObjectNode amount = purchaseUnit.putObject("amount"); - amount.put("currency_code", "USD"); - amount.put("value", "100.00"); + OrdersCreateInput ordersCreateInput = new OrdersCreateInput.Builder( + null, + new OrderRequest.Builder( + CheckoutPaymentIntent.CAPTURE, + Arrays.asList( + new PurchaseUnitRequest.Builder( + new AmountWithBreakdown.Builder( + "USD", + "100.00") + .build()) + .build())) + .build()) + .build(); - HttpHeaders headers = new HttpHeaders(); - headers.setBearerAuth(accessToken); - headers.setContentType(MediaType.APPLICATION_JSON); + OrdersController ordersController = client.getOrdersController(); - ResponseEntity response = restTemplate.postForEntity(url, new HttpEntity<>(payload, headers), JsonNode.class); - return handleResponse(response); - } - - private JsonNode captureOrders(String orderID) throws IOException { - String accessToken = generateAccessToken(); - String url = BASE_URL + "/v2/checkout/orders/" + orderID + "/capture"; + ApiResponse apiResponse = ordersController.ordersCreate(ordersCreateInput); - HttpHeaders headers = new HttpHeaders(); - headers.setBearerAuth(accessToken); - headers.setContentType(MediaType.APPLICATION_JSON); - - ResponseEntity response = restTemplate.postForEntity(url, new HttpEntity<>(headers), JsonNode.class); - return handleResponse(response); + return apiResponse.getResult(); } - private JsonNode handleResponse(ResponseEntity response) throws IOException { - if (response.getStatusCode().is2xxSuccessful()) { - return response.getBody(); - } else { - throw new IOException(response.getBody().toString()); - } + private Order captureOrders(String orderID) throws IOException, ApiException { + OrdersCaptureInput ordersCaptureInput = new OrdersCaptureInput.Builder( + orderID, + null) + .build(); + OrdersController ordersController = client.getOrdersController(); + ApiResponse apiResponse = ordersController.ordersCapture(ordersCaptureInput); + return apiResponse.getResult(); } } } diff --git a/advanced-integration/v2/server/node/README.md b/advanced-integration/v2/server/node/README.md index 2a224db8..e2c1f93e 100644 --- a/advanced-integration/v2/server/node/README.md +++ b/advanced-integration/v2/server/node/README.md @@ -1,4 +1,4 @@ -# Advanced Integartion Node.js Sample +# Advanced Integration Node.js Sample PayPal Advanced Integration sample in Node.js @@ -6,14 +6,14 @@ PayPal Advanced Integration sample in Node.js 1. Add your API credentials to the environment: - - **Windows** + - **Windows (powershell)** ```powershell $env:PAYPAL_CLIENT_ID = "" $env:PAYPAL_CLIENT_SECRET = "" ``` - - **Unix** + - **Linux / MacOS** ```bash export PAYPAL_CLIENT_ID="" diff --git a/advanced-integration/v2/server/node/package.json b/advanced-integration/v2/server/node/package.json index f24544de..44735762 100644 --- a/advanced-integration/v2/server/node/package.json +++ b/advanced-integration/v2/server/node/package.json @@ -4,14 +4,15 @@ "private": true, "type": "module", "dependencies": { + "@paypal/paypal-server-sdk": "^0.5.1", + "body-parser": "^1.20.3", "dotenv": "^16.3.1", - "express": "^4.18.2", - "node-fetch": "^3.3.2" + "express": "^4.18.2" }, "scripts": { - "server-dev": "nodemon server/server.js", + "server-dev": "nodemon server.js", "start": "npm run server-dev", - "prod": "node server/server.js", + "prod": "node server.js", "format": "npx prettier --write **/*.{js,jsx,md}", "format:check": "npx prettier --check **/*.{js,jsx,md}" }, diff --git a/advanced-integration/v2/server/node/server.js b/advanced-integration/v2/server/node/server.js new file mode 100644 index 00000000..08aadad1 --- /dev/null +++ b/advanced-integration/v2/server/node/server.js @@ -0,0 +1,127 @@ +import express from "express"; +import "dotenv/config"; +import { + ApiError, + CheckoutPaymentIntent, + Client, + Environment, + LogLevel, + OrdersController, +} from "@paypal/paypal-server-sdk"; +import bodyParser from "body-parser"; + +const app = express(); +app.use(bodyParser.json()); + +const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8080 } = process.env; + +const client = new Client({ + clientCredentialsAuthCredentials: { + oAuthClientId: PAYPAL_CLIENT_ID, + oAuthClientSecret: PAYPAL_CLIENT_SECRET, + }, + timeout: 0, + environment: Environment.Sandbox, + logging: { + logLevel: LogLevel.Info, + logRequest: { + logBody: true, + }, + logResponse: { + logHeaders: true, + }, + }, +}); + +const ordersController = new OrdersController(client); + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +const createOrder = async (cart) => { + const collect = { + body: { + intent: CheckoutPaymentIntent.CAPTURE, + purchaseUnits: [ + { + amount: { + currencyCode: "USD", + value: "100.00", + }, + }, + ], + }, + prefer: "return=minimal", + }; + + try { + const { body, ...httpResponse } = + await ordersController.ordersCreate(collect); + // Get more response info... + // const { statusCode, headers } = httpResponse; + return { + jsonResponse: JSON.parse(body), + httpStatusCode: httpResponse.statusCode, + }; + } catch (error) { + if (error instanceof ApiError) { + // const { statusCode, headers } = error; + throw new Error(error.message); + } + } +}; + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +const captureOrder = async (orderID) => { + const collect = { + id: orderID, + prefer: "return=minimal", + }; + + try { + const { body, ...httpResponse } = + await ordersController.ordersCapture(collect); + // Get more response info... + // const { statusCode, headers } = httpResponse; + return { + jsonResponse: JSON.parse(body), + httpStatusCode: httpResponse.statusCode, + }; + } catch (error) { + if (error instanceof ApiError) { + // const { statusCode, headers } = error; + throw new Error(error.message); + } + } +}; + +app.post("/api/orders", async (req, res) => { + try { + // use the cart information passed from the front-end to calculate the order amount detals + const { cart } = req.body; + const { jsonResponse, httpStatusCode } = await createOrder(cart); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to create order." }); + } +}); + +app.post("/api/orders/:orderID/capture", async (req, res) => { + try { + const { orderID } = req.params; + const { jsonResponse, httpStatusCode } = await captureOrder(orderID); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to capture order." }); + } +}); + +app.listen(PORT, () => { + console.log(`Node server listening at http://localhost:${PORT}/`); +}); diff --git a/advanced-integration/v2/server/node/server/server.js b/advanced-integration/v2/server/node/server/server.js deleted file mode 100644 index 1e2f9d4a..00000000 --- a/advanced-integration/v2/server/node/server/server.js +++ /dev/null @@ -1,154 +0,0 @@ -import express from "express"; -import fetch from "node-fetch"; -import "dotenv/config"; - -const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8080 } = process.env; -const base = "https://api-m.sandbox.paypal.com"; -const app = express(); - -// parse post params sent in body in json format -app.use(express.json()); - -/** - * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs. - * @see https://developer.paypal.com/api/rest/authentication/ - */ -const generateAccessToken = async () => { - try { - if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) { - throw new Error("MISSING_API_CREDENTIALS"); - } - const auth = Buffer.from( - PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET, - ).toString("base64"); - const response = await fetch(`${base}/v1/oauth2/token`, { - method: "POST", - body: "grant_type=client_credentials", - headers: { - Authorization: `Basic ${auth}`, - }, - }); - - const data = await response.json(); - return data.access_token; - } catch (error) { - console.error("Failed to generate Access Token:", error); - } -}; - -/** - * Create an order to start the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create - */ -const createOrder = async (cart) => { - // use the cart information passed from the front-end to calculate the purchase unit details - console.log( - "shopping cart information passed from the frontend createOrder() callback:", - cart, - ); - - const accessToken = await generateAccessToken(); - const url = `${base}/v2/checkout/orders`; - const payload = { - intent: "CAPTURE", - purchase_units: [ - { - amount: { - currency_code: "USD", - value: "100.00", - }, - }, - ], - }; - - const response = await fetch(url, { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: - // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ - // "PayPal-Mock-Response": '{"mock_application_codes": "MISSING_REQUIRED_PARAMETER"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "PERMISSION_DENIED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' - }, - method: "POST", - body: JSON.stringify(payload), - }); - - return handleResponse(response); -}; - -/** - * Capture payment for the created order to complete the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture - */ -const captureOrder = async (orderID) => { - const accessToken = await generateAccessToken(); - const url = `${base}/v2/checkout/orders/${orderID}/capture`; - - const response = await fetch(url, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: - // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ - // "PayPal-Mock-Response": '{"mock_application_codes": "INSTRUMENT_DECLINED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "TRANSACTION_REFUSED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' - }, - }); - - return handleResponse(response); -}; - -async function handleResponse(response) { - try { - const jsonResponse = await response.json(); - return { - jsonResponse, - httpStatusCode: response.status, - }; - } catch (err) { - const errorMessage = await response.text(); - throw new Error(errorMessage); - } -} - -app.post("/api/orders", async (req, res) => { - try { - // use the cart information passed from the front-end to calculate the order amount detals - const { cart } = req.body; - const { jsonResponse, httpStatusCode } = await createOrder(cart); - res.status(httpStatusCode).json(jsonResponse); - } catch (error) { - console.error("Failed to create order:", error); - res.status(500).json({ error: "Failed to create order." }); - } -}); - -app.post("/api/orders/:orderID/capture", async (req, res) => { - try { - const { orderID } = req.params; - const { jsonResponse, httpStatusCode } = await captureOrder(orderID); - res.status(httpStatusCode).json(jsonResponse); - } catch (error) { - console.error("Failed to create order:", error); - res.status(500).json({ error: "Failed to capture order." }); - } -}); - -// render checkout page with client id & unique client token -app.get("/", async (req, res) => { - try { - res.render("checkout", { - clientId: PAYPAL_CLIENT_ID, - }); - } catch (err) { - res.status(500).send(err.message); - } -}); - -app.listen(PORT, () => { - console.log(`Node server listening at http://localhost:${PORT}/`); -}); diff --git a/advanced-integration/v2/server/php/README.md b/advanced-integration/v2/server/php/README.md index a789b6bf..2bcecf8d 100644 --- a/advanced-integration/v2/server/php/README.md +++ b/advanced-integration/v2/server/php/README.md @@ -20,14 +20,14 @@ This sample app demonstrates how to integrate with ACDC using PayPal's REST APIs 1. Add your API credentials to the environment: - - **Windows** + - **Windows (powershell)** ```powershell $env:PAYPAL_CLIENT_ID = "" $env:PAYPAL_CLIENT_SECRET = "" ``` - - **Unix** + - **Linux / MacOS** ```bash export PAYPAL_CLIENT_ID="" diff --git a/advanced-integration/v2/server/php/composer.json b/advanced-integration/v2/server/php/composer.json index 5adaa5aa..721ec31f 100644 --- a/advanced-integration/v2/server/php/composer.json +++ b/advanced-integration/v2/server/php/composer.json @@ -4,25 +4,13 @@ "require": { "php": "^7.4 || ^8.0", "ext-json": "*", - "guzzlehttp/guzzle": "^7.9", - "monolog/monolog": "^2.8", - "php-di/php-di": "^6.4" + "paypal/paypal-server-sdk": "0.5.1" }, "require-dev": { - "jangregor/phpstan-prophecy": "^1.0.0", - "phpspec/prophecy-phpunit": "^2.0", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.8", - "phpunit/phpunit": "^9.5.26", - "squizlabs/php_codesniffer": "^3.7" }, "scripts": { - "start": "php -S localhost:8080 -t server", - "test": "phpunit" + "start": "php -S localhost:8080 -t src" }, "config": { - "allow-plugins": { - "phpstan/extension-installer": true - } } -} \ No newline at end of file +} diff --git a/advanced-integration/v2/server/php/composer.lock b/advanced-integration/v2/server/php/composer.lock index 351abe8e..39a01f7b 100644 --- a/advanced-integration/v2/server/php/composer.lock +++ b/advanced-integration/v2/server/php/composer.lock @@ -4,283 +4,188 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "215478eda9b5efd723cd51c11808902f", + "content-hash": "d4a57a266f3f33beef57b02efc8cfaac", "packages": [ { - "name": "fig/http-message-util", - "version": "1.1.5", + "name": "apimatic/core", + "version": "0.3.11", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message-util.git", - "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + "url": "https://github.com/apimatic/core-lib-php.git", + "reference": "2274f103f9f210664f546f504e4559d772a81fee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", - "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "url": "https://api.github.com/repos/apimatic/core-lib-php/zipball/2274f103f9f210664f546f504e4559d772a81fee", + "reference": "2274f103f9f210664f546f504e4559d772a81fee", "shasum": "" }, "require": { - "php": "^5.3 || ^7.0 || ^8.0" + "apimatic/core-interfaces": "~0.1.5", + "apimatic/jsonmapper": "^3.1.1", + "ext-curl": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "php": "^7.2 || ^8.0", + "php-jsonpointer/php-jsonpointer": "^3.0.2", + "psr/log": "^1.1.4 || ^2.0.0 || ^3.0.0" }, - "suggest": { - "psr/http-message": "The package containing the PSR-7 interfaces" + "require-dev": { + "phan/phan": "5.4.2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "squizlabs/php_codesniffer": "^3.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, "autoload": { "psr-4": { - "Fig\\Http\\Message\\": "src/" + "Core\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "description": "Core logic and the utilities for the Apimatic's PHP SDK", + "homepage": "https://github.com/apimatic/core-lib-php", "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" + "apimatic", + "core", + "corelib", + "php" ], "support": { - "issues": "https://github.com/php-fig/http-message-util/issues", - "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + "issues": "https://github.com/apimatic/core-lib-php/issues", + "source": "https://github.com/apimatic/core-lib-php/tree/0.3.11" }, - "time": "2020-11-24T22:02:12+00:00" + "time": "2024-07-08T11:50:08+00:00" }, { - "name": "graham-campbell/result-type", - "version": "v1.1.3", + "name": "apimatic/core-interfaces", + "version": "0.1.5", "source": { "type": "git", - "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + "url": "https://github.com/apimatic/core-interfaces-php.git", + "reference": "b4f1bffc8be79584836f70af33c65e097eec155c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "url": "https://api.github.com/repos/apimatic/core-interfaces-php/zipball/b4f1bffc8be79584836f70af33c65e097eec155c", + "reference": "b4f1bffc8be79584836f70af33c65e097eec155c", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { "psr-4": { - "GrahamCampbell\\ResultType\\": "src/" + "CoreInterfaces\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - } - ], - "description": "An Implementation Of The Result Type", + "description": "Definition of the behavior of apimatic/core, apimatic/unirest-php and Apimatic's PHP SDK", + "homepage": "https://github.com/apimatic/core-interfaces-php", "keywords": [ - "Graham Campbell", - "GrahamCampbell", - "Result Type", - "Result-Type", - "result" + "apimatic", + "core", + "corelib", + "interface", + "php", + "unirest" ], "support": { - "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + "issues": "https://github.com/apimatic/core-interfaces-php/issues", + "source": "https://github.com/apimatic/core-interfaces-php/tree/0.1.5" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", - "type": "tidelift" - } - ], - "time": "2024-07-20T21:45:45+00:00" + "time": "2024-05-09T06:32:07+00:00" }, { - "name": "guzzlehttp/guzzle", - "version": "7.9.2", + "name": "apimatic/jsonmapper", + "version": "3.1.4", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + "url": "https://github.com/apimatic/jsonmapper.git", + "reference": "407b455d2adda2efa51a44b99400389fbee0394e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", - "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "url": "https://api.github.com/repos/apimatic/jsonmapper/zipball/407b455d2adda2efa51a44b99400389fbee0394e", + "reference": "407b455d2adda2efa51a44b99400389fbee0394e", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", - "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0" - }, - "provide": { - "psr/http-client-implementation": "1.0" + "php": "^5.6 || ^7.0 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "ext-curl": "*", - "guzzle/client-integration-tests": "3.0.2", - "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.39 || ^9.6.20", - "psr/log": "^1.1 || ^2.0 || ^3.0" - }, - "suggest": { - "ext-curl": "Required for CURL handler support", - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" + "phpunit/phpunit": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "squizlabs/php_codesniffer": "^3.0.0" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { - "GuzzleHttp\\": "src/" + "apimatic\\jsonmapper\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "OSL-3.0" ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Jeremy Lindblom", - "email": "jeremeamia@gmail.com", - "homepage": "https://github.com/jeremeamia" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" + "name": "Christian Weiske", + "email": "christian.weiske@netresearch.de", + "homepage": "http://www.netresearch.de/", + "role": "Developer" }, { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" + "name": "Mehdi Jaffery", + "email": "mehdi.jaffery@apimatic.io", + "homepage": "http://apimatic.io/", + "role": "Developer" } ], - "description": "Guzzle is a PHP HTTP client library", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "psr-18", - "psr-7", - "rest", - "web service" - ], + "description": "Map nested JSON structures onto PHP classes", "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + "email": "mehdi.jaffery@apimatic.io", + "issues": "https://github.com/apimatic/jsonmapper/issues", + "source": "https://github.com/apimatic/jsonmapper/tree/3.1.4" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", - "type": "tidelift" - } - ], - "time": "2024-07-24T11:22:20+00:00" + "time": "2024-06-11T11:48:30+00:00" }, { - "name": "guzzlehttp/promises", - "version": "2.0.3", + "name": "apimatic/unirest-php", + "version": "4.0.5", "source": { "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" + "url": "https://github.com/apimatic/unirest-php.git", + "reference": "e16754010c16be5473289470f129d87a0f41b55e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", - "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "url": "https://api.github.com/repos/apimatic/unirest-php/zipball/e16754010c16be5473289470f129d87a0f41b55e", + "reference": "e16754010c16be5473289470f129d87a0f41b55e", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0" + "apimatic/core-interfaces": "^0.1.0", + "ext-curl": "*", + "ext-json": "*", + "php": "^7.2 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phan/phan": "5.4.2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "squizlabs/php_codesniffer": "^3.5" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, "autoload": { "psr-4": { - "GuzzleHttp\\Promise\\": "src/" + "Unirest\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -289,198 +194,107 @@ ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" + "name": "Mashape", + "email": "opensource@mashape.com", + "homepage": "https://www.mashape.com", + "role": "Developer" }, { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" + "name": "APIMATIC", + "email": "opensource@apimatic.io", + "homepage": "https://www.apimatic.io", + "role": "Developer" } ], - "description": "Guzzle promises library", + "description": "Unirest PHP", + "homepage": "https://github.com/apimatic/unirest-php", "keywords": [ - "promise" + "client", + "curl", + "http", + "https", + "rest" ], "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.3" + "email": "opensource@apimatic.io", + "issues": "https://github.com/apimatic/unirest-php/issues", + "source": "https://github.com/apimatic/unirest-php/tree/4.0.5" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", - "type": "tidelift" - } - ], - "time": "2024-07-18T10:29:17+00:00" + "time": "2023-04-25T14:19:45+00:00" }, { - "name": "guzzlehttp/psr7", - "version": "2.7.0", + "name": "paypal/paypal-server-sdk", + "version": "0.5.1", "source": { "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + "url": "https://github.com/paypal/PayPal-PHP-Server-SDK.git", + "reference": "09148245f72f9dc2f6c8363b6206eac5effefa77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "url": "https://api.github.com/repos/paypal/PayPal-PHP-Server-SDK/zipball/09148245f72f9dc2f6c8363b6206eac5effefa77", + "reference": "09148245f72f9dc2f6c8363b6206eac5effefa77", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" + "apimatic/core": "~0.3.11", + "apimatic/core-interfaces": "~0.1.5", + "apimatic/unirest-php": "^4.0.0", + "ext-json": "*", + "php": "^7.2 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + "phan/phan": "5.4.2", + "squizlabs/php_codesniffer": "^3.5" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, "autoload": { "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" + "PaypalServerSDKLib\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], + "description": "PayPal's SDK for interacting with the REST APIs", + "homepage": "https://github.com/paypal/PayPal-PHP-Server-SDK", "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.0" + "issues": "https://github.com/paypal/PayPal-PHP-Server-SDK/issues", + "source": "https://github.com/paypal/PayPal-PHP-Server-SDK/tree/0.5.1" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" - } - ], - "time": "2024-07-18T11:15:46+00:00" + "time": "2024-09-10T15:31:38+00:00" }, { - "name": "laravel/serializable-closure", - "version": "v1.3.3", + "name": "php-jsonpointer/php-jsonpointer", + "version": "v3.0.2", "source": { "type": "git", - "url": "https://github.com/laravel/serializable-closure.git", - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" + "url": "https://github.com/raphaelstolt/php-jsonpointer.git", + "reference": "4428f86c6f23846e9faa5a420c4ef14e485b3afb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", + "url": "https://api.github.com/repos/raphaelstolt/php-jsonpointer/zipball/4428f86c6f23846e9faa5a420c4ef14e485b3afb", + "reference": "4428f86c6f23846e9faa5a420c4ef14e485b3afb", "shasum": "" }, "require": { - "php": "^7.3|^8.0" + "php": ">=5.4" }, "require-dev": { - "nesbot/carbon": "^2.61", - "pestphp/pest": "^1.21.3", - "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11" + "friendsofphp/php-cs-fixer": "^1.11", + "phpunit/phpunit": "4.6.*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-4": { - "Laravel\\SerializableClosure\\": "src/" + "psr-0": { + "Rs\\Json": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -489,92 +303,50 @@ ], "authors": [ { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - }, - { - "name": "Nuno Maduro", - "email": "nuno@laravel.com" + "name": "Raphael Stolt", + "email": "raphael.stolt@gmail.com", + "homepage": "http://raphaelstolt.blogspot.com/" } ], - "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "description": "Implementation of JSON Pointer (http://tools.ietf.org/html/rfc6901)", + "homepage": "https://github.com/raphaelstolt/php-jsonpointer", "keywords": [ - "closure", - "laravel", - "serializable" + "json", + "json pointer", + "json traversal" ], "support": { - "issues": "https://github.com/laravel/serializable-closure/issues", - "source": "https://github.com/laravel/serializable-closure" + "issues": "https://github.com/raphaelstolt/php-jsonpointer/issues", + "source": "https://github.com/raphaelstolt/php-jsonpointer/tree/master" }, - "time": "2023-11-08T14:08:06+00:00" + "time": "2016-08-29T08:51:01+00:00" }, { - "name": "monolog/monolog", - "version": "2.9.3", + "name": "psr/log", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215" + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/a30bfe2e142720dfa990d0a7e573997f5d884215", - "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { - "php": ">=7.2", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" - }, - "provide": { - "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" - }, - "require-dev": { - "aws/aws-sdk-php": "^2.4.9 || ^3.0", - "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^7 || ^8", - "ext-json": "*", - "graylog2/gelf-php": "^1.4.2 || ^2@dev", - "guzzlehttp/guzzle": "^7.4", - "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", - "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpspec/prophecy": "^1.15", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.5.38 || ^9.6.19", - "predis/predis": "^1.1 || ^2.0", - "rollbar/rollbar": "^1.3 || ^2 || ^3", - "ruflin/elastica": "^7", - "swiftmailer/swiftmailer": "^5.3|^6.0", - "symfony/mailer": "^5.4 || ^6", - "symfony/mime": "^5.4 || ^6" - }, - "suggest": { - "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", - "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", - "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", - "ext-mbstring": "Allow to work properly with unicode symbols", - "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", - "ext-openssl": "Required to send log messages using SSL", - "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", - "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", - "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", - "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { - "Monolog\\": "src/Monolog" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -583,3894 +355,24 @@ ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "https://seld.be" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "https://github.com/Seldaek/monolog", + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ "log", - "logging", + "psr", "psr-3" ], "support": { - "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.9.3" - }, - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", - "type": "tidelift" - } - ], - "time": "2024-04-12T20:52:51+00:00" - }, - { - "name": "nikic/fast-route", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/FastRoute.git", - "reference": "181d480e08d9476e61381e04a71b34dc0432e812" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", - "reference": "181d480e08d9476e61381e04a71b34dc0432e812", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35|~5.7" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "FastRoute\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov", - "email": "nikic@php.net" - } - ], - "description": "Fast request router for PHP", - "keywords": [ - "router", - "routing" - ], - "support": { - "issues": "https://github.com/nikic/FastRoute/issues", - "source": "https://github.com/nikic/FastRoute/tree/master" - }, - "time": "2018-02-13T20:26:39+00:00" - }, - { - "name": "php-di/invoker", - "version": "2.3.4", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", - "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "psr/container": "^1.0|^2.0" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Invoker\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Generic and extensible callable invoker", - "homepage": "https://github.com/PHP-DI/Invoker", - "keywords": [ - "callable", - "dependency", - "dependency-injection", - "injection", - "invoke", - "invoker" - ], - "support": { - "issues": "https://github.com/PHP-DI/Invoker/issues", - "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - } - ], - "time": "2023-09-08T09:24:21+00:00" - }, - { - "name": "php-di/php-di", - "version": "6.4.0", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PHP-DI.git", - "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/ae0f1b3b03d8b29dff81747063cbfd6276246cc4", - "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4", - "shasum": "" - }, - "require": { - "laravel/serializable-closure": "^1.0", - "php": ">=7.4.0", - "php-di/invoker": "^2.0", - "php-di/phpdoc-reader": "^2.0.1", - "psr/container": "^1.0" - }, - "provide": { - "psr/container-implementation": "^1.0" - }, - "require-dev": { - "doctrine/annotations": "~1.10", - "friendsofphp/php-cs-fixer": "^2.4", - "mnapoli/phpunit-easymock": "^1.2", - "ocramius/proxy-manager": "^2.11.2", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^9.5" - }, - "suggest": { - "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", - "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "DI\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The dependency injection container for humans", - "homepage": "https://php-di.org/", - "keywords": [ - "PSR-11", - "container", - "container-interop", - "dependency injection", - "di", - "ioc", - "psr11" - ], - "support": { - "issues": "https://github.com/PHP-DI/PHP-DI/issues", - "source": "https://github.com/PHP-DI/PHP-DI/tree/6.4.0" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", - "type": "tidelift" - } - ], - "time": "2022-04-09T16:46:38+00:00" - }, - { - "name": "php-di/phpdoc-reader", - "version": "2.2.1", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PhpDocReader.git", - "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", - "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "require-dev": { - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^8.5|^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "PhpDocReader\\": "src/PhpDocReader" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", - "keywords": [ - "phpdoc", - "reflection" - ], - "support": { - "issues": "https://github.com/PHP-DI/PhpDocReader/issues", - "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" - }, - "time": "2020-10-12T12:39:22+00:00" - }, - { - "name": "phpoption/phpoption", - "version": "1.9.3", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - }, - "branch-alias": { - "dev-master": "1.9-dev" - } - }, - "autoload": { - "psr-4": { - "PhpOption\\": "src/PhpOption/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh" - }, - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - } - ], - "description": "Option Type for PHP", - "keywords": [ - "language", - "option", - "php", - "type" - ], - "support": { - "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", - "type": "tidelift" - } - ], - "time": "2024-07-20T21:41:07+00:00" - }, - { - "name": "psr/container", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" - }, - "time": "2021-11-05T16:50:12+00:00" - }, - { - "name": "psr/http-client", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", - "shasum": "" - }, - "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], - "support": { - "source": "https://github.com/php-fig/http-client" - }, - "time": "2023-09-23T14:17:50+00:00" - }, - { - "name": "psr/http-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory" - }, - "time": "2024-04-15T12:06:14+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "psr/http-server-handler", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-server-handler.git", - "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", - "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", - "shasum": "" - }, - "require": { - "php": ">=7.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Server\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP server-side request handler", - "keywords": [ - "handler", - "http", - "http-interop", - "psr", - "psr-15", - "psr-7", - "request", - "response", - "server" - ], - "support": { - "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" - }, - "time": "2023-04-10T20:06:20+00:00" - }, - { - "name": "psr/http-server-middleware", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-server-middleware.git", - "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", - "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", - "shasum": "" - }, - "require": { - "php": ">=7.0", - "psr/http-message": "^1.0 || ^2.0", - "psr/http-server-handler": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Server\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP server-side middleware", - "keywords": [ - "http", - "http-interop", - "middleware", - "psr", - "psr-15", - "psr-7", - "request", - "response" - ], - "support": { - "issues": "https://github.com/php-fig/http-server-middleware/issues", - "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" - }, - "time": "2023-04-11T06:14:47+00:00" - }, - { - "name": "psr/log", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" - }, - "time": "2021-07-14T16:46:02+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "slim/http", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim-Http.git", - "reference": "a8def7b8e9eabd0cdc21654ad4a82606942e066a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim-Http/zipball/a8def7b8e9eabd0cdc21654ad4a82606942e066a", - "reference": "a8def7b8e9eabd0cdc21654ad4a82606942e066a", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-simplexml": "*", - "php": "^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0" - }, - "require-dev": { - "adriansuter/php-autoload-override": "^1.4", - "doctrine/instantiator": "^1.3.1", - "laminas/laminas-diactoros": "^3.1.0", - "nyholm/psr7": "^1.8.1", - "php-http/psr7-integration-tests": "^1.3.0", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.6", - "squizlabs/php_codesniffer": "^3.9" - }, - "type": "library", - "autoload": { - "psr-4": { - "Slim\\Http\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "http://joshlockhart.com" - }, - { - "name": "Andrew Smith", - "email": "a.smith@silentworks.co.uk", - "homepage": "http://silentworks.co.uk" - }, - { - "name": "Rob Allen", - "email": "rob@akrabat.com", - "homepage": "http://akrabat.com" - }, - { - "name": "Pierre Berube", - "email": "pierre@lgse.com", - "homepage": "http://www.lgse.com" - } - ], - "description": "Slim PSR-7 Object Decorators", - "homepage": "http://slimframework.com", - "keywords": [ - "http", - "psr-7", - "psr7" - ], - "support": { - "issues": "https://github.com/slimphp/Slim-Http/issues", - "source": "https://github.com/slimphp/Slim-Http/tree/1.4.0" - }, - "time": "2024-06-24T18:27:41+00:00" - }, - { - "name": "slim/middleware", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim-Middleware.git", - "reference": "1190251a89a3044eda9d16dcb456dc92dba2d0c8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim-Middleware/zipball/1190251a89a3044eda9d16dcb456dc92dba2d0c8", - "reference": "1190251a89a3044eda9d16dcb456dc92dba2d0c8", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "slim/slim": ">=2.3.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Slim": "./src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "info@joshlockhart.com", - "homepage": "http://www.joshlockhart.com/" - } - ], - "description": "Slim Framework middleware", - "homepage": "http://github.com/codeguy/Slim", - "keywords": [ - "middleware", - "slim" - ], - "support": { - "issues": "https://github.com/slimphp/Slim-Middleware/issues", - "source": "https://github.com/slimphp/Slim-Middleware/tree/1.0.0" - }, - "abandoned": true, - "time": "2013-09-18T18:13:40+00:00" - }, - { - "name": "slim/psr7", - "version": "1.7.0", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim-Psr7.git", - "reference": "753e9646def5ff4db1a06e5cf4ef539bfd30f467" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/753e9646def5ff4db1a06e5cf4ef539bfd30f467", - "reference": "753e9646def5ff4db1a06e5cf4ef539bfd30f467", - "shasum": "" - }, - "require": { - "fig/http-message-util": "^1.1.5", - "php": "^8.0", - "psr/http-factory": "^1.1", - "psr/http-message": "^1.0 || ^2.0", - "ralouphie/getallheaders": "^3.0", - "symfony/polyfill-php80": "^1.29" - }, - "provide": { - "psr/http-factory-implementation": "^1.0", - "psr/http-message-implementation": "^1.0 || ^2.0" - }, - "require-dev": { - "adriansuter/php-autoload-override": "^1.4", - "ext-json": "*", - "http-interop/http-factory-tests": "^1.1.0", - "php-http/psr7-integration-tests": "1.3.0", - "phpspec/prophecy": "^1.19", - "phpspec/prophecy-phpunit": "^2.2", - "phpstan/phpstan": "^1.11", - "phpunit/phpunit": "^9.6", - "squizlabs/php_codesniffer": "^3.10" - }, - "type": "library", - "autoload": { - "psr-4": { - "Slim\\Psr7\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "http://joshlockhart.com" - }, - { - "name": "Andrew Smith", - "email": "a.smith@silentworks.co.uk", - "homepage": "http://silentworks.co.uk" - }, - { - "name": "Rob Allen", - "email": "rob@akrabat.com", - "homepage": "http://akrabat.com" - }, - { - "name": "Pierre Berube", - "email": "pierre@lgse.com", - "homepage": "http://www.lgse.com" - } - ], - "description": "Strict PSR-7 implementation", - "homepage": "https://www.slimframework.com", - "keywords": [ - "http", - "psr-7", - "psr7" - ], - "support": { - "issues": "https://github.com/slimphp/Slim-Psr7/issues", - "source": "https://github.com/slimphp/Slim-Psr7/tree/1.7.0" - }, - "time": "2024-06-08T14:48:17+00:00" - }, - { - "name": "slim/slim", - "version": "4.14.0", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim.git", - "reference": "5943393b88716eb9e82c4161caa956af63423913" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/5943393b88716eb9e82c4161caa956af63423913", - "reference": "5943393b88716eb9e82c4161caa956af63423913", - "shasum": "" - }, - "require": { - "ext-json": "*", - "nikic/fast-route": "^1.3", - "php": "^7.4 || ^8.0", - "psr/container": "^1.0 || ^2.0", - "psr/http-factory": "^1.1", - "psr/http-message": "^1.1 || ^2.0", - "psr/http-server-handler": "^1.0", - "psr/http-server-middleware": "^1.0", - "psr/log": "^1.1 || ^2.0 || ^3.0" - }, - "require-dev": { - "adriansuter/php-autoload-override": "^1.4", - "ext-simplexml": "*", - "guzzlehttp/psr7": "^2.6", - "httpsoft/http-message": "^1.1", - "httpsoft/http-server-request": "^1.1", - "laminas/laminas-diactoros": "^2.17 || ^3", - "nyholm/psr7": "^1.8", - "nyholm/psr7-server": "^1.1", - "phpspec/prophecy": "^1.19", - "phpspec/prophecy-phpunit": "^2.1", - "phpstan/phpstan": "^1.11", - "phpunit/phpunit": "^9.6", - "slim/http": "^1.3", - "slim/psr7": "^1.6", - "squizlabs/php_codesniffer": "^3.10", - "vimeo/psalm": "^5.24" - }, - "suggest": { - "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", - "ext-xml": "Needed to support XML format in BodyParsingMiddleware", - "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", - "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." - }, - "type": "library", - "autoload": { - "psr-4": { - "Slim\\": "Slim" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "https://joshlockhart.com" - }, - { - "name": "Andrew Smith", - "email": "a.smith@silentworks.co.uk", - "homepage": "http://silentworks.co.uk" - }, - { - "name": "Rob Allen", - "email": "rob@akrabat.com", - "homepage": "http://akrabat.com" - }, - { - "name": "Pierre Berube", - "email": "pierre@lgse.com", - "homepage": "http://www.lgse.com" - }, - { - "name": "Gabriel Manricks", - "email": "gmanricks@me.com", - "homepage": "http://gabrielmanricks.com" - } - ], - "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", - "homepage": "https://www.slimframework.com", - "keywords": [ - "api", - "framework", - "micro", - "router" - ], - "support": { - "docs": "https://www.slimframework.com/docs/v4/", - "forum": "https://discourse.slimframework.com/", - "irc": "irc://irc.freenode.net:6667/slimphp", - "issues": "https://github.com/slimphp/Slim/issues", - "rss": "https://www.slimframework.com/blog/feed.rss", - "slack": "https://slimphp.slack.com/", - "source": "https://github.com/slimphp/Slim", - "wiki": "https://github.com/slimphp/Slim/wiki" - }, - "funding": [ - { - "url": "https://opencollective.com/slimphp", - "type": "open_collective" - }, - { - "url": "https://tidelift.com/funding/github/packagist/slim/slim", - "type": "tidelift" - } - ], - "time": "2024-06-13T08:54:48+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.5.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-04-18T09:32:20+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T15:07:36+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-06-19T12:30:46+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T15:07:36+00:00" - }, - { - "name": "vlucas/phpdotenv", - "version": "v5.6.1", - "source": { - "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", - "shasum": "" - }, - "require": { - "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", - "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "ext-filter": "*", - "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" - }, - "suggest": { - "ext-filter": "Required to use the boolean validator." - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - }, - "branch-alias": { - "dev-master": "5.6-dev" - } - }, - "autoload": { - "psr-4": { - "Dotenv\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "https://github.com/vlucas" - } - ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", - "keywords": [ - "dotenv", - "env", - "environment" - ], - "support": { - "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", - "type": "tidelift" - } - ], - "time": "2024-07-20T21:52:34+00:00" - } - ], - "packages-dev": [ - { - "name": "doctrine/deprecations", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.3" - }, - "time": "2024-01-30T19:34:25+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.9.4", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:23:10+00:00" - }, - { - "name": "jangregor/phpstan-prophecy", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/Jan0707/phpstan-prophecy.git", - "reference": "5ee56c7db1d58f0578c82a35e3c1befe840e85a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jan0707/phpstan-prophecy/zipball/5ee56c7db1d58f0578c82a35e3c1befe840e85a9", - "reference": "5ee56c7db1d58f0578c82a35e3c1befe840e85a9", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0", - "phpstan/phpstan": "^1.0.0" - }, - "conflict": { - "phpspec/prophecy": "<1.7.0 || >=2.0.0", - "phpunit/phpunit": "<6.0.0 || >=12.0.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.1.1", - "ergebnis/license": "^1.0.0", - "ergebnis/php-cs-fixer-config": "~2.2.0", - "phpspec/prophecy": "^1.7.0", - "phpunit/phpunit": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - } - }, - "autoload": { - "psr-4": { - "JanGregor\\Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Gregor Emge-Triebel", - "email": "jan@jangregor.me" - } - ], - "description": "Provides a phpstan/phpstan extension for phpspec/prophecy", - "support": { - "issues": "https://github.com/Jan0707/phpstan-prophecy/issues", - "source": "https://github.com/Jan0707/phpstan-prophecy/tree/1.0.2" - }, - "time": "2024-04-03T08:15:54+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.12.0", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2024-06-12T14:39:25+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v5.1.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "php": ">=7.4" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" - }, - "time": "2024-07-01T20:03:41+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "54750ef60c58e43759730615a392c31c80e23176" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", - "reference": "54750ef60c58e43759730615a392c31c80e23176", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:33:53+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.4.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", - "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.1", - "ext-filter": "*", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.5", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-webmozart-assert": "^1.2", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" - }, - "time": "2024-05-21T05:55:05+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.8.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "153ae662783729388a584b4361f2545e4d841e3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", - "reference": "153ae662783729388a584b4361f2545e4d841e3c", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.3 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.13" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" - }, - "time": "2024-02-23T11:10:43+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.19.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/67a759e7d8746d501c41536ba40cd9c0a07d6a87", - "reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2 || ^2.0", - "php": "^7.2 || 8.0.* || 8.1.* || 8.2.* || 8.3.*", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0 || ^6.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0 || ^7.0", - "phpstan/phpstan": "^1.9", - "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "dev", - "fake", - "mock", - "spy", - "stub" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.19.0" - }, - "time": "2024-02-29T11:52:51+00:00" - }, - { - "name": "phpspec/prophecy-phpunit", - "version": "v2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy-phpunit.git", - "reference": "16e1247e139434bce0bac09848bc5c8d882940fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/16e1247e139434bce0bac09848bc5c8d882940fc", - "reference": "16e1247e139434bce0bac09848bc5c8d882940fc", - "shasum": "" - }, - "require": { - "php": "^7.3 || ^8", - "phpspec/prophecy": "^1.18", - "phpunit/phpunit": "^9.1 || ^10.1 || ^11.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\PhpUnit\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christophe Coevoet", - "email": "stof@notk.org" - } - ], - "description": "Integrating the Prophecy mocking library in PHPUnit test cases", - "homepage": "http://phpspec.net", - "keywords": [ - "phpunit", - "prophecy" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy-phpunit/issues", - "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.2.0" - }, - "time": "2024-03-01T08:33:58+00:00" - }, - { - "name": "phpstan/extension-installer", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/phpstan/extension-installer.git", - "reference": "f6b87faf9fc7978eab2f7919a8760bc9f58f9203" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f6b87faf9fc7978eab2f7919a8760bc9f58f9203", - "reference": "f6b87faf9fc7978eab2f7919a8760bc9f58f9203", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2.0", - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.0" - }, - "require-dev": { - "composer/composer": "^2.0", - "php-parallel-lint/php-parallel-lint": "^1.2.0", - "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPStan\\ExtensionInstaller\\Plugin" - }, - "autoload": { - "psr-4": { - "PHPStan\\ExtensionInstaller\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Composer plugin for automatic installation of PHPStan extensions", - "support": { - "issues": "https://github.com/phpstan/extension-installer/issues", - "source": "https://github.com/phpstan/extension-installer/tree/1.4.1" - }, - "time": "2024-06-10T08:20:49+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "1.29.1", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" - }, - "time": "2024-05-31T08:52:43+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "1.11.8", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", - "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2024-07-24T07:01:22+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "9.2.31", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:37:42+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "3.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-12-02T12:48:52+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "5.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:16:10+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "9.6.20", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "49d7820565836236411f5dc002d16dd689cde42f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", - "reference": "49d7820565836236411f5dc002d16dd689cde42f", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.5.0 || ^2", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", - "phar-io/manifest": "^2.0.4", - "phar-io/version": "^3.2.1", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.31", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.4", - "phpunit/php-timer": "^5.0.3", - "sebastian/cli-parser": "^1.0.2", - "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.6", - "sebastian/environment": "^5.1.5", - "sebastian/exporter": "^4.0.6", - "sebastian/global-state": "^5.0.7", - "sebastian/object-enumerator": "^4.0.4", - "sebastian/resource-operations": "^3.0.4", - "sebastian/type": "^3.2.1", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.6-dev" - } - }, - "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2024-07-10T11:45:39+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:27:43+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" - }, - { - "name": "sebastian/comparator", - "version": "4.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T12:41:17+00:00" - }, - { - "name": "sebastian/complexity", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:19:30+00:00" - }, - { - "name": "sebastian/diff", - "version": "4.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:30:58+00:00" - }, - { - "name": "sebastian/environment", - "version": "5.1.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:03:51+00:00" - }, - { - "name": "sebastian/exporter", - "version": "4.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:33:00+00:00" - }, - { - "name": "sebastian/global-state", - "version": "5.0.7", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:35:11+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:20:34+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:12:34+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:14:26+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:07:39+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-14T16:00:52+00:00" - }, - { - "name": "sebastian/type", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", - "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:13:03+00:00" - }, - { - "name": "sebastian/version", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.10.2", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/86e5f5dd9a840c46810ebe5ff1885581c42a3017", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - } - ], - "time": "2024-07-21T23:26:44+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:36:25+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2022-06-03T18:03:27+00:00" + "time": "2024-09-11T13:17:53+00:00" } ], + "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": [], diff --git a/advanced-integration/v2/server/php/server/index.php b/advanced-integration/v2/server/php/server/index.php deleted file mode 100644 index e99a2841..00000000 --- a/advanced-integration/v2/server/php/server/index.php +++ /dev/null @@ -1,145 +0,0 @@ - false]); - $response = $client->post("$base/v1/oauth2/token", [ - 'form_params' => [ - 'grant_type' => 'client_credentials' - ], - 'headers' => [ - 'Authorization' => "Basic $auth" - ] - ]); - - $data = json_decode($response->getBody(), true); - return $data['access_token']; -} - -/** - * Create an order to start the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create - */ -function createOrder($cart) -{ - global $base; - - $accessToken = generateAccessToken(); - - // Disabling certificate validation for local development - $client = new Client(['verify' => false]); - $payload = [ - 'intent' => 'CAPTURE', - 'purchase_units' => [ - [ - 'amount' => [ - 'currency_code' => 'USD', - 'value' => '100.00' - ] - ] - ], - ]; - - $response = $client->post("$base/v2/checkout/orders", [ - 'headers' => [ - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer $accessToken" - ], - 'json' => $payload - ]); - - return handleResponse($response); -} - -/** - * Capture payment for the created order to complete the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture - */ -function captureOrder($orderID) -{ - global $base; - - $accessToken = generateAccessToken(); - - // Disabling certificate validation for local development - $client = new Client(['verify' => false]); - $response = $client->post("$base/v2/checkout/orders/$orderID/capture", [ - 'headers' => [ - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer $accessToken" - ] - ]); - - return handleResponse($response); -} - -function handleResponse($response) -{ - $jsonResponse = json_decode($response->getBody(), true); - return [ - 'jsonResponse' => $jsonResponse, - 'httpStatusCode' => $response->getStatusCode() - ]; -} - -$endpoint = $_SERVER['REQUEST_URI']; -if ($endpoint === '/') { - try { - $response = [ - "message" => "Server is running" - ]; - header('Content-Type: application/json'); - echo json_encode($response); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - http_response_code(500); - } -} - -if ($endpoint === '/api/orders') { - $data = json_decode(file_get_contents('php://input'), true); - $cart = $data['cart']; - header('Content-Type: application/json'); - try { - $orderResponse = createOrder($cart); - echo json_encode($orderResponse['jsonResponse']); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - http_response_code(500); - } -} - - -if (str_ends_with($endpoint, '/capture')) { - $urlSegments = explode('/', $endpoint); - end($urlSegments); // Will set the pointer to the end of array - $orderID = prev($urlSegments); - header('Content-Type: application/json'); - try { - $captureResponse = captureOrder($orderID); - echo json_encode($captureResponse['jsonResponse']); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - http_response_code(500); - } -} \ No newline at end of file diff --git a/advanced-integration/v2/server/php/server/.htaccess b/advanced-integration/v2/server/php/src/.htaccess similarity index 100% rename from advanced-integration/v2/server/php/server/.htaccess rename to advanced-integration/v2/server/php/src/.htaccess diff --git a/advanced-integration/v2/server/php/src/index.php b/advanced-integration/v2/server/php/src/index.php new file mode 100644 index 00000000..ee2b3d4c --- /dev/null +++ b/advanced-integration/v2/server/php/src/index.php @@ -0,0 +1,117 @@ +clientCredentialsAuthCredentials( + ClientCredentialsAuthCredentialsBuilder::init( + $PAYPAL_CLIENT_ID, + $PAYPAL_CLIENT_SECRET + ) + ) + ->environment(Environment::SANDBOX) + ->build(); + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +function createOrder($cart) +{ + global $client; + + $orderBody = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '100.00' + )->build() + )->build() + ] + )->build() + ]; + + $apiResponse = $client->getOrdersController()->ordersCreate($orderBody); + + return handleResponse($apiResponse); +} + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +function captureOrder($orderID) +{ + global $client; + + $captureBody = [ + 'id' => $orderID + ]; + + $apiResponse = $client->getOrdersController()->ordersCapture($captureBody); + + return handleResponse($apiResponse); +} + +function handleResponse($response) +{ + return [ + 'jsonResponse' => $response->getResult(), + 'httpStatusCode' => $response->getStatusCode() + ]; +} + +$endpoint = $_SERVER['REQUEST_URI']; +if ($endpoint === '/') { + try { + $response = [ + "message" => "Server is running" + ]; + header('Content-Type: application/json'); + echo json_encode($response); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + +if ($endpoint === '/api/orders') { + $data = json_decode(file_get_contents('php://input'), true); + $cart = $data['cart']; + header('Content-Type: application/json'); + try { + $orderResponse = createOrder($cart); + echo json_encode($orderResponse['jsonResponse']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + + +if (str_ends_with($endpoint, '/capture')) { + $urlSegments = explode('/', $endpoint); + end($urlSegments); // Will set the pointer to the end of array + $orderID = prev($urlSegments); + header('Content-Type: application/json'); + try { + $captureResponse = captureOrder($orderID); + echo json_encode($captureResponse['jsonResponse']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} diff --git a/standard-integration/client/html/README.md b/standard-integration/client/html/README.md index 302fcb42..fba52a4b 100644 --- a/standard-integration/client/html/README.md +++ b/standard-integration/client/html/README.md @@ -57,15 +57,15 @@ npm install 3. Starting the development server - - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory. + - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory. - **Start the client**: ```bash - npm run dev + npm run start ``` - This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). + This will start the development server, and you should be able to access the Standard Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). ### Additional Notes diff --git a/standard-integration/client/html/client/app.js b/standard-integration/client/html/src/app.js similarity index 100% rename from standard-integration/client/html/client/app.js rename to standard-integration/client/html/src/app.js diff --git a/standard-integration/client/html/client/index.html b/standard-integration/client/html/src/index.html similarity index 100% rename from standard-integration/client/html/client/index.html rename to standard-integration/client/html/src/index.html diff --git a/standard-integration/client/html/vite.config.js b/standard-integration/client/html/vite.config.js index 76921cbb..0a14da0e 100644 --- a/standard-integration/client/html/vite.config.js +++ b/standard-integration/client/html/vite.config.js @@ -5,7 +5,7 @@ export default defineConfig({ plugins: [], envDir: "../", envPrefix: "PAYPAL", - root: "client", + root: "src", server: { port: 3000, proxy: { diff --git a/standard-integration/client/react/README.md b/standard-integration/client/react/README.md index da8ec278..208ccd52 100644 --- a/standard-integration/client/react/README.md +++ b/standard-integration/client/react/README.md @@ -57,15 +57,15 @@ npm install 3. Starting the development server - - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory. + - **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory. - **Start the client**: ```bash - npm run dev + npm run start ``` - This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). + This will start the development server, and you should be able to access the Standard Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output). ### Additional Notes diff --git a/standard-integration/client/react/client/App.jsx b/standard-integration/client/react/src/App.jsx similarity index 100% rename from standard-integration/client/react/client/App.jsx rename to standard-integration/client/react/src/App.jsx diff --git a/standard-integration/client/react/client/index.html b/standard-integration/client/react/src/index.html similarity index 100% rename from standard-integration/client/react/client/index.html rename to standard-integration/client/react/src/index.html diff --git a/standard-integration/client/react/client/main.jsx b/standard-integration/client/react/src/main.jsx similarity index 100% rename from standard-integration/client/react/client/main.jsx rename to standard-integration/client/react/src/main.jsx diff --git a/standard-integration/client/react/vite.config.js b/standard-integration/client/react/vite.config.js index 8049384e..274f8cf5 100644 --- a/standard-integration/client/react/vite.config.js +++ b/standard-integration/client/react/vite.config.js @@ -4,7 +4,7 @@ import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], - root: "client", + root: "src", envDir: "../", envPrefix: "PAYPAL", server: { diff --git a/standard-integration/server/dotnet/PayPalAdvancedIntegration.csproj b/standard-integration/server/dotnet/PayPalStandardIntegration.csproj similarity index 100% rename from standard-integration/server/dotnet/PayPalAdvancedIntegration.csproj rename to standard-integration/server/dotnet/PayPalStandardIntegration.csproj diff --git a/standard-integration/server/dotnet/README.md b/standard-integration/server/dotnet/README.md index d1f5fd91..2405572a 100644 --- a/standard-integration/server/dotnet/README.md +++ b/standard-integration/server/dotnet/README.md @@ -1,4 +1,4 @@ -# Standard Integartion .NET Sample +# Standard Integration .NET Sample PayPal Standard Integration sample in .NET @@ -6,14 +6,14 @@ PayPal Standard Integration sample in .NET 1. **Add your API credentials to the environment:** - - **Windows** + - **Windows (powershell)** ```powershell $env:PAYPAL_CLIENT_ID = "" $env:PAYPAL_CLIENT_SECRET = "" ``` - - **Unix** + - **Linux / MacOS** ```bash export PAYPAL_CLIENT_ID="" diff --git a/standard-integration/server/java/README.md b/standard-integration/server/java/README.md index a9fcce21..1a242c7a 100644 --- a/standard-integration/server/java/README.md +++ b/standard-integration/server/java/README.md @@ -1,4 +1,4 @@ -# Standard Integartion Java Sample +# Standard Integration Java Sample PayPal Standard Integration sample in Java @@ -6,14 +6,14 @@ PayPal Standard Integration sample in Java 1. Add your API credentials to the environment: - - **Windows** + - **Windows (powershell)** ```powershell $env:PAYPAL_CLIENT_ID = "" $env:PAYPAL_CLIENT_SECRET = "" ``` - - **Unix** + - **Linux / MacOS** ```bash export PAYPAL_CLIENT_ID="" diff --git a/standard-integration/server/java/pom.xml b/standard-integration/server/java/pom.xml index ab4c30bc..647f687c 100644 --- a/standard-integration/server/java/pom.xml +++ b/standard-integration/server/java/pom.xml @@ -38,6 +38,17 @@ org.springframework.boot spring-boot-starter-web
+ + + com.paypal.sdk + + + paypal-server-sdk + + + 0.5.1 + +
diff --git a/standard-integration/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java b/standard-integration/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java index b4f3b4ae..f34fef3a 100644 --- a/standard-integration/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java +++ b/standard-integration/server/java/src/main/java/com/paypal/sample/SampleAppApplication.java @@ -1,30 +1,37 @@ package com.paypal.sample; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.client.RestTemplate; +import com.paypal.sdk.Environment; +import com.paypal.sdk.PaypalServerSDKClient; +import com.paypal.sdk.authentication.ClientCredentialsAuthModel; +import com.paypal.sdk.controllers.OrdersController; +import com.paypal.sdk.exceptions.ApiException; +import com.paypal.sdk.http.response.ApiResponse; +import com.paypal.sdk.models.AmountWithBreakdown; +import com.paypal.sdk.models.CheckoutPaymentIntent; +import com.paypal.sdk.models.Order; +import com.paypal.sdk.models.OrderRequest; +import com.paypal.sdk.models.OrdersCaptureInput; +import com.paypal.sdk.models.OrdersCreateInput; +import com.paypal.sdk.models.PurchaseUnitRequest; +import java.util.Arrays; +import org.slf4j.event.Level; + import java.io.IOException; -import java.util.Base64; import java.util.Map; @SpringBootApplication @@ -36,8 +43,6 @@ public class SampleAppApplication { @Value("${PAYPAL_CLIENT_SECRET}") private String PAYPAL_CLIENT_SECRET; - private final String BASE_URL = "https://api-m.sandbox.paypal.com"; - public static void main(String[] args) { SpringApplication.run(SampleAppApplication.class, args); } @@ -47,23 +52,41 @@ public RestTemplate restTemplate() { return new RestTemplate(); } + @Bean + public PaypalServerSDKClient paypalClient() { + return new PaypalServerSDKClient.Builder() + .loggingConfig(builder -> builder + .level(Level.DEBUG) + .requestConfig(logConfigBuilder -> logConfigBuilder.body(true)) + .responseConfig(logConfigBuilder -> logConfigBuilder.headers(true))) + .httpClientConfig(configBuilder -> configBuilder + .timeout(0)) + .environment(Environment.SANDBOX) + .clientCredentialsAuth(new ClientCredentialsAuthModel.Builder( + PAYPAL_CLIENT_ID, + PAYPAL_CLIENT_SECRET) + .build()) + .build(); + } + + @Controller @RequestMapping("/") public class CheckoutController { - private final RestTemplate restTemplate; private final ObjectMapper objectMapper; + private final PaypalServerSDKClient client; - public CheckoutController(RestTemplate restTemplate, ObjectMapper objectMapper) { - this.restTemplate = restTemplate; + public CheckoutController(ObjectMapper objectMapper, PaypalServerSDKClient client) { this.objectMapper = objectMapper; + this.client = client; } @PostMapping("/api/orders") - public ResponseEntity createOrder(@RequestBody Map request) { + public ResponseEntity createOrder(@RequestBody Map request) { try { String cart = objectMapper.writeValueAsString(request.get("cart")); - JsonNode response = createOrder(cart); + Order response = createOrder(cart); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { e.printStackTrace(); @@ -72,69 +95,47 @@ public ResponseEntity createOrder(@RequestBody Map req } @PostMapping("/api/orders/{orderID}/capture") - public ResponseEntity captureOrder(@PathVariable String orderID) { + public ResponseEntity captureOrder(@PathVariable String orderID) { try { - JsonNode response = captureOrders(orderID); - return new ResponseEntity<>(response, HttpStatus.OK); + Order response = captureOrders(orderID); + return new ResponseEntity(response, HttpStatus.OK); } catch (Exception e) { e.printStackTrace(); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } - private String generateAccessToken() throws IOException { - if (PAYPAL_CLIENT_ID == null || PAYPAL_CLIENT_SECRET == null) { - throw new IllegalArgumentException("MISSING_API_CREDENTIALS"); - } - String auth = Base64.getEncoder().encodeToString((PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET).getBytes()); - HttpHeaders headers = new HttpHeaders(); - headers.setBasicAuth(auth); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - - MultiValueMap body = new LinkedMultiValueMap<>(); - body.add("grant_type", "client_credentials"); - - ResponseEntity response = restTemplate.postForEntity(BASE_URL + "/v1/oauth2/token", new HttpEntity<>(body, headers), JsonNode.class); - return response.getBody().get("access_token").asText(); - } - - private JsonNode createOrder(String cart) throws IOException { - String accessToken = generateAccessToken(); - String url = BASE_URL + "/v2/checkout/orders"; + private Order createOrder(String cart) throws IOException, ApiException { - ObjectNode payload = objectMapper.createObjectNode(); - payload.put("intent", "CAPTURE"); - ObjectNode purchaseUnit = payload.putArray("purchase_units").addObject(); - ObjectNode amount = purchaseUnit.putObject("amount"); - amount.put("currency_code", "USD"); - amount.put("value", "100.00"); + OrdersCreateInput ordersCreateInput = new OrdersCreateInput.Builder( + null, + new OrderRequest.Builder( + CheckoutPaymentIntent.CAPTURE, + Arrays.asList( + new PurchaseUnitRequest.Builder( + new AmountWithBreakdown.Builder( + "USD", + "100.00") + .build()) + .build())) + .build()) + .build(); - HttpHeaders headers = new HttpHeaders(); - headers.setBearerAuth(accessToken); - headers.setContentType(MediaType.APPLICATION_JSON); + OrdersController ordersController = client.getOrdersController(); - ResponseEntity response = restTemplate.postForEntity(url, new HttpEntity<>(payload, headers), JsonNode.class); - return handleResponse(response); - } - - private JsonNode captureOrders(String orderID) throws IOException { - String accessToken = generateAccessToken(); - String url = BASE_URL + "/v2/checkout/orders/" + orderID + "/capture"; + ApiResponse apiResponse = ordersController.ordersCreate(ordersCreateInput); - HttpHeaders headers = new HttpHeaders(); - headers.setBearerAuth(accessToken); - headers.setContentType(MediaType.APPLICATION_JSON); - - ResponseEntity response = restTemplate.postForEntity(url, new HttpEntity<>(headers), JsonNode.class); - return handleResponse(response); + return apiResponse.getResult(); } - private JsonNode handleResponse(ResponseEntity response) throws IOException { - if (response.getStatusCode().is2xxSuccessful()) { - return response.getBody(); - } else { - throw new IOException(response.getBody().toString()); - } + private Order captureOrders(String orderID) throws IOException, ApiException { + OrdersCaptureInput ordersCaptureInput = new OrdersCaptureInput.Builder( + orderID, + null) + .build(); + OrdersController ordersController = client.getOrdersController(); + ApiResponse apiResponse = ordersController.ordersCapture(ordersCaptureInput); + return apiResponse.getResult(); } } } diff --git a/standard-integration/server/node/README.md b/standard-integration/server/node/README.md index 0fce05d5..81657297 100644 --- a/standard-integration/server/node/README.md +++ b/standard-integration/server/node/README.md @@ -1,4 +1,4 @@ -# Standard Integartion Node.js Sample +# Standard Integration Node.js Sample PayPal Standard Integration sample in Node.js @@ -6,14 +6,14 @@ PayPal Standard Integration sample in Node.js 1. Add your API credentials to the environment: - - **Windows** + - **Windows (powershell)** ```powershell $env:PAYPAL_CLIENT_ID = "" $env:PAYPAL_CLIENT_SECRET = "" ``` - - **Unix** + - **Linux / MacOS** ```bash export PAYPAL_CLIENT_ID="" diff --git a/standard-integration/server/node/package.json b/standard-integration/server/node/package.json index 006a766d..29301738 100644 --- a/standard-integration/server/node/package.json +++ b/standard-integration/server/node/package.json @@ -4,14 +4,15 @@ "private": true, "type": "module", "dependencies": { + "@paypal/paypal-server-sdk": "^0.5.1", + "body-parser": "^1.20.3", "dotenv": "^16.3.1", - "express": "^4.18.2", - "node-fetch": "^3.3.2" + "express": "^4.18.2" }, "scripts": { - "server-dev": "nodemon server/server.js", + "server-dev": "nodemon server.js", "start": "npm run server-dev", - "prod": "node server/server.js", + "prod": "node server.js", "format": "npx prettier --write **/*.{js,jsx,md}", "format:check": "npx prettier --check **/*.{js,jsx,md}" }, diff --git a/standard-integration/server/node/server.js b/standard-integration/server/node/server.js new file mode 100644 index 00000000..08aadad1 --- /dev/null +++ b/standard-integration/server/node/server.js @@ -0,0 +1,127 @@ +import express from "express"; +import "dotenv/config"; +import { + ApiError, + CheckoutPaymentIntent, + Client, + Environment, + LogLevel, + OrdersController, +} from "@paypal/paypal-server-sdk"; +import bodyParser from "body-parser"; + +const app = express(); +app.use(bodyParser.json()); + +const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8080 } = process.env; + +const client = new Client({ + clientCredentialsAuthCredentials: { + oAuthClientId: PAYPAL_CLIENT_ID, + oAuthClientSecret: PAYPAL_CLIENT_SECRET, + }, + timeout: 0, + environment: Environment.Sandbox, + logging: { + logLevel: LogLevel.Info, + logRequest: { + logBody: true, + }, + logResponse: { + logHeaders: true, + }, + }, +}); + +const ordersController = new OrdersController(client); + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +const createOrder = async (cart) => { + const collect = { + body: { + intent: CheckoutPaymentIntent.CAPTURE, + purchaseUnits: [ + { + amount: { + currencyCode: "USD", + value: "100.00", + }, + }, + ], + }, + prefer: "return=minimal", + }; + + try { + const { body, ...httpResponse } = + await ordersController.ordersCreate(collect); + // Get more response info... + // const { statusCode, headers } = httpResponse; + return { + jsonResponse: JSON.parse(body), + httpStatusCode: httpResponse.statusCode, + }; + } catch (error) { + if (error instanceof ApiError) { + // const { statusCode, headers } = error; + throw new Error(error.message); + } + } +}; + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +const captureOrder = async (orderID) => { + const collect = { + id: orderID, + prefer: "return=minimal", + }; + + try { + const { body, ...httpResponse } = + await ordersController.ordersCapture(collect); + // Get more response info... + // const { statusCode, headers } = httpResponse; + return { + jsonResponse: JSON.parse(body), + httpStatusCode: httpResponse.statusCode, + }; + } catch (error) { + if (error instanceof ApiError) { + // const { statusCode, headers } = error; + throw new Error(error.message); + } + } +}; + +app.post("/api/orders", async (req, res) => { + try { + // use the cart information passed from the front-end to calculate the order amount detals + const { cart } = req.body; + const { jsonResponse, httpStatusCode } = await createOrder(cart); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to create order." }); + } +}); + +app.post("/api/orders/:orderID/capture", async (req, res) => { + try { + const { orderID } = req.params; + const { jsonResponse, httpStatusCode } = await captureOrder(orderID); + res.status(httpStatusCode).json(jsonResponse); + } catch (error) { + console.error("Failed to create order:", error); + res.status(500).json({ error: "Failed to capture order." }); + } +}); + +app.listen(PORT, () => { + console.log(`Node server listening at http://localhost:${PORT}/`); +}); diff --git a/standard-integration/server/node/server/server.js b/standard-integration/server/node/server/server.js deleted file mode 100644 index 1e2f9d4a..00000000 --- a/standard-integration/server/node/server/server.js +++ /dev/null @@ -1,154 +0,0 @@ -import express from "express"; -import fetch from "node-fetch"; -import "dotenv/config"; - -const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT = 8080 } = process.env; -const base = "https://api-m.sandbox.paypal.com"; -const app = express(); - -// parse post params sent in body in json format -app.use(express.json()); - -/** - * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs. - * @see https://developer.paypal.com/api/rest/authentication/ - */ -const generateAccessToken = async () => { - try { - if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) { - throw new Error("MISSING_API_CREDENTIALS"); - } - const auth = Buffer.from( - PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET, - ).toString("base64"); - const response = await fetch(`${base}/v1/oauth2/token`, { - method: "POST", - body: "grant_type=client_credentials", - headers: { - Authorization: `Basic ${auth}`, - }, - }); - - const data = await response.json(); - return data.access_token; - } catch (error) { - console.error("Failed to generate Access Token:", error); - } -}; - -/** - * Create an order to start the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create - */ -const createOrder = async (cart) => { - // use the cart information passed from the front-end to calculate the purchase unit details - console.log( - "shopping cart information passed from the frontend createOrder() callback:", - cart, - ); - - const accessToken = await generateAccessToken(); - const url = `${base}/v2/checkout/orders`; - const payload = { - intent: "CAPTURE", - purchase_units: [ - { - amount: { - currency_code: "USD", - value: "100.00", - }, - }, - ], - }; - - const response = await fetch(url, { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: - // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ - // "PayPal-Mock-Response": '{"mock_application_codes": "MISSING_REQUIRED_PARAMETER"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "PERMISSION_DENIED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' - }, - method: "POST", - body: JSON.stringify(payload), - }); - - return handleResponse(response); -}; - -/** - * Capture payment for the created order to complete the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture - */ -const captureOrder = async (orderID) => { - const accessToken = await generateAccessToken(); - const url = `${base}/v2/checkout/orders/${orderID}/capture`; - - const response = await fetch(url, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation: - // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/ - // "PayPal-Mock-Response": '{"mock_application_codes": "INSTRUMENT_DECLINED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "TRANSACTION_REFUSED"}' - // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}' - }, - }); - - return handleResponse(response); -}; - -async function handleResponse(response) { - try { - const jsonResponse = await response.json(); - return { - jsonResponse, - httpStatusCode: response.status, - }; - } catch (err) { - const errorMessage = await response.text(); - throw new Error(errorMessage); - } -} - -app.post("/api/orders", async (req, res) => { - try { - // use the cart information passed from the front-end to calculate the order amount detals - const { cart } = req.body; - const { jsonResponse, httpStatusCode } = await createOrder(cart); - res.status(httpStatusCode).json(jsonResponse); - } catch (error) { - console.error("Failed to create order:", error); - res.status(500).json({ error: "Failed to create order." }); - } -}); - -app.post("/api/orders/:orderID/capture", async (req, res) => { - try { - const { orderID } = req.params; - const { jsonResponse, httpStatusCode } = await captureOrder(orderID); - res.status(httpStatusCode).json(jsonResponse); - } catch (error) { - console.error("Failed to create order:", error); - res.status(500).json({ error: "Failed to capture order." }); - } -}); - -// render checkout page with client id & unique client token -app.get("/", async (req, res) => { - try { - res.render("checkout", { - clientId: PAYPAL_CLIENT_ID, - }); - } catch (err) { - res.status(500).send(err.message); - } -}); - -app.listen(PORT, () => { - console.log(`Node server listening at http://localhost:${PORT}/`); -}); diff --git a/standard-integration/server/php/README.md b/standard-integration/server/php/README.md index 53284b42..dd42041d 100644 --- a/standard-integration/server/php/README.md +++ b/standard-integration/server/php/README.md @@ -20,14 +20,14 @@ This sample app demonstrates how to integrate with ACDC using PayPal's REST APIs 1. Add your API credentials to the environment: - - **Windows** + - **Windows (powershell)** ```powershell $env:PAYPAL_CLIENT_ID = "" $env:PAYPAL_CLIENT_SECRET = "" ``` - - **Unix** + - **Linux / MacOS** ```bash export PAYPAL_CLIENT_ID="" diff --git a/standard-integration/server/php/composer.json b/standard-integration/server/php/composer.json index 7f87a9c2..e3135ef3 100644 --- a/standard-integration/server/php/composer.json +++ b/standard-integration/server/php/composer.json @@ -4,25 +4,13 @@ "require": { "php": "^7.4 || ^8.0", "ext-json": "*", - "guzzlehttp/guzzle": "^7.9", - "monolog/monolog": "^2.8", - "php-di/php-di": "^6.4" + "paypal/paypal-server-sdk": "0.5.1" }, "require-dev": { - "jangregor/phpstan-prophecy": "^1.0.0", - "phpspec/prophecy-phpunit": "^2.0", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.8", - "phpunit/phpunit": "^9.5.26", - "squizlabs/php_codesniffer": "^3.7" }, "scripts": { - "start": "php -S localhost:8080 -t server", - "test": "phpunit" + "start": "php -S localhost:8080 -t src" }, "config": { - "allow-plugins": { - "phpstan/extension-installer": true - } } } \ No newline at end of file diff --git a/standard-integration/server/php/composer.lock b/standard-integration/server/php/composer.lock index 351abe8e..39a01f7b 100644 --- a/standard-integration/server/php/composer.lock +++ b/standard-integration/server/php/composer.lock @@ -4,283 +4,188 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "215478eda9b5efd723cd51c11808902f", + "content-hash": "d4a57a266f3f33beef57b02efc8cfaac", "packages": [ { - "name": "fig/http-message-util", - "version": "1.1.5", + "name": "apimatic/core", + "version": "0.3.11", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message-util.git", - "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + "url": "https://github.com/apimatic/core-lib-php.git", + "reference": "2274f103f9f210664f546f504e4559d772a81fee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", - "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "url": "https://api.github.com/repos/apimatic/core-lib-php/zipball/2274f103f9f210664f546f504e4559d772a81fee", + "reference": "2274f103f9f210664f546f504e4559d772a81fee", "shasum": "" }, "require": { - "php": "^5.3 || ^7.0 || ^8.0" + "apimatic/core-interfaces": "~0.1.5", + "apimatic/jsonmapper": "^3.1.1", + "ext-curl": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "php": "^7.2 || ^8.0", + "php-jsonpointer/php-jsonpointer": "^3.0.2", + "psr/log": "^1.1.4 || ^2.0.0 || ^3.0.0" }, - "suggest": { - "psr/http-message": "The package containing the PSR-7 interfaces" + "require-dev": { + "phan/phan": "5.4.2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "squizlabs/php_codesniffer": "^3.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, "autoload": { "psr-4": { - "Fig\\Http\\Message\\": "src/" + "Core\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "description": "Core logic and the utilities for the Apimatic's PHP SDK", + "homepage": "https://github.com/apimatic/core-lib-php", "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" + "apimatic", + "core", + "corelib", + "php" ], "support": { - "issues": "https://github.com/php-fig/http-message-util/issues", - "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + "issues": "https://github.com/apimatic/core-lib-php/issues", + "source": "https://github.com/apimatic/core-lib-php/tree/0.3.11" }, - "time": "2020-11-24T22:02:12+00:00" + "time": "2024-07-08T11:50:08+00:00" }, { - "name": "graham-campbell/result-type", - "version": "v1.1.3", + "name": "apimatic/core-interfaces", + "version": "0.1.5", "source": { "type": "git", - "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + "url": "https://github.com/apimatic/core-interfaces-php.git", + "reference": "b4f1bffc8be79584836f70af33c65e097eec155c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "url": "https://api.github.com/repos/apimatic/core-interfaces-php/zipball/b4f1bffc8be79584836f70af33c65e097eec155c", + "reference": "b4f1bffc8be79584836f70af33c65e097eec155c", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { "psr-4": { - "GrahamCampbell\\ResultType\\": "src/" + "CoreInterfaces\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - } - ], - "description": "An Implementation Of The Result Type", + "description": "Definition of the behavior of apimatic/core, apimatic/unirest-php and Apimatic's PHP SDK", + "homepage": "https://github.com/apimatic/core-interfaces-php", "keywords": [ - "Graham Campbell", - "GrahamCampbell", - "Result Type", - "Result-Type", - "result" + "apimatic", + "core", + "corelib", + "interface", + "php", + "unirest" ], "support": { - "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + "issues": "https://github.com/apimatic/core-interfaces-php/issues", + "source": "https://github.com/apimatic/core-interfaces-php/tree/0.1.5" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", - "type": "tidelift" - } - ], - "time": "2024-07-20T21:45:45+00:00" + "time": "2024-05-09T06:32:07+00:00" }, { - "name": "guzzlehttp/guzzle", - "version": "7.9.2", + "name": "apimatic/jsonmapper", + "version": "3.1.4", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + "url": "https://github.com/apimatic/jsonmapper.git", + "reference": "407b455d2adda2efa51a44b99400389fbee0394e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", - "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "url": "https://api.github.com/repos/apimatic/jsonmapper/zipball/407b455d2adda2efa51a44b99400389fbee0394e", + "reference": "407b455d2adda2efa51a44b99400389fbee0394e", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", - "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0" - }, - "provide": { - "psr/http-client-implementation": "1.0" + "php": "^5.6 || ^7.0 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "ext-curl": "*", - "guzzle/client-integration-tests": "3.0.2", - "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.39 || ^9.6.20", - "psr/log": "^1.1 || ^2.0 || ^3.0" - }, - "suggest": { - "ext-curl": "Required for CURL handler support", - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" + "phpunit/phpunit": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "squizlabs/php_codesniffer": "^3.0.0" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { - "GuzzleHttp\\": "src/" + "apimatic\\jsonmapper\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "OSL-3.0" ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Jeremy Lindblom", - "email": "jeremeamia@gmail.com", - "homepage": "https://github.com/jeremeamia" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" + "name": "Christian Weiske", + "email": "christian.weiske@netresearch.de", + "homepage": "http://www.netresearch.de/", + "role": "Developer" }, { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" + "name": "Mehdi Jaffery", + "email": "mehdi.jaffery@apimatic.io", + "homepage": "http://apimatic.io/", + "role": "Developer" } ], - "description": "Guzzle is a PHP HTTP client library", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "psr-18", - "psr-7", - "rest", - "web service" - ], + "description": "Map nested JSON structures onto PHP classes", "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + "email": "mehdi.jaffery@apimatic.io", + "issues": "https://github.com/apimatic/jsonmapper/issues", + "source": "https://github.com/apimatic/jsonmapper/tree/3.1.4" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", - "type": "tidelift" - } - ], - "time": "2024-07-24T11:22:20+00:00" + "time": "2024-06-11T11:48:30+00:00" }, { - "name": "guzzlehttp/promises", - "version": "2.0.3", + "name": "apimatic/unirest-php", + "version": "4.0.5", "source": { "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" + "url": "https://github.com/apimatic/unirest-php.git", + "reference": "e16754010c16be5473289470f129d87a0f41b55e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", - "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "url": "https://api.github.com/repos/apimatic/unirest-php/zipball/e16754010c16be5473289470f129d87a0f41b55e", + "reference": "e16754010c16be5473289470f129d87a0f41b55e", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0" + "apimatic/core-interfaces": "^0.1.0", + "ext-curl": "*", + "ext-json": "*", + "php": "^7.2 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phan/phan": "5.4.2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "squizlabs/php_codesniffer": "^3.5" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, "autoload": { "psr-4": { - "GuzzleHttp\\Promise\\": "src/" + "Unirest\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -289,198 +194,107 @@ ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" + "name": "Mashape", + "email": "opensource@mashape.com", + "homepage": "https://www.mashape.com", + "role": "Developer" }, { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" + "name": "APIMATIC", + "email": "opensource@apimatic.io", + "homepage": "https://www.apimatic.io", + "role": "Developer" } ], - "description": "Guzzle promises library", + "description": "Unirest PHP", + "homepage": "https://github.com/apimatic/unirest-php", "keywords": [ - "promise" + "client", + "curl", + "http", + "https", + "rest" ], "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.3" + "email": "opensource@apimatic.io", + "issues": "https://github.com/apimatic/unirest-php/issues", + "source": "https://github.com/apimatic/unirest-php/tree/4.0.5" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", - "type": "tidelift" - } - ], - "time": "2024-07-18T10:29:17+00:00" + "time": "2023-04-25T14:19:45+00:00" }, { - "name": "guzzlehttp/psr7", - "version": "2.7.0", + "name": "paypal/paypal-server-sdk", + "version": "0.5.1", "source": { "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + "url": "https://github.com/paypal/PayPal-PHP-Server-SDK.git", + "reference": "09148245f72f9dc2f6c8363b6206eac5effefa77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "url": "https://api.github.com/repos/paypal/PayPal-PHP-Server-SDK/zipball/09148245f72f9dc2f6c8363b6206eac5effefa77", + "reference": "09148245f72f9dc2f6c8363b6206eac5effefa77", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" + "apimatic/core": "~0.3.11", + "apimatic/core-interfaces": "~0.1.5", + "apimatic/unirest-php": "^4.0.0", + "ext-json": "*", + "php": "^7.2 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + "phan/phan": "5.4.2", + "squizlabs/php_codesniffer": "^3.5" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, "autoload": { "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" + "PaypalServerSDKLib\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], + "description": "PayPal's SDK for interacting with the REST APIs", + "homepage": "https://github.com/paypal/PayPal-PHP-Server-SDK", "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.0" + "issues": "https://github.com/paypal/PayPal-PHP-Server-SDK/issues", + "source": "https://github.com/paypal/PayPal-PHP-Server-SDK/tree/0.5.1" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" - } - ], - "time": "2024-07-18T11:15:46+00:00" + "time": "2024-09-10T15:31:38+00:00" }, { - "name": "laravel/serializable-closure", - "version": "v1.3.3", + "name": "php-jsonpointer/php-jsonpointer", + "version": "v3.0.2", "source": { "type": "git", - "url": "https://github.com/laravel/serializable-closure.git", - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" + "url": "https://github.com/raphaelstolt/php-jsonpointer.git", + "reference": "4428f86c6f23846e9faa5a420c4ef14e485b3afb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", + "url": "https://api.github.com/repos/raphaelstolt/php-jsonpointer/zipball/4428f86c6f23846e9faa5a420c4ef14e485b3afb", + "reference": "4428f86c6f23846e9faa5a420c4ef14e485b3afb", "shasum": "" }, "require": { - "php": "^7.3|^8.0" + "php": ">=5.4" }, "require-dev": { - "nesbot/carbon": "^2.61", - "pestphp/pest": "^1.21.3", - "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11" + "friendsofphp/php-cs-fixer": "^1.11", + "phpunit/phpunit": "4.6.*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-4": { - "Laravel\\SerializableClosure\\": "src/" + "psr-0": { + "Rs\\Json": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -489,92 +303,50 @@ ], "authors": [ { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - }, - { - "name": "Nuno Maduro", - "email": "nuno@laravel.com" + "name": "Raphael Stolt", + "email": "raphael.stolt@gmail.com", + "homepage": "http://raphaelstolt.blogspot.com/" } ], - "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "description": "Implementation of JSON Pointer (http://tools.ietf.org/html/rfc6901)", + "homepage": "https://github.com/raphaelstolt/php-jsonpointer", "keywords": [ - "closure", - "laravel", - "serializable" + "json", + "json pointer", + "json traversal" ], "support": { - "issues": "https://github.com/laravel/serializable-closure/issues", - "source": "https://github.com/laravel/serializable-closure" + "issues": "https://github.com/raphaelstolt/php-jsonpointer/issues", + "source": "https://github.com/raphaelstolt/php-jsonpointer/tree/master" }, - "time": "2023-11-08T14:08:06+00:00" + "time": "2016-08-29T08:51:01+00:00" }, { - "name": "monolog/monolog", - "version": "2.9.3", + "name": "psr/log", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215" + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/a30bfe2e142720dfa990d0a7e573997f5d884215", - "reference": "a30bfe2e142720dfa990d0a7e573997f5d884215", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { - "php": ">=7.2", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" - }, - "provide": { - "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" - }, - "require-dev": { - "aws/aws-sdk-php": "^2.4.9 || ^3.0", - "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^7 || ^8", - "ext-json": "*", - "graylog2/gelf-php": "^1.4.2 || ^2@dev", - "guzzlehttp/guzzle": "^7.4", - "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", - "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpspec/prophecy": "^1.15", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.5.38 || ^9.6.19", - "predis/predis": "^1.1 || ^2.0", - "rollbar/rollbar": "^1.3 || ^2 || ^3", - "ruflin/elastica": "^7", - "swiftmailer/swiftmailer": "^5.3|^6.0", - "symfony/mailer": "^5.4 || ^6", - "symfony/mime": "^5.4 || ^6" - }, - "suggest": { - "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", - "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", - "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", - "ext-mbstring": "Allow to work properly with unicode symbols", - "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", - "ext-openssl": "Required to send log messages using SSL", - "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", - "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", - "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", - "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { - "Monolog\\": "src/Monolog" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -583,3894 +355,24 @@ ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "https://seld.be" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "https://github.com/Seldaek/monolog", + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ "log", - "logging", + "psr", "psr-3" ], "support": { - "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.9.3" - }, - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", - "type": "tidelift" - } - ], - "time": "2024-04-12T20:52:51+00:00" - }, - { - "name": "nikic/fast-route", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/FastRoute.git", - "reference": "181d480e08d9476e61381e04a71b34dc0432e812" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", - "reference": "181d480e08d9476e61381e04a71b34dc0432e812", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35|~5.7" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "FastRoute\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov", - "email": "nikic@php.net" - } - ], - "description": "Fast request router for PHP", - "keywords": [ - "router", - "routing" - ], - "support": { - "issues": "https://github.com/nikic/FastRoute/issues", - "source": "https://github.com/nikic/FastRoute/tree/master" - }, - "time": "2018-02-13T20:26:39+00:00" - }, - { - "name": "php-di/invoker", - "version": "2.3.4", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", - "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "psr/container": "^1.0|^2.0" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Invoker\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Generic and extensible callable invoker", - "homepage": "https://github.com/PHP-DI/Invoker", - "keywords": [ - "callable", - "dependency", - "dependency-injection", - "injection", - "invoke", - "invoker" - ], - "support": { - "issues": "https://github.com/PHP-DI/Invoker/issues", - "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - } - ], - "time": "2023-09-08T09:24:21+00:00" - }, - { - "name": "php-di/php-di", - "version": "6.4.0", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PHP-DI.git", - "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/ae0f1b3b03d8b29dff81747063cbfd6276246cc4", - "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4", - "shasum": "" - }, - "require": { - "laravel/serializable-closure": "^1.0", - "php": ">=7.4.0", - "php-di/invoker": "^2.0", - "php-di/phpdoc-reader": "^2.0.1", - "psr/container": "^1.0" - }, - "provide": { - "psr/container-implementation": "^1.0" - }, - "require-dev": { - "doctrine/annotations": "~1.10", - "friendsofphp/php-cs-fixer": "^2.4", - "mnapoli/phpunit-easymock": "^1.2", - "ocramius/proxy-manager": "^2.11.2", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^9.5" - }, - "suggest": { - "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", - "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "DI\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The dependency injection container for humans", - "homepage": "https://php-di.org/", - "keywords": [ - "PSR-11", - "container", - "container-interop", - "dependency injection", - "di", - "ioc", - "psr11" - ], - "support": { - "issues": "https://github.com/PHP-DI/PHP-DI/issues", - "source": "https://github.com/PHP-DI/PHP-DI/tree/6.4.0" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", - "type": "tidelift" - } - ], - "time": "2022-04-09T16:46:38+00:00" - }, - { - "name": "php-di/phpdoc-reader", - "version": "2.2.1", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PhpDocReader.git", - "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", - "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "require-dev": { - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^8.5|^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "PhpDocReader\\": "src/PhpDocReader" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", - "keywords": [ - "phpdoc", - "reflection" - ], - "support": { - "issues": "https://github.com/PHP-DI/PhpDocReader/issues", - "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" - }, - "time": "2020-10-12T12:39:22+00:00" - }, - { - "name": "phpoption/phpoption", - "version": "1.9.3", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - }, - "branch-alias": { - "dev-master": "1.9-dev" - } - }, - "autoload": { - "psr-4": { - "PhpOption\\": "src/PhpOption/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh" - }, - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - } - ], - "description": "Option Type for PHP", - "keywords": [ - "language", - "option", - "php", - "type" - ], - "support": { - "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", - "type": "tidelift" - } - ], - "time": "2024-07-20T21:41:07+00:00" - }, - { - "name": "psr/container", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" - }, - "time": "2021-11-05T16:50:12+00:00" - }, - { - "name": "psr/http-client", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", - "shasum": "" - }, - "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], - "support": { - "source": "https://github.com/php-fig/http-client" - }, - "time": "2023-09-23T14:17:50+00:00" - }, - { - "name": "psr/http-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory" - }, - "time": "2024-04-15T12:06:14+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "psr/http-server-handler", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-server-handler.git", - "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", - "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", - "shasum": "" - }, - "require": { - "php": ">=7.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Server\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP server-side request handler", - "keywords": [ - "handler", - "http", - "http-interop", - "psr", - "psr-15", - "psr-7", - "request", - "response", - "server" - ], - "support": { - "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" - }, - "time": "2023-04-10T20:06:20+00:00" - }, - { - "name": "psr/http-server-middleware", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-server-middleware.git", - "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", - "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", - "shasum": "" - }, - "require": { - "php": ">=7.0", - "psr/http-message": "^1.0 || ^2.0", - "psr/http-server-handler": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Server\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP server-side middleware", - "keywords": [ - "http", - "http-interop", - "middleware", - "psr", - "psr-15", - "psr-7", - "request", - "response" - ], - "support": { - "issues": "https://github.com/php-fig/http-server-middleware/issues", - "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" - }, - "time": "2023-04-11T06:14:47+00:00" - }, - { - "name": "psr/log", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" - }, - "time": "2021-07-14T16:46:02+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "slim/http", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim-Http.git", - "reference": "a8def7b8e9eabd0cdc21654ad4a82606942e066a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim-Http/zipball/a8def7b8e9eabd0cdc21654ad4a82606942e066a", - "reference": "a8def7b8e9eabd0cdc21654ad4a82606942e066a", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-simplexml": "*", - "php": "^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0" - }, - "require-dev": { - "adriansuter/php-autoload-override": "^1.4", - "doctrine/instantiator": "^1.3.1", - "laminas/laminas-diactoros": "^3.1.0", - "nyholm/psr7": "^1.8.1", - "php-http/psr7-integration-tests": "^1.3.0", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.6", - "squizlabs/php_codesniffer": "^3.9" - }, - "type": "library", - "autoload": { - "psr-4": { - "Slim\\Http\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "http://joshlockhart.com" - }, - { - "name": "Andrew Smith", - "email": "a.smith@silentworks.co.uk", - "homepage": "http://silentworks.co.uk" - }, - { - "name": "Rob Allen", - "email": "rob@akrabat.com", - "homepage": "http://akrabat.com" - }, - { - "name": "Pierre Berube", - "email": "pierre@lgse.com", - "homepage": "http://www.lgse.com" - } - ], - "description": "Slim PSR-7 Object Decorators", - "homepage": "http://slimframework.com", - "keywords": [ - "http", - "psr-7", - "psr7" - ], - "support": { - "issues": "https://github.com/slimphp/Slim-Http/issues", - "source": "https://github.com/slimphp/Slim-Http/tree/1.4.0" - }, - "time": "2024-06-24T18:27:41+00:00" - }, - { - "name": "slim/middleware", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim-Middleware.git", - "reference": "1190251a89a3044eda9d16dcb456dc92dba2d0c8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim-Middleware/zipball/1190251a89a3044eda9d16dcb456dc92dba2d0c8", - "reference": "1190251a89a3044eda9d16dcb456dc92dba2d0c8", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "slim/slim": ">=2.3.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Slim": "./src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "info@joshlockhart.com", - "homepage": "http://www.joshlockhart.com/" - } - ], - "description": "Slim Framework middleware", - "homepage": "http://github.com/codeguy/Slim", - "keywords": [ - "middleware", - "slim" - ], - "support": { - "issues": "https://github.com/slimphp/Slim-Middleware/issues", - "source": "https://github.com/slimphp/Slim-Middleware/tree/1.0.0" - }, - "abandoned": true, - "time": "2013-09-18T18:13:40+00:00" - }, - { - "name": "slim/psr7", - "version": "1.7.0", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim-Psr7.git", - "reference": "753e9646def5ff4db1a06e5cf4ef539bfd30f467" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/753e9646def5ff4db1a06e5cf4ef539bfd30f467", - "reference": "753e9646def5ff4db1a06e5cf4ef539bfd30f467", - "shasum": "" - }, - "require": { - "fig/http-message-util": "^1.1.5", - "php": "^8.0", - "psr/http-factory": "^1.1", - "psr/http-message": "^1.0 || ^2.0", - "ralouphie/getallheaders": "^3.0", - "symfony/polyfill-php80": "^1.29" - }, - "provide": { - "psr/http-factory-implementation": "^1.0", - "psr/http-message-implementation": "^1.0 || ^2.0" - }, - "require-dev": { - "adriansuter/php-autoload-override": "^1.4", - "ext-json": "*", - "http-interop/http-factory-tests": "^1.1.0", - "php-http/psr7-integration-tests": "1.3.0", - "phpspec/prophecy": "^1.19", - "phpspec/prophecy-phpunit": "^2.2", - "phpstan/phpstan": "^1.11", - "phpunit/phpunit": "^9.6", - "squizlabs/php_codesniffer": "^3.10" - }, - "type": "library", - "autoload": { - "psr-4": { - "Slim\\Psr7\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "http://joshlockhart.com" - }, - { - "name": "Andrew Smith", - "email": "a.smith@silentworks.co.uk", - "homepage": "http://silentworks.co.uk" - }, - { - "name": "Rob Allen", - "email": "rob@akrabat.com", - "homepage": "http://akrabat.com" - }, - { - "name": "Pierre Berube", - "email": "pierre@lgse.com", - "homepage": "http://www.lgse.com" - } - ], - "description": "Strict PSR-7 implementation", - "homepage": "https://www.slimframework.com", - "keywords": [ - "http", - "psr-7", - "psr7" - ], - "support": { - "issues": "https://github.com/slimphp/Slim-Psr7/issues", - "source": "https://github.com/slimphp/Slim-Psr7/tree/1.7.0" - }, - "time": "2024-06-08T14:48:17+00:00" - }, - { - "name": "slim/slim", - "version": "4.14.0", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim.git", - "reference": "5943393b88716eb9e82c4161caa956af63423913" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/5943393b88716eb9e82c4161caa956af63423913", - "reference": "5943393b88716eb9e82c4161caa956af63423913", - "shasum": "" - }, - "require": { - "ext-json": "*", - "nikic/fast-route": "^1.3", - "php": "^7.4 || ^8.0", - "psr/container": "^1.0 || ^2.0", - "psr/http-factory": "^1.1", - "psr/http-message": "^1.1 || ^2.0", - "psr/http-server-handler": "^1.0", - "psr/http-server-middleware": "^1.0", - "psr/log": "^1.1 || ^2.0 || ^3.0" - }, - "require-dev": { - "adriansuter/php-autoload-override": "^1.4", - "ext-simplexml": "*", - "guzzlehttp/psr7": "^2.6", - "httpsoft/http-message": "^1.1", - "httpsoft/http-server-request": "^1.1", - "laminas/laminas-diactoros": "^2.17 || ^3", - "nyholm/psr7": "^1.8", - "nyholm/psr7-server": "^1.1", - "phpspec/prophecy": "^1.19", - "phpspec/prophecy-phpunit": "^2.1", - "phpstan/phpstan": "^1.11", - "phpunit/phpunit": "^9.6", - "slim/http": "^1.3", - "slim/psr7": "^1.6", - "squizlabs/php_codesniffer": "^3.10", - "vimeo/psalm": "^5.24" - }, - "suggest": { - "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", - "ext-xml": "Needed to support XML format in BodyParsingMiddleware", - "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", - "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." - }, - "type": "library", - "autoload": { - "psr-4": { - "Slim\\": "Slim" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "https://joshlockhart.com" - }, - { - "name": "Andrew Smith", - "email": "a.smith@silentworks.co.uk", - "homepage": "http://silentworks.co.uk" - }, - { - "name": "Rob Allen", - "email": "rob@akrabat.com", - "homepage": "http://akrabat.com" - }, - { - "name": "Pierre Berube", - "email": "pierre@lgse.com", - "homepage": "http://www.lgse.com" - }, - { - "name": "Gabriel Manricks", - "email": "gmanricks@me.com", - "homepage": "http://gabrielmanricks.com" - } - ], - "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", - "homepage": "https://www.slimframework.com", - "keywords": [ - "api", - "framework", - "micro", - "router" - ], - "support": { - "docs": "https://www.slimframework.com/docs/v4/", - "forum": "https://discourse.slimframework.com/", - "irc": "irc://irc.freenode.net:6667/slimphp", - "issues": "https://github.com/slimphp/Slim/issues", - "rss": "https://www.slimframework.com/blog/feed.rss", - "slack": "https://slimphp.slack.com/", - "source": "https://github.com/slimphp/Slim", - "wiki": "https://github.com/slimphp/Slim/wiki" - }, - "funding": [ - { - "url": "https://opencollective.com/slimphp", - "type": "open_collective" - }, - { - "url": "https://tidelift.com/funding/github/packagist/slim/slim", - "type": "tidelift" - } - ], - "time": "2024-06-13T08:54:48+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.5.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-04-18T09:32:20+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T15:07:36+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-06-19T12:30:46+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T15:07:36+00:00" - }, - { - "name": "vlucas/phpdotenv", - "version": "v5.6.1", - "source": { - "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", - "shasum": "" - }, - "require": { - "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", - "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "ext-filter": "*", - "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" - }, - "suggest": { - "ext-filter": "Required to use the boolean validator." - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - }, - "branch-alias": { - "dev-master": "5.6-dev" - } - }, - "autoload": { - "psr-4": { - "Dotenv\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "https://github.com/vlucas" - } - ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", - "keywords": [ - "dotenv", - "env", - "environment" - ], - "support": { - "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", - "type": "tidelift" - } - ], - "time": "2024-07-20T21:52:34+00:00" - } - ], - "packages-dev": [ - { - "name": "doctrine/deprecations", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.3" - }, - "time": "2024-01-30T19:34:25+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.9.4", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:23:10+00:00" - }, - { - "name": "jangregor/phpstan-prophecy", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/Jan0707/phpstan-prophecy.git", - "reference": "5ee56c7db1d58f0578c82a35e3c1befe840e85a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jan0707/phpstan-prophecy/zipball/5ee56c7db1d58f0578c82a35e3c1befe840e85a9", - "reference": "5ee56c7db1d58f0578c82a35e3c1befe840e85a9", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0", - "phpstan/phpstan": "^1.0.0" - }, - "conflict": { - "phpspec/prophecy": "<1.7.0 || >=2.0.0", - "phpunit/phpunit": "<6.0.0 || >=12.0.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.1.1", - "ergebnis/license": "^1.0.0", - "ergebnis/php-cs-fixer-config": "~2.2.0", - "phpspec/prophecy": "^1.7.0", - "phpunit/phpunit": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - } - }, - "autoload": { - "psr-4": { - "JanGregor\\Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Gregor Emge-Triebel", - "email": "jan@jangregor.me" - } - ], - "description": "Provides a phpstan/phpstan extension for phpspec/prophecy", - "support": { - "issues": "https://github.com/Jan0707/phpstan-prophecy/issues", - "source": "https://github.com/Jan0707/phpstan-prophecy/tree/1.0.2" - }, - "time": "2024-04-03T08:15:54+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.12.0", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2024-06-12T14:39:25+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v5.1.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "php": ">=7.4" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" - }, - "time": "2024-07-01T20:03:41+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "54750ef60c58e43759730615a392c31c80e23176" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", - "reference": "54750ef60c58e43759730615a392c31c80e23176", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:33:53+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.4.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", - "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.1", - "ext-filter": "*", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.5", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-webmozart-assert": "^1.2", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" - }, - "time": "2024-05-21T05:55:05+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.8.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "153ae662783729388a584b4361f2545e4d841e3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", - "reference": "153ae662783729388a584b4361f2545e4d841e3c", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.3 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.13" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" - }, - "time": "2024-02-23T11:10:43+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.19.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/67a759e7d8746d501c41536ba40cd9c0a07d6a87", - "reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2 || ^2.0", - "php": "^7.2 || 8.0.* || 8.1.* || 8.2.* || 8.3.*", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0 || ^6.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0 || ^7.0", - "phpstan/phpstan": "^1.9", - "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "dev", - "fake", - "mock", - "spy", - "stub" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.19.0" - }, - "time": "2024-02-29T11:52:51+00:00" - }, - { - "name": "phpspec/prophecy-phpunit", - "version": "v2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy-phpunit.git", - "reference": "16e1247e139434bce0bac09848bc5c8d882940fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/16e1247e139434bce0bac09848bc5c8d882940fc", - "reference": "16e1247e139434bce0bac09848bc5c8d882940fc", - "shasum": "" - }, - "require": { - "php": "^7.3 || ^8", - "phpspec/prophecy": "^1.18", - "phpunit/phpunit": "^9.1 || ^10.1 || ^11.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\PhpUnit\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christophe Coevoet", - "email": "stof@notk.org" - } - ], - "description": "Integrating the Prophecy mocking library in PHPUnit test cases", - "homepage": "http://phpspec.net", - "keywords": [ - "phpunit", - "prophecy" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy-phpunit/issues", - "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.2.0" - }, - "time": "2024-03-01T08:33:58+00:00" - }, - { - "name": "phpstan/extension-installer", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/phpstan/extension-installer.git", - "reference": "f6b87faf9fc7978eab2f7919a8760bc9f58f9203" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f6b87faf9fc7978eab2f7919a8760bc9f58f9203", - "reference": "f6b87faf9fc7978eab2f7919a8760bc9f58f9203", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2.0", - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.0" - }, - "require-dev": { - "composer/composer": "^2.0", - "php-parallel-lint/php-parallel-lint": "^1.2.0", - "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPStan\\ExtensionInstaller\\Plugin" - }, - "autoload": { - "psr-4": { - "PHPStan\\ExtensionInstaller\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Composer plugin for automatic installation of PHPStan extensions", - "support": { - "issues": "https://github.com/phpstan/extension-installer/issues", - "source": "https://github.com/phpstan/extension-installer/tree/1.4.1" - }, - "time": "2024-06-10T08:20:49+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "1.29.1", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" - }, - "time": "2024-05-31T08:52:43+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "1.11.8", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", - "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2024-07-24T07:01:22+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "9.2.31", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:37:42+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "3.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-12-02T12:48:52+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "5.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:16:10+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "9.6.20", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "49d7820565836236411f5dc002d16dd689cde42f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", - "reference": "49d7820565836236411f5dc002d16dd689cde42f", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.5.0 || ^2", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", - "phar-io/manifest": "^2.0.4", - "phar-io/version": "^3.2.1", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.31", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.4", - "phpunit/php-timer": "^5.0.3", - "sebastian/cli-parser": "^1.0.2", - "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.6", - "sebastian/environment": "^5.1.5", - "sebastian/exporter": "^4.0.6", - "sebastian/global-state": "^5.0.7", - "sebastian/object-enumerator": "^4.0.4", - "sebastian/resource-operations": "^3.0.4", - "sebastian/type": "^3.2.1", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.6-dev" - } - }, - "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2024-07-10T11:45:39+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:27:43+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" - }, - { - "name": "sebastian/comparator", - "version": "4.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T12:41:17+00:00" - }, - { - "name": "sebastian/complexity", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:19:30+00:00" - }, - { - "name": "sebastian/diff", - "version": "4.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:30:58+00:00" - }, - { - "name": "sebastian/environment", - "version": "5.1.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:03:51+00:00" - }, - { - "name": "sebastian/exporter", - "version": "4.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:33:00+00:00" - }, - { - "name": "sebastian/global-state", - "version": "5.0.7", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:35:11+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:20:34+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:12:34+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:14:26+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:07:39+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-14T16:00:52+00:00" - }, - { - "name": "sebastian/type", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", - "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:13:03+00:00" - }, - { - "name": "sebastian/version", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.10.2", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/86e5f5dd9a840c46810ebe5ff1885581c42a3017", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - } - ], - "time": "2024-07-21T23:26:44+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:36:25+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2022-06-03T18:03:27+00:00" + "time": "2024-09-11T13:17:53+00:00" } ], + "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": [], diff --git a/standard-integration/server/php/server/index.php b/standard-integration/server/php/server/index.php deleted file mode 100644 index e99a2841..00000000 --- a/standard-integration/server/php/server/index.php +++ /dev/null @@ -1,145 +0,0 @@ - false]); - $response = $client->post("$base/v1/oauth2/token", [ - 'form_params' => [ - 'grant_type' => 'client_credentials' - ], - 'headers' => [ - 'Authorization' => "Basic $auth" - ] - ]); - - $data = json_decode($response->getBody(), true); - return $data['access_token']; -} - -/** - * Create an order to start the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create - */ -function createOrder($cart) -{ - global $base; - - $accessToken = generateAccessToken(); - - // Disabling certificate validation for local development - $client = new Client(['verify' => false]); - $payload = [ - 'intent' => 'CAPTURE', - 'purchase_units' => [ - [ - 'amount' => [ - 'currency_code' => 'USD', - 'value' => '100.00' - ] - ] - ], - ]; - - $response = $client->post("$base/v2/checkout/orders", [ - 'headers' => [ - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer $accessToken" - ], - 'json' => $payload - ]); - - return handleResponse($response); -} - -/** - * Capture payment for the created order to complete the transaction. - * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture - */ -function captureOrder($orderID) -{ - global $base; - - $accessToken = generateAccessToken(); - - // Disabling certificate validation for local development - $client = new Client(['verify' => false]); - $response = $client->post("$base/v2/checkout/orders/$orderID/capture", [ - 'headers' => [ - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer $accessToken" - ] - ]); - - return handleResponse($response); -} - -function handleResponse($response) -{ - $jsonResponse = json_decode($response->getBody(), true); - return [ - 'jsonResponse' => $jsonResponse, - 'httpStatusCode' => $response->getStatusCode() - ]; -} - -$endpoint = $_SERVER['REQUEST_URI']; -if ($endpoint === '/') { - try { - $response = [ - "message" => "Server is running" - ]; - header('Content-Type: application/json'); - echo json_encode($response); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - http_response_code(500); - } -} - -if ($endpoint === '/api/orders') { - $data = json_decode(file_get_contents('php://input'), true); - $cart = $data['cart']; - header('Content-Type: application/json'); - try { - $orderResponse = createOrder($cart); - echo json_encode($orderResponse['jsonResponse']); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - http_response_code(500); - } -} - - -if (str_ends_with($endpoint, '/capture')) { - $urlSegments = explode('/', $endpoint); - end($urlSegments); // Will set the pointer to the end of array - $orderID = prev($urlSegments); - header('Content-Type: application/json'); - try { - $captureResponse = captureOrder($orderID); - echo json_encode($captureResponse['jsonResponse']); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - http_response_code(500); - } -} \ No newline at end of file diff --git a/standard-integration/server/php/server/.htaccess b/standard-integration/server/php/src/.htaccess similarity index 100% rename from standard-integration/server/php/server/.htaccess rename to standard-integration/server/php/src/.htaccess diff --git a/standard-integration/server/php/src/index.php b/standard-integration/server/php/src/index.php new file mode 100644 index 00000000..8f000133 --- /dev/null +++ b/standard-integration/server/php/src/index.php @@ -0,0 +1,118 @@ +clientCredentialsAuthCredentials( + ClientCredentialsAuthCredentialsBuilder::init( + $PAYPAL_CLIENT_ID, + $PAYPAL_CLIENT_SECRET + ) + ) + ->environment(Environment::SANDBOX) + ->build(); + +/** + * Create an order to start the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create + */ +function createOrder($cart) +{ + global $client; + + $orderBody = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '100.00' + )->build() + )->build() + ] + )->build() + ]; + + $apiResponse = $client->getOrdersController()->ordersCreate($orderBody); + + return handleResponse($apiResponse); +} + +/** + * Capture payment for the created order to complete the transaction. + * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture + */ +function captureOrder($orderID) +{ + global $client; + + $captureBody = [ + 'id' => $orderID + ]; + + $apiResponse = $client->getOrdersController()->ordersCapture($captureBody); + + return handleResponse($apiResponse); +} + +function handleResponse($response) +{ + return [ + 'jsonResponse' => $response->getResult(), + 'httpStatusCode' => $response->getStatusCode() + ]; +} + +$endpoint = $_SERVER['REQUEST_URI']; +if ($endpoint === '/') { + try { + $response = [ + "message" => "Server is running" + ]; + header('Content-Type: application/json'); + echo json_encode($response); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + +if ($endpoint === '/api/orders') { + $data = json_decode(file_get_contents('php://input'), true); + $cart = $data['cart']; + header('Content-Type: application/json'); + try { + $orderResponse = createOrder($cart); + echo json_encode($orderResponse['jsonResponse']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + + +if (str_ends_with($endpoint, '/capture')) { + $urlSegments = explode('/', $endpoint); + end($urlSegments); // Will set the pointer to the end of array + $orderID = prev($urlSegments); + header('Content-Type: application/json'); + try { + $captureResponse = captureOrder($orderID); + echo json_encode($captureResponse['jsonResponse']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + http_response_code(500); + } +} + From faf8b4d59e66b30c7bca0c289202a460c62e012e Mon Sep 17 00:00:00 2001 From: rekhaabaidipati <130034318+rekhaabaidipati@users.noreply.github.com> Date: Tue, 15 Oct 2024 07:37:11 -0700 Subject: [PATCH 32/34] Fix client worrkspace foldere clone (#162) Co-authored-by: Rekhaa --- .devcontainer/post-commands.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/post-commands.sh b/.devcontainer/post-commands.sh index ffdf0fc3..505bdf50 100755 --- a/.devcontainer/post-commands.sh +++ b/.devcontainer/post-commands.sh @@ -16,7 +16,7 @@ if [ -z "$VISIBLE_FOLDER_VERSION" ]; then CLIENT_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/client/${VISIBLE_FOLDER_CLIENT}" else SERVER_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/${VISIBLE_FOLDER_VERSION}/server" - CLIENT_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/${VISIBLE_FOLDER_VERSION}/client/${VISIBLE_FOLDER_CLIENT}/client" + CLIENT_DIR="${WORKSPACE_DIR}/${VISIBLE_FOLDER_PROJECT}/${VISIBLE_FOLDER_VERSION}/client/${VISIBLE_FOLDER_CLIENT}" fi # Backend setup functions From 2cdd5d346f9047c269023728ea1d7a1713ea6cb3 Mon Sep 17 00:00:00 2001 From: sourav sarkar Date: Wed, 16 Oct 2024 20:01:54 +0530 Subject: [PATCH 33/34] feat: migrate to dotnet server sdk (#163) Co-authored-by: Sourav Sarkar --- .../dotnet/PayPalAdvancedIntegration.csproj | 1 + .../v2/server/dotnet/Server.cs | 159 +++++++---------- .../dotnet/PayPalStandardIntegration.csproj | 1 + standard-integration/server/dotnet/Server.cs | 161 +++++++----------- 4 files changed, 129 insertions(+), 193 deletions(-) diff --git a/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj b/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj index 1c9d4604..838e3aa4 100644 --- a/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj +++ b/advanced-integration/v2/server/dotnet/PayPalAdvancedIntegration.csproj @@ -7,5 +7,6 @@ + diff --git a/advanced-integration/v2/server/dotnet/Server.cs b/advanced-integration/v2/server/dotnet/Server.cs index dcd334fb..5132e726 100644 --- a/advanced-integration/v2/server/dotnet/Server.cs +++ b/advanced-integration/v2/server/dotnet/Server.cs @@ -1,16 +1,18 @@ using System; -using System.IO; -using System.Net.Http; -using System.Text; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; +using Microsoft.Extensions.Logging; +using PaypalServerSDK.Standard; +using PaypalServerSDK.Standard.Authentication; +using PaypalServerSDK.Standard.Controllers; +using PaypalServerSDK.Standard.Http.Response; +using PaypalServerSDK.Standard.Models; +using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration; namespace PayPalAdvancedIntegration; @@ -56,22 +58,42 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) [ApiController] public class CheckoutController : Controller { - private readonly IHttpClientFactory _httpClientFactory; + private readonly OrdersController _ordersController; + private readonly PaymentsController _paymentsController; + private IConfiguration _configuration { get; } private string _paypalClientId { - get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); } + get { return System.Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); } } private string _paypalClientSecret { - get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); } + get { return System.Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); } } - private readonly string _base = "https://api-m.sandbox.paypal.com"; - public CheckoutController(IHttpClientFactory httpClientFactory, IConfiguration configuration) + private readonly ILogger _logger; + + public CheckoutController(IConfiguration configuration, ILogger logger) { - _httpClientFactory = httpClientFactory; _configuration = configuration; + _logger = logger; + + // Initialize the PayPal SDK client + PaypalServerSDKClient client = new PaypalServerSDKClient.Builder() + .Environment(PaypalServerSDK.Standard.Environment.Sandbox) + .ClientCredentialsAuth( + new ClientCredentialsAuthModel.Builder(_paypalClientId, _paypalClientSecret).Build() + ) + .LoggingConfig(config => + config + .LogLevel(LogLevel.Information) + .RequestConfig(reqConfig => reqConfig.Body(true)) + .ResponseConfig(respConfig => respConfig.Headers(true)) + ) + .Build(); + + _ordersController = client.OrdersController; + _paymentsController = client.PaymentsController; } [HttpPost("api/orders")] @@ -80,7 +102,7 @@ public async Task CreateOrder([FromBody] dynamic cart) try { var result = await _CreateOrder(cart); - return StatusCode((int)result.httpStatusCode, result.jsonResponse); + return StatusCode((int)result.StatusCode, result.Data); } catch (Exception ex) { @@ -89,13 +111,37 @@ public async Task CreateOrder([FromBody] dynamic cart) } } + private async Task _CreateOrder(dynamic cart) + { + CheckoutPaymentIntent intent = (CheckoutPaymentIntent) + Enum.Parse(typeof(CheckoutPaymentIntent), "CAPTURE", true); + + OrdersCreateInput ordersCreateInput = new OrdersCreateInput + { + Body = new OrderRequest + { + Intent = intent, + PurchaseUnits = new List + { + new PurchaseUnitRequest + { + Amount = new AmountWithBreakdown { CurrencyCode = "USD", MValue = "100", }, + }, + }, + }, + }; + + ApiResponse result = await _ordersController.OrdersCreateAsync(ordersCreateInput); + return result; + } + [HttpPost("api/orders/{orderID}/capture")] public async Task CaptureOrder(string orderID) { try { var result = await _CaptureOrder(orderID); - return StatusCode((int)result.httpStatusCode, result.jsonResponse); + return StatusCode((int)result.StatusCode, result.Data); } catch (Exception ex) { @@ -104,91 +150,12 @@ public async Task CaptureOrder(string orderID) } } - private async Task GenerateAccessToken() - { - if (string.IsNullOrEmpty(_paypalClientId) || string.IsNullOrEmpty(_paypalClientSecret)) - { - throw new Exception("MISSING_API_CREDENTIALS"); - } - - var auth = Convert.ToBase64String( - Encoding.UTF8.GetBytes($"{_paypalClientId}:{_paypalClientSecret}") - ); - var client = _httpClientFactory.CreateClient(); - var request = new HttpRequestMessage(HttpMethod.Post, $"{_base}/v1/oauth2/token") - { - Content = new StringContent( - "grant_type=client_credentials", - Encoding.UTF8, - "application/x-www-form-urlencoded" - ) - }; - request.Headers.Add("Authorization", $"Basic {auth}"); - - var response = await client.SendAsync(request); - var data = JsonConvert.DeserializeObject( - await response.Content.ReadAsStringAsync() - ); - return data.access_token; - } - - private async Task _CreateOrder(dynamic cart) - { - var accessToken = await GenerateAccessToken(); - var url = $"{_base}/v2/checkout/orders"; - var payload = new - { - intent = "CAPTURE", - purchase_units = new[] - { - new { amount = new { currency_code = "USD", value = "100.00" } } - } - }; - - var client = _httpClientFactory.CreateClient(); - var request = new HttpRequestMessage(HttpMethod.Post, url) - { - Content = new StringContent( - JsonConvert.SerializeObject(payload), - Encoding.UTF8, - "application/json" - ) - }; - request.Headers.Add("Authorization", $"Bearer {accessToken}"); - - var response = await client.SendAsync(request); - return await HandleResponse(response); - } - private async Task _CaptureOrder(string orderID) { - var accessToken = await GenerateAccessToken(); - var url = $"{_base}/v2/checkout/orders/{orderID}/capture"; - - var client = _httpClientFactory.CreateClient(); - var request = new HttpRequestMessage(HttpMethod.Post, url) - { - Content = new StringContent("", Encoding.UTF8, "application/json") - }; - request.Headers.Add("Authorization", $"Bearer {accessToken}"); + OrdersCaptureInput ordersCaptureInput = new OrdersCaptureInput { Id = orderID, }; - var response = await client.SendAsync(request); - return await HandleResponse(response); - } + ApiResponse result = await _ordersController.OrdersCaptureAsync(ordersCaptureInput); - private async Task HandleResponse(HttpResponseMessage response) - { - try - { - var jsonResponse = JsonConvert.DeserializeObject( - await response.Content.ReadAsStringAsync() - ); - return new { jsonResponse, httpStatusCode = response.StatusCode }; - } - catch (Exception) - { - var errorMessage = await response.Content.ReadAsStringAsync(); - throw new Exception(errorMessage); - } + return result; } } diff --git a/standard-integration/server/dotnet/PayPalStandardIntegration.csproj b/standard-integration/server/dotnet/PayPalStandardIntegration.csproj index 6b5a7d0e..a506c6d8 100644 --- a/standard-integration/server/dotnet/PayPalStandardIntegration.csproj +++ b/standard-integration/server/dotnet/PayPalStandardIntegration.csproj @@ -7,5 +7,6 @@ + diff --git a/standard-integration/server/dotnet/Server.cs b/standard-integration/server/dotnet/Server.cs index 9be4f5e5..5132e726 100644 --- a/standard-integration/server/dotnet/Server.cs +++ b/standard-integration/server/dotnet/Server.cs @@ -1,18 +1,20 @@ using System; -using System.IO; -using System.Net.Http; -using System.Text; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; +using Microsoft.Extensions.Logging; +using PaypalServerSDK.Standard; +using PaypalServerSDK.Standard.Authentication; +using PaypalServerSDK.Standard.Controllers; +using PaypalServerSDK.Standard.Http.Response; +using PaypalServerSDK.Standard.Models; +using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration; -namespace PayPalStandardIntegration; +namespace PayPalAdvancedIntegration; public class Program { @@ -56,22 +58,42 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) [ApiController] public class CheckoutController : Controller { - private readonly IHttpClientFactory _httpClientFactory; + private readonly OrdersController _ordersController; + private readonly PaymentsController _paymentsController; + private IConfiguration _configuration { get; } private string _paypalClientId { - get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); } + get { return System.Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID"); } } private string _paypalClientSecret { - get { return Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); } + get { return System.Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET"); } } - private readonly string _base = "https://api-m.sandbox.paypal.com"; - public CheckoutController(IHttpClientFactory httpClientFactory, IConfiguration configuration) + private readonly ILogger _logger; + + public CheckoutController(IConfiguration configuration, ILogger logger) { - _httpClientFactory = httpClientFactory; _configuration = configuration; + _logger = logger; + + // Initialize the PayPal SDK client + PaypalServerSDKClient client = new PaypalServerSDKClient.Builder() + .Environment(PaypalServerSDK.Standard.Environment.Sandbox) + .ClientCredentialsAuth( + new ClientCredentialsAuthModel.Builder(_paypalClientId, _paypalClientSecret).Build() + ) + .LoggingConfig(config => + config + .LogLevel(LogLevel.Information) + .RequestConfig(reqConfig => reqConfig.Body(true)) + .ResponseConfig(respConfig => respConfig.Headers(true)) + ) + .Build(); + + _ordersController = client.OrdersController; + _paymentsController = client.PaymentsController; } [HttpPost("api/orders")] @@ -80,7 +102,7 @@ public async Task CreateOrder([FromBody] dynamic cart) try { var result = await _CreateOrder(cart); - return StatusCode((int)result.httpStatusCode, result.jsonResponse); + return StatusCode((int)result.StatusCode, result.Data); } catch (Exception ex) { @@ -89,13 +111,37 @@ public async Task CreateOrder([FromBody] dynamic cart) } } + private async Task _CreateOrder(dynamic cart) + { + CheckoutPaymentIntent intent = (CheckoutPaymentIntent) + Enum.Parse(typeof(CheckoutPaymentIntent), "CAPTURE", true); + + OrdersCreateInput ordersCreateInput = new OrdersCreateInput + { + Body = new OrderRequest + { + Intent = intent, + PurchaseUnits = new List + { + new PurchaseUnitRequest + { + Amount = new AmountWithBreakdown { CurrencyCode = "USD", MValue = "100", }, + }, + }, + }, + }; + + ApiResponse result = await _ordersController.OrdersCreateAsync(ordersCreateInput); + return result; + } + [HttpPost("api/orders/{orderID}/capture")] public async Task CaptureOrder(string orderID) { try { var result = await _CaptureOrder(orderID); - return StatusCode((int)result.httpStatusCode, result.jsonResponse); + return StatusCode((int)result.StatusCode, result.Data); } catch (Exception ex) { @@ -104,91 +150,12 @@ public async Task CaptureOrder(string orderID) } } - private async Task GenerateAccessToken() - { - if (string.IsNullOrEmpty(_paypalClientId) || string.IsNullOrEmpty(_paypalClientSecret)) - { - throw new Exception("MISSING_API_CREDENTIALS"); - } - - var auth = Convert.ToBase64String( - Encoding.UTF8.GetBytes($"{_paypalClientId}:{_paypalClientSecret}") - ); - var client = _httpClientFactory.CreateClient(); - var request = new HttpRequestMessage(HttpMethod.Post, $"{_base}/v1/oauth2/token") - { - Content = new StringContent( - "grant_type=client_credentials", - Encoding.UTF8, - "application/x-www-form-urlencoded" - ) - }; - request.Headers.Add("Authorization", $"Basic {auth}"); - - var response = await client.SendAsync(request); - var data = JsonConvert.DeserializeObject( - await response.Content.ReadAsStringAsync() - ); - return data.access_token; - } - - private async Task _CreateOrder(dynamic cart) - { - var accessToken = await GenerateAccessToken(); - var url = $"{_base}/v2/checkout/orders"; - var payload = new - { - intent = "CAPTURE", - purchase_units = new[] - { - new { amount = new { currency_code = "USD", value = "100.00" } } - } - }; - - var client = _httpClientFactory.CreateClient(); - var request = new HttpRequestMessage(HttpMethod.Post, url) - { - Content = new StringContent( - JsonConvert.SerializeObject(payload), - Encoding.UTF8, - "application/json" - ) - }; - request.Headers.Add("Authorization", $"Bearer {accessToken}"); - - var response = await client.SendAsync(request); - return await HandleResponse(response); - } - private async Task _CaptureOrder(string orderID) { - var accessToken = await GenerateAccessToken(); - var url = $"{_base}/v2/checkout/orders/{orderID}/capture"; - - var client = _httpClientFactory.CreateClient(); - var request = new HttpRequestMessage(HttpMethod.Post, url) - { - Content = new StringContent("", Encoding.UTF8, "application/json") - }; - request.Headers.Add("Authorization", $"Bearer {accessToken}"); + OrdersCaptureInput ordersCaptureInput = new OrdersCaptureInput { Id = orderID, }; - var response = await client.SendAsync(request); - return await HandleResponse(response); - } + ApiResponse result = await _ordersController.OrdersCaptureAsync(ordersCaptureInput); - private async Task HandleResponse(HttpResponseMessage response) - { - try - { - var jsonResponse = JsonConvert.DeserializeObject( - await response.Content.ReadAsStringAsync() - ); - return new { jsonResponse, httpStatusCode = response.StatusCode }; - } - catch (Exception) - { - var errorMessage = await response.Content.ReadAsStringAsync(); - throw new Exception(errorMessage); - } + return result; } } From 843672dfc74581b770dc7b3fc369d9cbf7545656 Mon Sep 17 00:00:00 2001 From: LeonarthusMectus Date: Wed, 16 Oct 2024 10:34:22 -0400 Subject: [PATCH 34/34] update Python Flask/Ruby Sinatra examples (#160) --- .../v2/server/python/.flaskenv | 1 + .../v2/server/python/README.md | 41 +++++++++ .../v2/server/python/requirements.txt | 2 + .../v2/server/python/server.py | 86 +++++++++++++++++++ .../v2/server/ruby/.ruby-version | 1 + advanced-integration/v2/server/ruby/Gemfile | 9 ++ advanced-integration/v2/server/ruby/README.md | 37 ++++++++ advanced-integration/v2/server/ruby/server.rb | 67 +++++++++++++++ standard-integration/server/python/.flaskenv | 1 + standard-integration/server/python/README.md | 41 +++++++++ .../server/python/requirements.txt | 2 + standard-integration/server/python/server.py | 86 +++++++++++++++++++ .../server/ruby/.ruby-version | 1 + standard-integration/server/ruby/Gemfile | 9 ++ standard-integration/server/ruby/README.md | 37 ++++++++ standard-integration/server/ruby/server.rb | 67 +++++++++++++++ 16 files changed, 488 insertions(+) create mode 100644 advanced-integration/v2/server/python/.flaskenv create mode 100644 advanced-integration/v2/server/python/README.md create mode 100644 advanced-integration/v2/server/python/requirements.txt create mode 100644 advanced-integration/v2/server/python/server.py create mode 100644 advanced-integration/v2/server/ruby/.ruby-version create mode 100644 advanced-integration/v2/server/ruby/Gemfile create mode 100644 advanced-integration/v2/server/ruby/README.md create mode 100644 advanced-integration/v2/server/ruby/server.rb create mode 100644 standard-integration/server/python/.flaskenv create mode 100644 standard-integration/server/python/README.md create mode 100644 standard-integration/server/python/requirements.txt create mode 100644 standard-integration/server/python/server.py create mode 100644 standard-integration/server/ruby/.ruby-version create mode 100644 standard-integration/server/ruby/Gemfile create mode 100644 standard-integration/server/ruby/README.md create mode 100644 standard-integration/server/ruby/server.rb diff --git a/advanced-integration/v2/server/python/.flaskenv b/advanced-integration/v2/server/python/.flaskenv new file mode 100644 index 00000000..c6cbe150 --- /dev/null +++ b/advanced-integration/v2/server/python/.flaskenv @@ -0,0 +1 @@ +FLASK_RUN_PORT=8080 \ No newline at end of file diff --git a/advanced-integration/v2/server/python/README.md b/advanced-integration/v2/server/python/README.md new file mode 100644 index 00000000..de523758 --- /dev/null +++ b/advanced-integration/v2/server/python/README.md @@ -0,0 +1,41 @@ +# Standard Integration Python Flask Sample + +PayPal Standard Integration sample in Python using Flask + +## Running the sample + +1. **Setup a virtual environment** + + ```sh + python3 -m venv .venv + ``` + +1. **Install the dependencies** + + ```sh + pip install -r requirements.txt + ``` + +1. **Add your API credentials to the environment:** + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +1. **Run the server** + + ```sh + flask --app server run + ``` + +1. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/advanced-integration/v2/server/python/requirements.txt b/advanced-integration/v2/server/python/requirements.txt new file mode 100644 index 00000000..7a44eadf --- /dev/null +++ b/advanced-integration/v2/server/python/requirements.txt @@ -0,0 +1,2 @@ +Flask==3.0.3 +paypal-server-sdk==0.5.2 \ No newline at end of file diff --git a/advanced-integration/v2/server/python/server.py b/advanced-integration/v2/server/python/server.py new file mode 100644 index 00000000..2cf004a3 --- /dev/null +++ b/advanced-integration/v2/server/python/server.py @@ -0,0 +1,86 @@ +import logging +import os + +from flask import Flask, request +from paypalserversdk.http.auth.o_auth_2 import ClientCredentialsAuthCredentials +from paypalserversdk.logging.configuration.api_logging_configuration import LoggingConfiguration, \ + RequestLoggingConfiguration, ResponseLoggingConfiguration +from paypalserversdk.paypalserversdk_client import PaypalserversdkClient +from paypalserversdk.controllers.orders_controller import OrdersController +from paypalserversdk.models.amount_with_breakdown import AmountWithBreakdown +from paypalserversdk.models.checkout_payment_intent import CheckoutPaymentIntent +from paypalserversdk.models.order_request import OrderRequest +from paypalserversdk.models.purchase_unit_request import PurchaseUnitRequest +from paypalserversdk.api_helper import ApiHelper + +app = Flask(__name__) + +paypal_client: PaypalserversdkClient = PaypalserversdkClient( + client_credentials_auth_credentials=ClientCredentialsAuthCredentials( + o_auth_client_id=os.getenv('PAYPAL_CLIENT_ID'), + o_auth_client_secret=os.getenv('PAYPAL_CLIENT_SECRET') + ), + logging_configuration=LoggingConfiguration( + log_level=logging.INFO, + # Disable masking of sensitive headers for Sandbox testing. + # This should be set to True (the default if unset)in production. + mask_sensitive_headers=False, + request_logging_config=RequestLoggingConfiguration( + log_headers=True, + log_body=True + ), + response_logging_config=ResponseLoggingConfiguration( + log_headers=True, + log_body=True + ) + ) +) + +''' +Health check +''' +@app.route('/', methods=['GET']) +def index(): + return {"message": "Server is running"} + +orders_controller: OrdersController = paypal_client.orders + +''' +Create an order to start the transaction. + +@see https://developer.paypal.com/docs/api/orders/v2/#orders_create +''' +@app.route('/api/orders', methods=['POST']) +def create_order(): + request_body = request.get_json() + # use the cart information passed from the front-end to calculate the order amount detals + cart = request_body['cart'] + order = orders_controller.orders_create({ + "body": OrderRequest( + intent=CheckoutPaymentIntent.CAPTURE, + purchase_units=[ + PurchaseUnitRequest( + AmountWithBreakdown( + currency_code='USD', + value='100.00' + ) + ) + ] + ), + "prefer": 'return=representation' + } + ) + return ApiHelper.json_serialize(order.body) + +''' + Capture payment for the created order to complete the transaction. + + @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture +''' +@app.route('/api/orders//capture', methods=['POST']) +def capture_order(order_id): + order = orders_controller.orders_capture({ + 'id': order_id, + 'prefer': 'return=representation' + }) + return ApiHelper.json_serialize(order.body) \ No newline at end of file diff --git a/advanced-integration/v2/server/ruby/.ruby-version b/advanced-integration/v2/server/ruby/.ruby-version new file mode 100644 index 00000000..fa7adc7a --- /dev/null +++ b/advanced-integration/v2/server/ruby/.ruby-version @@ -0,0 +1 @@ +3.3.5 diff --git a/advanced-integration/v2/server/ruby/Gemfile b/advanced-integration/v2/server/ruby/Gemfile new file mode 100644 index 00000000..a5b31725 --- /dev/null +++ b/advanced-integration/v2/server/ruby/Gemfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gem "paypal-server-sdk", "~> 0.5.2" +gem "puma", "~> 6.4" +gem "rackup", "~> 2.1" +gem "sinatra", "~> 4.0" +gem "sinatra-contrib", "~> 4.0" \ No newline at end of file diff --git a/advanced-integration/v2/server/ruby/README.md b/advanced-integration/v2/server/ruby/README.md new file mode 100644 index 00000000..6ad18fe2 --- /dev/null +++ b/advanced-integration/v2/server/ruby/README.md @@ -0,0 +1,37 @@ +# Standard Integration Ruby Sinatra Sample + +PayPal Standard Integration sample in Ruby using Sinatra + +## Running the sample + +1. **Ensure you have a supported Ruby version installed**: [Ruby Maintenance Branches](https://www.ruby-lang.org/en/downloads/branches/) + +1. **Install the dependencies** + + ```bash + bundle install + ``` + +1. **Add your API credentials to the environment:** + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +1. **Run the server** + + ```bash + bundle exec ruby server.rb + ``` + +1. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/advanced-integration/v2/server/ruby/server.rb b/advanced-integration/v2/server/ruby/server.rb new file mode 100644 index 00000000..6f0987c8 --- /dev/null +++ b/advanced-integration/v2/server/ruby/server.rb @@ -0,0 +1,67 @@ +require 'paypal_server_sdk' +require 'sinatra' +require 'sinatra/json' + +include PaypalServerSdk + +set :port, 8080 + +paypal_client = PaypalServerSdk::Client.new( + client_credentials_auth_credentials: ClientCredentialsAuthCredentials.new( + o_auth_client_id: ENV['PAYPAL_CLIENT_ID'], + o_auth_client_secret: ENV['PAYPAL_CLIENT_SECRET'] + ), + environment: Environment::SANDBOX, + logging_configuration: LoggingConfiguration.new( + mask_sensitive_headers: false, + log_level: Logger::INFO, + request_logging_config: RequestLoggingConfiguration.new( + log_headers: true, + log_body: true, + ), + response_logging_config: ResponseLoggingConfiguration.new( + log_headers: true, + log_body: true + ) + ) +) + +# Health Check +get '/' do + json :message => "Server is running" +end + +# Create an order to start the transaction. +# +# @see https://developer.paypal.com/docs/api/orders/v2/#orders_create +post "/api/orders" do + # use the cart information passed from the front-end to calculate the order amount detals + cart = JSON.parse request.body.read + order_response = paypal_client.orders.orders_create({ + 'body' => OrderRequest.new( + intent: CheckoutPaymentIntent::CAPTURE, + purchase_units: [ + PurchaseUnitRequest.new( + amount: AmountWithBreakdown.new( + currency_code: 'USD', + value: '100.00' + ) + ) + ] + ), + 'prefer' => 'return=representation' + }) + json order_response.data +end + +# Capture payment for the created order to complete the transaction. +# +# @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture +post '/api/orders/:order_id/capture' do |order_id| + capture_response = paypal_client.orders.orders_capture({ + 'id' => order_id, + 'prefer' => 'return=representation' + }) + json capture_response.data +rescue ErrorException => e +end \ No newline at end of file diff --git a/standard-integration/server/python/.flaskenv b/standard-integration/server/python/.flaskenv new file mode 100644 index 00000000..c6cbe150 --- /dev/null +++ b/standard-integration/server/python/.flaskenv @@ -0,0 +1 @@ +FLASK_RUN_PORT=8080 \ No newline at end of file diff --git a/standard-integration/server/python/README.md b/standard-integration/server/python/README.md new file mode 100644 index 00000000..de523758 --- /dev/null +++ b/standard-integration/server/python/README.md @@ -0,0 +1,41 @@ +# Standard Integration Python Flask Sample + +PayPal Standard Integration sample in Python using Flask + +## Running the sample + +1. **Setup a virtual environment** + + ```sh + python3 -m venv .venv + ``` + +1. **Install the dependencies** + + ```sh + pip install -r requirements.txt + ``` + +1. **Add your API credentials to the environment:** + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +1. **Run the server** + + ```sh + flask --app server run + ``` + +1. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/standard-integration/server/python/requirements.txt b/standard-integration/server/python/requirements.txt new file mode 100644 index 00000000..7a44eadf --- /dev/null +++ b/standard-integration/server/python/requirements.txt @@ -0,0 +1,2 @@ +Flask==3.0.3 +paypal-server-sdk==0.5.2 \ No newline at end of file diff --git a/standard-integration/server/python/server.py b/standard-integration/server/python/server.py new file mode 100644 index 00000000..2cf004a3 --- /dev/null +++ b/standard-integration/server/python/server.py @@ -0,0 +1,86 @@ +import logging +import os + +from flask import Flask, request +from paypalserversdk.http.auth.o_auth_2 import ClientCredentialsAuthCredentials +from paypalserversdk.logging.configuration.api_logging_configuration import LoggingConfiguration, \ + RequestLoggingConfiguration, ResponseLoggingConfiguration +from paypalserversdk.paypalserversdk_client import PaypalserversdkClient +from paypalserversdk.controllers.orders_controller import OrdersController +from paypalserversdk.models.amount_with_breakdown import AmountWithBreakdown +from paypalserversdk.models.checkout_payment_intent import CheckoutPaymentIntent +from paypalserversdk.models.order_request import OrderRequest +from paypalserversdk.models.purchase_unit_request import PurchaseUnitRequest +from paypalserversdk.api_helper import ApiHelper + +app = Flask(__name__) + +paypal_client: PaypalserversdkClient = PaypalserversdkClient( + client_credentials_auth_credentials=ClientCredentialsAuthCredentials( + o_auth_client_id=os.getenv('PAYPAL_CLIENT_ID'), + o_auth_client_secret=os.getenv('PAYPAL_CLIENT_SECRET') + ), + logging_configuration=LoggingConfiguration( + log_level=logging.INFO, + # Disable masking of sensitive headers for Sandbox testing. + # This should be set to True (the default if unset)in production. + mask_sensitive_headers=False, + request_logging_config=RequestLoggingConfiguration( + log_headers=True, + log_body=True + ), + response_logging_config=ResponseLoggingConfiguration( + log_headers=True, + log_body=True + ) + ) +) + +''' +Health check +''' +@app.route('/', methods=['GET']) +def index(): + return {"message": "Server is running"} + +orders_controller: OrdersController = paypal_client.orders + +''' +Create an order to start the transaction. + +@see https://developer.paypal.com/docs/api/orders/v2/#orders_create +''' +@app.route('/api/orders', methods=['POST']) +def create_order(): + request_body = request.get_json() + # use the cart information passed from the front-end to calculate the order amount detals + cart = request_body['cart'] + order = orders_controller.orders_create({ + "body": OrderRequest( + intent=CheckoutPaymentIntent.CAPTURE, + purchase_units=[ + PurchaseUnitRequest( + AmountWithBreakdown( + currency_code='USD', + value='100.00' + ) + ) + ] + ), + "prefer": 'return=representation' + } + ) + return ApiHelper.json_serialize(order.body) + +''' + Capture payment for the created order to complete the transaction. + + @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture +''' +@app.route('/api/orders//capture', methods=['POST']) +def capture_order(order_id): + order = orders_controller.orders_capture({ + 'id': order_id, + 'prefer': 'return=representation' + }) + return ApiHelper.json_serialize(order.body) \ No newline at end of file diff --git a/standard-integration/server/ruby/.ruby-version b/standard-integration/server/ruby/.ruby-version new file mode 100644 index 00000000..fa7adc7a --- /dev/null +++ b/standard-integration/server/ruby/.ruby-version @@ -0,0 +1 @@ +3.3.5 diff --git a/standard-integration/server/ruby/Gemfile b/standard-integration/server/ruby/Gemfile new file mode 100644 index 00000000..a5b31725 --- /dev/null +++ b/standard-integration/server/ruby/Gemfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gem "paypal-server-sdk", "~> 0.5.2" +gem "puma", "~> 6.4" +gem "rackup", "~> 2.1" +gem "sinatra", "~> 4.0" +gem "sinatra-contrib", "~> 4.0" \ No newline at end of file diff --git a/standard-integration/server/ruby/README.md b/standard-integration/server/ruby/README.md new file mode 100644 index 00000000..6ad18fe2 --- /dev/null +++ b/standard-integration/server/ruby/README.md @@ -0,0 +1,37 @@ +# Standard Integration Ruby Sinatra Sample + +PayPal Standard Integration sample in Ruby using Sinatra + +## Running the sample + +1. **Ensure you have a supported Ruby version installed**: [Ruby Maintenance Branches](https://www.ruby-lang.org/en/downloads/branches/) + +1. **Install the dependencies** + + ```bash + bundle install + ``` + +1. **Add your API credentials to the environment:** + + - **Windows** + + ```powershell + $env:PAYPAL_CLIENT_ID = "" + $env:PAYPAL_CLIENT_SECRET = "" + ``` + + - **Unix** + + ```bash + export PAYPAL_CLIENT_ID="" + export PAYPAL_CLIENT_SECRET="" + ``` + +1. **Run the server** + + ```bash + bundle exec ruby server.rb + ``` + +1. Go to [http://localhost:8080/](http://localhost:8080/) diff --git a/standard-integration/server/ruby/server.rb b/standard-integration/server/ruby/server.rb new file mode 100644 index 00000000..6f0987c8 --- /dev/null +++ b/standard-integration/server/ruby/server.rb @@ -0,0 +1,67 @@ +require 'paypal_server_sdk' +require 'sinatra' +require 'sinatra/json' + +include PaypalServerSdk + +set :port, 8080 + +paypal_client = PaypalServerSdk::Client.new( + client_credentials_auth_credentials: ClientCredentialsAuthCredentials.new( + o_auth_client_id: ENV['PAYPAL_CLIENT_ID'], + o_auth_client_secret: ENV['PAYPAL_CLIENT_SECRET'] + ), + environment: Environment::SANDBOX, + logging_configuration: LoggingConfiguration.new( + mask_sensitive_headers: false, + log_level: Logger::INFO, + request_logging_config: RequestLoggingConfiguration.new( + log_headers: true, + log_body: true, + ), + response_logging_config: ResponseLoggingConfiguration.new( + log_headers: true, + log_body: true + ) + ) +) + +# Health Check +get '/' do + json :message => "Server is running" +end + +# Create an order to start the transaction. +# +# @see https://developer.paypal.com/docs/api/orders/v2/#orders_create +post "/api/orders" do + # use the cart information passed from the front-end to calculate the order amount detals + cart = JSON.parse request.body.read + order_response = paypal_client.orders.orders_create({ + 'body' => OrderRequest.new( + intent: CheckoutPaymentIntent::CAPTURE, + purchase_units: [ + PurchaseUnitRequest.new( + amount: AmountWithBreakdown.new( + currency_code: 'USD', + value: '100.00' + ) + ) + ] + ), + 'prefer' => 'return=representation' + }) + json order_response.data +end + +# Capture payment for the created order to complete the transaction. +# +# @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture +post '/api/orders/:order_id/capture' do |order_id| + capture_response = paypal_client.orders.orders_capture({ + 'id' => order_id, + 'prefer' => 'return=representation' + }) + json capture_response.data +rescue ErrorException => e +end \ No newline at end of file