### Start Local Development from App Directory Source: https://docs.gadget.dev/guides/development-tools/cli Once `ggt` is installed globally and you are inside your local app directory, you can start the development sync with a simple `ggt dev` command. ```shell cd ./example-app ggt dev ``` -------------------------------- ### Installation Source: https://docs.gadget.dev/reference/shopify-extensions Instructions for installing the Gadget JS client and the @gadgetinc/shopify-extensions package. ```APIDOC ## Installation This package is a companion to the JavaScript API client for your Gadget app. First, install the JS client by setting up the Gadget NPM registry and then installing the client. ### Yarn ```bash yarn config set @gadget-client:registry https://registry.gadget.dev/npm yarn add @gadget-client/example-app ``` ### NPM ```bash npm config set @gadget-client:registry https://registry.gadget.dev/npm npm install @gadget-client/example-app ``` Refer to your app's API docs for full installation instructions. Once the JS client is installed, install the `@gadgetinc/shopify-extensions` package: ### Yarn ```bash yarn add @gadgetinc/shopify-extensions ``` ### NPM ```bash npm install --save @gadgetinc/shopify-extensions ``` ``` -------------------------------- ### Installation Source: https://docs.gadget.dev/reference/react-bigcommerce Instructions for installing the @gadgetinc/react-bigcommerce package. ```APIDOC ## Installation For Gadget apps that have a BigCommerce connection, the `@gadgetinc/react-bigcommerce` package is automatically installed. If you need to install the package manually, you can do so with `yarn`: ```bash yarn add @gadgetinc/react-bigcommerce ``` Gadget apps use `yarn` as the package manager. If you are adding `@gadgetinc/react-bigcommerce` to a non-Gadget app, you can use the package manager of your choice. ``` -------------------------------- ### Example: Clone and Sync App with `ggt dev` Source: https://docs.gadget.dev/reference/ggt An example demonstrating how to clone the 'my-blog' app into the './my-blog' directory and keep it synchronized with the 'development' environment. ```sh ggt dev ./my-blog --app my-blog --env development ``` -------------------------------- ### Start Shopify Extension Development Server Source: https://docs.gadget.dev/guides/plugins/shopify/advanced-topics/extensions Run this command in your Gadget editor terminal to start the development server for your Shopify extensions. ```bash yarn shopify:dev ``` -------------------------------- ### Install API Client via Script Tag for Development Source: https://docs.gadget.dev/guides/environments Use a script tag to install the API client and connect to the development environment. ```html // in use a script tag to install the API client for an environment ``` -------------------------------- ### Custom Router Setup with Gadget Provider Source: https://docs.gadget.dev/reference/shopify-app-bridge This example demonstrates setting up a custom router using createBrowserRouter and createRoutesFromElements from react-router. It includes a basic layout, index route, and a catch-all 404 route. The GadgetProvider is used within the Layout component to handle authentication and App Bridge initialization. ```typescript import { AppType, Provider as GadgetProvider, useGadget, } from "@gadgetinc/react-shopify-app-bridge"; import { NavMenu } from "@shopify/app-bridge-react"; import { useEffect } from "react"; import { Link, Outlet, Route, RouterProvider, createBrowserRouter, createRoutesFromElements, useLocation, useNavigate, } from "react-router"; import { api } from "../api"; import Index from "../routes/index"; function Error404() { // use navigation hooks to handle 404 pages for undefined routes const navigate = useNavigate(); const location = useLocation(); useEffect(() => { const appURL = process.env.GADGET_PUBLIC_SHOPIFY_APP_URL; if (appURL && location.pathname === new URL(appURL).pathname) { navigate("/", { replace: true }); } }, [location.pathname]); return
404 not found
; } function App() { // define routes const router = createBrowserRouter( createRoutesFromElements( }> } /> } /> ) ); // and return the router provider that defines the App component return ( <> ); } function Layout() { // use the Provider to set up auth, init App Bridge return ( ); } function AuthenticatedApp() { // we use `isAuthenticated` to render pages once the OAuth flow is complete! const { isAuthenticated, loading } = useGadget(); if (loading) { return <>Loading...; } return isAuthenticated ? : ; } function EmbeddedApp() { // use the Outlet, which renders the correct page given the current route // and use the App Bridge NavMenu for Shopify embedded app nav return ( <> Shop Information ); } function UnauthenticatedApp() { return <>App must be viewed in the Shopify Admin; } export default App; ``` -------------------------------- ### Install Shopify Extensions Package (NPM) Source: https://docs.gadget.dev/reference/shopify-extensions Install the `@gadgetinc/shopify-extensions` package using NPM after the Gadget JS client is installed. ```bash npm install --save @gadgetinc/shopify-extensions ``` -------------------------------- ### Usage Example Source: https://docs.gadget.dev/reference/react-bigcommerce Example of how to use the Provider and useGadget hook in a React application. ```APIDOC ## Usage Example To use `@gadgetinc/react-bigcommerce` in your app, you can import the `` and pass in your Gadget app API client as a prop. A `useGadget()` hook can be used to check when the OAuth request is `loading` and if the user `isAuthenticated`. ```tsx import { Provider as GadgetProvider, useGadget } from "@gadgetinc/react-bigcommerce"; import { Box, Link, Panel, ProgressCircle, Text } from "@bigcommerce/big-design"; import { api } from "../api"; import { Outlet } from "react-router"; export default function App() { // pass your app's api client to the Provider return ( ); } function AuthenticatedApp() { // the useGadget hook provides the `isAuthenticated` and `loading` booleans const { isAuthenticated, loading } = useGadget(); // show a spinner if authentication is in progress if (loading) { return (
); } // if the user is authenticated, render the router Outlet // otherwise show an unauthenticated app page return ( {isAuthenticated ? : } ); } function UnauthenticatedApp() { return ( {"Edit this app"} ); } ``` ``` -------------------------------- ### Install React Libraries (Yarn) Source: https://docs.gadget.dev/reference/shopify-app-bridge Install the React hooks library, App Bridge React, and React using Yarn. ```bash yarn add @gadgetinc/react-shopify-app-bridge @gadgetinc/react @shopify/app-bridge-react react ``` -------------------------------- ### Install React Libraries (NPM) Source: https://docs.gadget.dev/reference/shopify-app-bridge Install the React hooks library, App Bridge React, and React using NPM. ```bash npm install --save @gadgetinc/react-shopify-app-bridge @gadgetinc/react @shopify/app-bridge-react react ``` -------------------------------- ### Start Gadget Extension Dev Server Locally Source: https://docs.gadget.dev/guides/tutorials/shopify/ui-extension Run this command in your local terminal at your Gadget project root to start the development server for your extension. ```sh yarn shopify app dev ``` -------------------------------- ### Install Shopify Extensions Package Source: https://docs.gadget.dev/guides/plugins/shopify/advanced-topics/customer-account-ui-extensions Install the `@gadgetinc/shopify-extensions` package at your Gadget project root or extension root. ```bash yarn add @gadgetinc/shopify-extensions ``` -------------------------------- ### Start Gadget Development Server Source: https://docs.gadget.dev/guides/development-tools/working-with-agents/working-in-parallel Start `ggt dev` in the workspace directory to enable automatic syncing of local changes with the running Gadget environment. ```bash ggt dev ``` -------------------------------- ### Install Gadget Client and React Hooks (npm) Source: https://docs.gadget.dev/guides/frontend/external-frontends Install the Gadget client package for your specific app and the @gadgetinc/react package using npm. ```npm npm install @gadget-client/example-app @gadgetinc/react ``` -------------------------------- ### Install Gadget CLI Source: https://docs.gadget.dev/guides/tutorials/shopify/theme-app-extensions Install the Gadget Command Line Interface (CLI) globally using npm. ```bash npm install -g @gadgetinc/cli ``` -------------------------------- ### Install ChatGPT Widget Packages Source: https://docs.gadget.dev/guides/plugins/chatgpt Install the required packages for hosting ChatGPT app widgets using Yarn. ```shell yarn add vite-plugin-chatgpt-widgets @gadgetinc/react-chatgpt-apps ``` -------------------------------- ### Install Gadget Client and React Hooks (yarn) Source: https://docs.gadget.dev/guides/frontend/external-frontends Install the Gadget client package for your specific app and the @gadgetinc/react package using yarn. ```yarn yarn add @gadget-client/example-app @gadgetinc/react ``` -------------------------------- ### Widget Deleter Example Source: https://docs.gadget.dev/reference/preact An example demonstrating how to use `useFindMany` to fetch a list of widgets and `useAction` to delete a specific widget. ```APIDOC ## `useFindMany` and `useAction` Example ### Description This example shows how to fetch a list of widgets using `useFindMany` and how to set up a mutation to delete a widget using `useAction`. ### Method N/A (Client-side hooks) ### Endpoint N/A (Client-side hooks) ### Request Example ```javascript import { useFindMany, useAction } from "@gadgetinc/preact"; import { api } from "../api"; function WidgetDeleter() { const [{ data, fetching, error }, refresh] = useFindMany(api.widget, { select: { id: true, name: true, }, }); const [_, deleteWidget] = useAction(api.widget.delete); if (fetching) return "Loading..."; return (
    {data?.map((widget) => (
  • {widget.name}
  • ))}
); } ``` ### Response #### Success Response (200) Data for the widgets, including `id` and `name`. #### Response Example ```json { "data": [ { "id": "widget-1", "name": "Example Widget 1" }, { "id": "widget-2", "name": "Example Widget 2" } ] } ``` ``` -------------------------------- ### Install Gadget Node Client (Yarn) Source: https://docs.gadget.dev/api/example-app/development/external-api-calls/installing Install the Gadget API client package for your application using Yarn. ```yarn yarn add @gadget-client/example-app ``` -------------------------------- ### Install Gadget agent plugin Source: https://docs.gadget.dev/guides/development-tools/working-with-agents/prompt-guide Run this command to install Gadget agent files, including AGENTS.md and Gadget skills, for platform-specific guidance in AI editors. ```bash ggt agent-plugin install ``` -------------------------------- ### Install @gadgetinc/react-chatgpt-apps with Yarn Source: https://docs.gadget.dev/reference/react-chatgpt-apps Use this command to install the package if you need to add it manually to your project. Gadget apps typically have this package pre-installed. ```bash yarn add @gadgetinc/react-chatgpt-apps ``` -------------------------------- ### Example Shopify OAuth Trigger Object Source: https://docs.gadget.dev/guides/actions/triggers This trigger object is passed when a shop completes the OAuth process to install or reinstall an app. It signifies the start of the installation flow. ```json // in an example shopify OAuth trigger { "type": "shopify_oauth" } ``` -------------------------------- ### Example Shopify Admin Trigger Object Source: https://docs.gadget.dev/guides/actions/triggers This trigger object is activated when a Shopify admin app is installed into Gadget. It is used for the `install` action on the `ShopifyShop` model. ```json // in an example shopify admin trigger { "type": "shopify_admin_install" } ``` -------------------------------- ### Send GET Request Immediately with useFetch Source: https://docs.gadget.dev/reference/preact This example demonstrates how `useFetch` automatically sends GET requests when the component first renders. `fetching` will be `true` initially. ```preact import { useFetch } from "@gadgetinc/preact"; export function GetRequest() { // will automatically send the request when the component renders the first time, as it is a GET const [{ data, fetching, error }, resend] = useFetch("/products"); // fetching will be `true` } ``` -------------------------------- ### Install and Initialize Gadget Client SDK Source: https://docs.gadget.dev/guides/plugins/shopify/building-shopify-apps Include the Gadget client-side JavaScript SDK and initialize the client within a `DOMContentLoaded` event listener. Ensure the `endpoint` matches your app proxy configuration. ```html ``` -------------------------------- ### Record Free Trial Start Date Source: https://docs.gadget.dev/guides/plugins/shopify/advanced-topics/billing Populate the 'Trial Started At' field in the Shopify Shop model when a merchant installs the app. This prevents restarting trials on re-installs. ```typescript export const onSuccess: ActionOnSuccess = async ({ api, record }) => { if (!record.trialStartedAt) { // record the current time as the trial start date await api.internal.shopifyShop.update(record.id, { trialStartedAt: new Date() }); } }; ``` -------------------------------- ### Initialize Gadget App with Local Sync Source: https://docs.gadget.dev/guides/source-control Use this command to download Gadget's CLI tool and start a two-way sync session between your local directory and Gadget's cloud infrastructure. Replace 'test-app' with your actual app name. ```sh npx ggt@latest dev ./test-app --app=test-app ``` -------------------------------- ### Handling ChatGPT App Install Trigger Source: https://docs.gadget.dev/guides/plugins/chatgpt Custom actions with the 'ChatGPT App Install' trigger receive a payload containing OAuth information. Use this to perform setup or validation during the OAuth flow. Errors in these actions will abort the OAuth flow. ```typescript export const onSuccess: ActionOnSuccess = async ({ params, record, trigger }) => { if (trigger?.type === "chatgpt_app_install") { // Access OAuth information from the trigger const { oauth, userId, sessionId } = trigger; // oauth.scope - the scopes being granted // oauth.clientId - the OAuth client ID // userId - the user ID (if user model exists) // sessionId - the session ID // Perform any setup needed for this installation await api.yourModel.create({ session: { _link: sessionId }, // ... other fields }); } }; ``` -------------------------------- ### Gadget App File Structure Example Source: https://docs.gadget.dev/guides/source-control This example illustrates the typical file structure of a Gadget app, including backend models, actions, frontend components, access control, and settings. ```text api/ // the backend folder powering your app's api models/ foo/ schema.gadget.ts // the metadata for the foo model actions/ create.js update.js delete.js bar/ schema.gadget.ts // the metadata for the bar model actions/ create.js update.js delete.js actions/ globalActionA.js globalActionB.js web/ // the frontend folder powering your app's experience pages/ index.js about.js components/ header.js footer.js accessControl/ permissions.gadget.ts // the metadata for the app's roles and permissions settings.gadget.ts // the metadata for the app's settings ``` -------------------------------- ### Configure Vite with Remix and Gadget Source: https://docs.gadget.dev/reference/gadget-server Integrates Gadget's pre-defined Remix configuration into your Vite setup. Ensure `gadget-server/vite` and `@remix-run/dev` are installed. ```typescript import { defineConfig } from "vite"; import { gadget } from "gadget-server/vite"; // import the pre-defined config import { remixViteOptions } from "gadget-server/remix"; import { vitePlugin as remix } from "@remix-run/dev"; export default defineConfig({ plugins: [ gadget(), remix({ // pass the config to the remix plugin ...remixViteOptions, }), ], }); ``` -------------------------------- ### Filter Employees by Last Name Prefix Source: https://docs.gadget.dev/guides/data-access/gelly Fetch employees whose last name starts with a specific prefix. This example filters for employees with last names beginning with 'A'. ```gelly field on department { employeeList { id [where startsWith(lastName, prefix: "A")] } } ``` -------------------------------- ### Include Trace ID in Route Response Source: https://docs.gadget.dev/guides/development-tools/logger This example shows how to access the current trace ID using OpenTelemetry's API and include it in an HTTP route's JSON response. Ensure `@opentelemetry/api` is installed. ```typescript import { RouteHandler, } from "gadget-server"; import { trace, context } from "@opentelemetry/api"; function getCurrentTraceId() { const spanContext = trace.getSpanContext(context.active()); return spanContext?.traceId; } /** * Route handler for GET hello * * @type { RouteHandler } route handler - see: https://docs.gadget.dev/guides/http-routes/route-configuration#route-context */ const route = async ({ request, reply, api, logger, connections }) => { // This route file will respond to an http request -- feel free to edit or change it! // For more information on HTTP routes in Gadget applications, see https://docs.gadget.dev/guides/http-routes await reply .type("application/json") .send({ hello: "world", traceId: getCurrentTraceId() }); }; export default route; ``` -------------------------------- ### Call BigCommerce API with Authenticated Client in HTTP Route Source: https://docs.gadget.dev/guides/plugins/bigcommerce/frontends When calling from a single-click frontend, use `connections.bigcommerce.current` to get an authenticated BigCommerce API client instance within an HTTP route. This example fetches products. ```typescript import { RouteHandler } from "gadget-server"; const route: RouteHandler = async ({ request, reply, connections }) => { const bigcommerce = connections.bigcommerce.current; const products = await bigcommerce?.v3.get(`/catalog/products`, { query: { limit: 5 }, }); await reply.send({ products, }); }; export default route; ``` -------------------------------- ### Start Shopify Development Server Source: https://docs.gadget.dev/guides/tutorials/shopify/theme-app-extensions Serve your theme extension locally using the Shopify CLI. This command can be run from your local terminal or the Gadget editor's terminal. ```bash shopify app dev ``` ```bash yarn shopify:dev ``` -------------------------------- ### Initialize Gadget Client with Dynamic Environment Source: https://docs.gadget.dev/guides/development-tools/framework-linter This example demonstrates initializing a Gadget API client with a dynamic environment, which is the recommended approach. It uses `window.gadgetConfig.environment` for runtime environment selection. ```typescript import { MyAppClient } from "@gadget-client/my-app-name"; export const api = new MyAppClient({ environment: window.gadgetConfig.environment }); ``` -------------------------------- ### Example cURL Request for LLM Chat Completion Source: https://docs.gadget.dev/guides/plugins/openai/building-ai-apps This bash command shows how to call the previously defined Gadget HTTP route to get a chat completion, passing the user's question as a query parameter. The response will be the LLM's answer based on the provided context. ```bash > curl https://example-app--development.gadget.app/ask?question=what%20will%20keep%20me%20dry%20in%20the%20rain A raincoat or shelter will keep you dry in the rain. ``` -------------------------------- ### Start Gadget Development Server Source: https://docs.gadget.dev/guides/plugins/shopify/advanced-topics/extensions Run this command in your local terminal to pull down your Gadget app to your local machine for development. Replace placeholders with your actual app domain. ```bash ggt dev ./ --app= --env=development ``` -------------------------------- ### Defining Custom Routes within a Plugin Source: https://docs.gadget.dev/guides/http-routes/route-structure A route plugin that defines a custom GET route using Fastify's `server.get` method. This example creates a route that captures a numeric file ID from the URL and responds with a JSON object containing the extracted file ID. ```typescript // in routes/+custom-routes.ts import type { Server } from "gadget-server"; export default async function (server: Server) { server.get("/example/:file(^d+).png", async ({ request, reply }) => { await reply.send({ filenameWithoutExtension: request.params.file }); }); } ``` -------------------------------- ### Making API Calls with Gadget Client Source: https://docs.gadget.dev/guides/plugins/shopify/building-shopify-apps After initializing the client, use `window.exampleAppClient` to make secure calls to your app's actions (e.g., `getBanner()`) or HTTP routes (e.g., `fetch('/banner-image')`). ```html ``` -------------------------------- ### Create New Environment Source: https://docs.gadget.dev/reference/ggt Create a new environment for your Gadget application. Use `--from` to clone an existing environment and `--use` to switch to it immediately. ```sh ggt env create [options] ``` ```sh $ ggt env create dev-2 --app my-blog ``` ```sh $ ggt env create dev-2 --from development --app my-blog ``` ```sh $ ggt env create dev-2 --use --app my-blog ``` -------------------------------- ### API Client Setup Source: https://docs.gadget.dev/reference/shopify-app-bridge Set up your API client for use in your Gadget frontend. Ensure the client is imported correctly. ```typescript import { ExampleAppClient } from "@gadget-client/example-app"; export const api = new ExampleAppClient(); ``` -------------------------------- ### Install @gadgetinc/react-bigcommerce with Yarn Source: https://docs.gadget.dev/reference/react-bigcommerce Use this command to install the package if you need to add it manually to your project. Gadget apps typically have this package installed automatically. ```bash yarn add @gadgetinc/react-bigcommerce ``` -------------------------------- ### Example TOML with Webhook Subscriptions Source: https://docs.gadget.dev/guides/plugins/shopify/advanced-topics/shopify-app-toml An example of a `shopify.app.toml` file for framework v1.7+ demonstrating webhook subscriptions. This includes auto-generated entries for enabled Shopify models and specific entries for model actions with filters. ```toml // in example shopify.app.toml with webhook subscriptions [webhooks] api_version = "2024-10" # Model webhook subscriptions (auto-generated for enabled models) [[webhooks.subscriptions]] topics = ["products/create", "products/update", "products/delete"] uri = "https://webhooks.gadget-services.net/shopify/v1?domain=my-app--development.gadget.app" # Model action webhook with filter and include_fields (linked via triggerKey) [[webhooks.subscriptions]] topics = ["products/update"] filter = "vendor:Nike" include_fields = ["id", "title", "vendor", "updated_at"] uri = "https://webhooks.gadget-services.net/shopify/v1/shopifyProduct-update?domain=my-app--development.gadget.app" ``` -------------------------------- ### Navigate and List App Files Source: https://docs.gadget.dev/guides/source-control Change into your application's directory and list the files to verify the sync. This is a standard command-line operation. ```sh cd ./test-app ls ``` -------------------------------- ### Print logs from a specific start time Source: https://docs.gadget.dev/reference/ggt Query logs starting from a specific point in time using the `--start` flag with an ISO 8601 datetime. ```sh ggt logs --start 2026-03-12T10:00:00Z ``` ```sh $ ggt logs --start 2026-03-12T10:00:00Z ``` -------------------------------- ### Set up a new agent workspace Source: https://docs.gadget.dev/guides/development-tools/working-with-agents/working-in-parallel Use these commands to create a new Git worktree and initialize a Gadget environment for an agent. Ensure you are in your main app directory before starting. This process creates an isolated workspace for each agent. ```bash # From your main app directory git worktree add ../agent-feature-2 cd ../agent-feature-2 ggt env create agent-feature-2 --use ggt var import --from development --all --include-values ggt push --force ``` -------------------------------- ### Provider Setup Source: https://docs.gadget.dev/reference/preact Demonstrates how to set up the `Provider` component to make Gadget API hooks available to your Preact components. ```APIDOC ## Provider Setup ### Description To use the hooks provided by `@gadgetinc/preact`, your Preact components must be wrapped in the `Provider` component. This ensures that the hooks can access the Gadget API client. ### Method N/A (Client-side setup) ### Endpoint N/A (Client-side setup) ### Request Example ```javascript // import the API client for your specific application from your client package // be sure to replace this package name with your own import { ExampleAppClient } from "@gadget-client/example-app"; // import the required Provider object and some example hooks from this package import { Provider } from "@gadgetinc/preact"; import { ComponentChildren } from "preact"; // instantiate the API client for our app const api = new ExampleAppClient({ authenticationMode: { browserSession: true } }); export const MyApp = (props: { children: ComponentChildren }) => { // wrap the application in the so the hooks can find the current client return {props.children}; }; ``` ``` -------------------------------- ### Create a "Hello World" Widget Source: https://docs.gadget.dev/guides/plugins/chatgpt Define a simple React component to be used as a widget in ChatGPT apps. Ensure the file is placed in the `web/chatgpt` directory. ```typescript const HelloWorldWidget = () => { return (

