### 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
```