npm package: @secundo/shopify-bridge-client
Description: Client library for communicating with the Secundo Shopify Bridge Extension
Author: Einar-Johan Hansen
Latest version: 1.0.2

# Shopify Bridge Client

Client library for communicating with the [Secundo Shopify Bridge Extension](https://github.com/SecundoAS/secundo-bridge). This library enables embedded Shopify apps to execute GraphQL operations through the Chrome extension, which handles authentication and API calls.

## Features

- **Promise-based API** for GraphQL operations
- **TypeScript support** with full type definitions
- **Automatic shop detection** from URL, App Bridge, or meta tags
- **Request timeout handling** with configurable timeouts
- **Bridge readiness detection** with retry logic
- **Multiple usage modes** - ES modules, CommonJS, or script tag

## Installation

```bash
npm install @secundo/shopify-bridge-client
```

or

```bash
pnpm add @secundo/shopify-bridge-client
```

## Usage

### ES Module

```typescript
import ShopifyBridgeClient from '@secundo/shopify-bridge-client';

// Create a client instance
const bridge = new ShopifyBridgeClient();

// Send a GraphQL query
const products = await bridge.sendOperation(
  'GetProducts',
  `query GetProducts {
    products(first: 10) {
      edges {
        node {
          id
          title
          status
        }
      }
    }
  }`,
);

// Send a GraphQL mutation
const result = await bridge.sendOperation(
  'UpdateProduct',
  `mutation UpdateProduct($input: ProductInput!) {
    productUpdate(input: $input) {
      product {
        id
        title
      }
      userErrors {
        field
        message
      }
    }
  }`,
  {
    input: {
      id: 'gid://shopify/Product/123',
      title: 'Updated Product Title',
    },
  },
  'mutation',
);
```

### Script Tag (CDN)

```html
<!doctype html>
<html>
  <head>
    <meta name="shopify-api-key" content="your-app-api-key" />
  </head>
  <body>
    <script src="https://unpkg.com/@secundo/shopify-bridge-client@latest"></script>
    <script>
      // Client is automatically initialized as window.shopifyBridge
      async function loadProducts() {
        try {
          const result = await window.shopifyBridge.sendOperation(
            'GetProducts',
            `query GetProducts {
              products(first: 10) {
                edges { node { id title } }
              }
            }`,
          );
          console.log('Products:', result);
        } catch (error) {
          console.error('Failed to load products:', error);
        }
      }

      loadProducts();
    </script>
  </body>
</html>
```

## API Reference

### `ShopifyBridgeClient`

#### Constructor

```typescript
const bridge = new ShopifyBridgeClient();
```

Creates a new bridge client instance. The client will automatically:

- Set up message listeners for extension responses
- Check if the extension bridge is ready
- Handle race conditions between client and extension initialization

#### `sendOperation<T>(operationName, query, variables?, operationType?, timeout?): Promise<T>`

Sends a GraphQL operation to the extension for execution.

**Parameters:**

- `operationName` (string): Name of the GraphQL operation
- `query` (string): GraphQL query or mutation string
- `variables` (object, optional): Variables for the operation
- `operationType` ('query' | 'mutation', optional): Type of operation (default: 'query')
- `timeout` (number, optional): Timeout in milliseconds (default: 30000)

**Returns:** Promise that resolves with the operation result

**Example:**

```typescript
const result = await bridge.sendOperation<{ products: ProductConnection }>(
  'GetProducts',
  `query GetProducts($first: Int!) {
    products(first: $first) {
      edges { node { id title } }
    }
  }`,
  { first: 10 },
  'query',
  15000,
);
```

#### `isReady(): boolean`

Returns whether the bridge connection to the extension is ready.

```typescript
if (bridge.isReady()) {
  console.log('Bridge is ready!');
}
```

## Shop Detection

The client automatically detects the shop domain from multiple sources, in order:

1. URL query parameter (`?shop=...`)
2. Shopify App Bridge config (`window.shopify.config.shop`)
3. Base64-encoded host parameter (`?host=...`)
4. Meta tag (`<meta name="shopify-shop-domain" content="..." />`)
5. Hostname patterns (`.myshopify.com`, `admin.shopify.com`)

Make sure your embedded app is loaded in a context where the shop can be detected.

## Error Handling

The client throws errors in the following cases:

- **Bridge not ready**: If the extension is not installed or not responding after retries
- **Shop not detected**: If the shop domain cannot be extracted from the URL/context
- **Operation timeout**: If the operation doesn't complete within the timeout period
- **Operation failed**: If the extension returns an error response

```typescript
try {
  const result = await bridge.sendOperation('GetProducts', query);
  console.log('Success:', result);
} catch (error) {
  if (error.message.includes('timeout')) {
    console.error('Operation timed out');
  } else if (error.message.includes('shop')) {
    console.error('Shop not detected');
  } else {
    console.error('Operation failed:', error);
  }
}
```

## Requirements

- The [Secundo Shopify Bridge Extension](https://github.com/SecundoAS/secundo-bridge) must be installed and enabled
- Your app must be running in a Shopify admin context (embedded app or Shopify admin page)
- The shop domain must be detectable (see Shop Detection section)

## Browser Support

This library uses modern JavaScript features and requires:

- ES2020+ support
- `window.postMessage` API
- `Promise` support
- `async/await` support

Supported browsers:

- Chrome/Edge 80+
- Firefox 75+
- Safari 13.1+

## License

MIT

## Contributing

Contributions are welcome! Please see the [main repository](https://github.com/SecundoAS/secundo-bridge) for contribution guidelines.