Hello World

); }; export default HelloWorldWidget; ``` -------------------------------- ### Sync Shopify Data on Shop Install Source: https://docs.gadget.dev/guides/plugins/shopify/syncing-shopify-data Use the `onSuccess` function within the Shopify Shop model's `install` action to trigger an initial data sync after a merchant installs your app. ```typescript // in api/models/shopifyShop/actions/install.ts export const onSuccess: ActionOnSuccess = async ({ record, api }) => { await api.shopifySync.run({ domain: record.domain, shop: { _link: record.id, }, }); }; ``` ```graphql mutation ($shopifySync: RunShopifySyncInput) { runShopifySync(shopifySync: $shopifySync) { success errors { message ... on InvalidRecordError { validationErrors { apiIdentifier message } record model { apiIdentifier } } } shopifySync { __typename id state createdAt domain errorDetails errorMessage models syncSince updatedAt } } } ``` ```json { "shopifySync": { "shop": { "_link": "SHOPID" }, "domain": "SHOPDOMAIN" } } ``` -------------------------------- ### Install Anthropic SDK Source: https://docs.gadget.dev/guides/plugins/extending-gadget Install the Anthropic SDK using yarn to integrate with the Anthropic API. ```bash yarn add @anthropic-ai/sdk ``` -------------------------------- ### Example Public Folder Structure Source: https://docs.gadget.dev/guides/frontend/building-frontends This markdown illustrates a typical structure for the `public` folder in a Gadget project, used for hosting non-transformed static assets. ```markdown public/ favicon.ico robots.txt foo/ bar.txt ``` -------------------------------- ### Install React Router Dev Dependency Source: https://docs.gadget.dev/guides/frontend/react-router-in-gadget Install the required development dependency for React Router. ```bash yarn add -D @react-router/dev ``` -------------------------------- ### Install React Router Dependencies Source: https://docs.gadget.dev/guides/frontend/react-router-in-gadget Install the necessary React Router packages using yarn. ```bash yarn add react-router @react-router/fs-routes @react-router/node @react-router/serve ``` -------------------------------- ### Create a React App Frontend Source: https://docs.gadget.dev/guides/frontend/external-frontends Use this command to quickly scaffold a new React application for your external frontend. This is a prerequisite for integrating with Gadget. ```plain npx create-react-app example-app-frontend ``` ```plain yarn create react-app example-app-frontend ``` -------------------------------- ### Custom Shopify Install Route Handler Source: https://docs.gadget.dev/guides/plugins/shopify/advanced-topics/oauth Implement this route to customize the behavior of your application's OAuth installation flow. It handles initial installs and re-installs, verifying shop details and redirecting through the OAuth process if necessary. ```typescript import { RouteHandler } from "gadget-server"; const route: RouteHandler<{ Querystring: { hmac: string; shop: string; apiKey: string; host: string; embedded?: "1"; }; }> = async ({ request, reply, api, logger, connections }) => { const { query, gadgetContext } = request; const { hmac, shop: shopDomain, embedded, host: base64Host } = query; const { apiKey } = gadgetContext; if (!hmac || !shopDomain) { // Before rendering this route, Gadget will automatically verify the hmac on your behalf when both of these parameters are present // If either is missing, then this is not a request initiated by Shopify so we'll redirect to the root page return await reply.redirect("/"); } // if you have two or more apps configured for the same environment, it's possible that you could install the same shop twice on the same environment // if we don't find one with this api key, going through the OAuth flow will update any existing shop record with the new api key from this app const shop = ( await api.shopifyShop.findMany({ filter: { myshopifyDomain: { equals: shopDomain }, installedViaApiKey: { equals: apiKey }, state: { inState: "created.installed" }, }, }) )[0]; // An array of all the Shopify scopes that your Gadget app requires const requiredScopes = Array.from( connections.shopify.configuration.requiredScopes ); // This is the single entry point to your app from Shopify. It is both the route that is hit on the initial app install // as well as every time a merchant clicks on your app in their admin if (shop) { const hasAllRequiredScopes = requiredScopes.every((requiredScope) => shop.grantedScopes?.includes(requiredScope) ); if (embedded) { return await reply.redirect("/?" + new URLSearchParams(query).toString()); } else { const host = Buffer.from(base64Host, "base64").toString("ascii"); return await reply.redirect(`https://${host}/apps/${apiKey}`); } } else { // If there's no shop record, this is a fresh install, proceed through OAuth with Shopify logger.info({ shop }, "New app installation, redirecting through OAuth flow"); } // This route will kick-off an OAuth flow with Shopify, pass along all parameters from Shopify (hmac, host, shop, etc) const redirectURL = "/api/connections/auth/shopify?" + new URLSearchParams(query).toString(); // Redirect the merchant through the OAuth flow to grant all required scopes to your Gadget app. // At the end of this flow, the App URL in the connection configuration will point back to this route await reply.redirect(redirectURL.toString()); }; export default route; ``` -------------------------------- ### Install and Update ggt Source: https://docs.gadget.dev/reference/ggt Instructions for installing and updating the Gadget CLI (ggt) globally using npm. ```APIDOC ## Install `ggt` Install `ggt` globally by running: ```sh npm install -g ggt ``` ## Update `ggt` When there is a new release of `ggt`, running `ggt` will show you a message letting you know that an update is available. Update it by running: ```sh npm install -g ggt@latest ``` ``` -------------------------------- ### ggt dev Source: https://docs.gadget.dev/reference/ggt Start local development by syncing your Gadget environment to your local machine. ```APIDOC ## `ggt dev` Clones your hosted Gadget environment's file directory to your local machine, allowing for local development using your favorite code editor and source control support. `ggt dev` will run until stopped. While running, any changes made locally will be pushed to the hosted environment, and any changes made in the hosted environment will be pulled down locally. If your app's local directory already exists, this command first syncs local and environment directories to ensure they match. Changes are tracked from the last sync run (`ggt dev`, `ggt push`, `ggt pull`). If there are conflicts, you will be asked to resolve them before starting development. Only one `ggt dev` process can run per directory at a time. If you try to start `ggt dev` in a directory where it is already running, ggt will print the PID of the existing process and exit. Gadget only supports [Yarn v1](https://classic.yarnpkg.com/lang/en/) for dependency management during synchronization. Avoid deleting or moving all your files while `ggt dev` is active! Gadget will also delete all of your hosted files which will lead to a fatal error in your hosted environment. ##### Usage ```sh-session ggt dev [DIRECTORY] [--app ] [options] ``` ##### Example Clone the `my-blog` app into `./my-blog` and keep it up to date with the development environment: ```sh ggt dev ./my-blog --app my-blog --env development ``` ##### Arguments ###### `DIRECTORY` The directory to sync files to. Defaults to "." (current directory). ##### Options ###### `-a` `--app ` Selects the app to sync files with. If not specified, defaults to the app set in `.gadget/sync.json`. ```sh ggt dev --app my-blog ``` ###### `-e` `--env ` Selects the environment to sync files with. If not specified, defaults to the environment set in `.gadget/sync.json`. ```sh ggt dev --env development ``` ###### `--prefer ` Sets the preferred source, **local** or **environment**, in the event of conflicting changes. If not specified, `ggt` prompts you to manually select during conflicts. ```sh ggt dev --prefer local ``` ``` -------------------------------- ### Example TOML File Structure for Multiple Environments Source: https://docs.gadget.dev/guides/plugins/shopify/advanced-topics/shopify-app-toml Illustrates how to organize primary TOML files for different environments within a single project. Each file (`.toml` or `.environment.toml`) corresponds to a distinct Shopify app configuration. ```markdown // in example of toml files in a single app shopify.app.toml // for your production environment's Shopify app shopify.app.development.toml // for your development environment shopify.app.carl-dev.toml // for a carl-dev development environment ``` -------------------------------- ### Enable live data updates with `useFindOne` and `live: true` Source: https://docs.gadget.dev/reference/preact Pass `live: true` to `useFindOne` to make the component re-render automatically when the data it displays changes in the database. This sets up a subscription to the Gadget backend for real-time updates. ```preact import { useFindOne } from "@gadgetinc/preact"; import { api } from "../api"; export const LiveWidgets = (props: { id: string }) => { const [{ data, fetching, error }] = useFindOne(api.widget, props.id, { live: true }); // will re-render when widgets change return ( {data?.id}: {data?.name} ); }; ``` -------------------------------- ### Install @fastify/multipart Source: https://docs.gadget.dev/guides/http-routes/route-configuration Install the @fastify/multipart package using yarn. This enables support for multipart requests, such as file uploads. ```sh yarn add @fastify/multipart ``` -------------------------------- ### Install Gadget Node Client (NPM) Source: https://docs.gadget.dev/api/example-app/development/external-api-calls/installing Install the Gadget API client package for your application using NPM. ```npm npm install @gadget-client/example-app ```