# Browser/CDN Bundle Implementation Plan

## Document Purpose

This document serves as the engineering reference for the browser-ready IIFE bundle implementation. It details the architectural decisions, safety guarantees, and verification procedures to ensure a **100% non-breaking** addition to the `@one-payments/web-components` package.

---

## 1. High-Level Goal

**Objective**: Enable `@one-payments/web-components` to be loaded via a simple `<script>` tag from CDN (jsDelivr, unpkg) for use on platforms without build systems:

- Shopify themes (Liquid)
- Wix sites (HTML embeds)
- WordPress pages (Custom HTML blocks)
- Static HTML sites
- No-code/low-code platforms

**Deliverable**: A single `one-payment.browser.iife.js` file that:

1. Auto-registers the `<one-payment>` custom element
2. Exposes `window.OnePayments` API with `createWebAdapters()`
3. Bundles all dependencies inline (no external imports)
4. Works with a simple `<script src="..."></script>` tag

---

## 2. Non-Breaking Requirement

> **CRITICAL**: This implementation MUST NOT affect any existing functionality.

### What MUST Remain Unchanged

| Component | Guarantee |
|-----------|-----------|
| ESM build (`dist/index.js`) | No modifications to output |
| TypeScript types (`dist/index.d.ts`) | No modifications |
| `@one-payments/react` | No behavioral changes |
| `@one-payments/vue` | No behavioral changes |
| `@one-payments/angular` | No behavioral changes |
| `@one-payments/react-native` | No behavioral changes |
| Existing `src/index.ts` | **NOT MODIFIED** |
| Existing `vite.config.ts` | **NOT MODIFIED** |
| Tree-shaking for ESM consumers | Preserved |

### Non-Breaking Strategy

1. **New files only** - No modifications to existing source files
2. **Separate build config** - `vite.config.browser.ts` is completely independent
3. **Additive package.json** - Only new scripts/exports added
4. **Safe registration** - `customElements.get()` check prevents conflicts

---

## 3. Implementation Details

### 3.1 File Structure

```
packages/web-components/
├── src/
│   ├── index.ts              # UNCHANGED - ESM entry
│   ├── one-payment.ts        # UNCHANGED - Component
│   └── browser-entry.ts      # NEW - IIFE entry
├── vite.config.ts            # UNCHANGED - ESM build
├── vite.config.browser.ts    # NEW - IIFE build
├── dist/
│   ├── index.js              # ESM output (unchanged)
│   ├── index.d.ts            # Types (unchanged)
│   └── one-payment.browser.iife.js  # NEW - IIFE output
└── docs/
    ├── integration-cdn-shopify-wix-wordpress.md
    └── dropin-cdn-implementation-plan.md
```

### 3.2 New Entry Point: `browser-entry.ts`

**Purpose**: Provide a browser-specific entry point that:

1. Imports the `OnePayment` class (not the auto-registering module)
2. Manually registers the custom element with safety checks
3. Exposes minimal `window.OnePayments` API

**Key Safety Features**:

```typescript
// Check if already registered (prevents DOMException)
if (customElements.get(TAG_NAME)) {
  console.info(`<${TAG_NAME}> already registered`);
  return true;
}

// Check if window.OnePayments exists (handles multiple loads)
if (!window.OnePayments) {
  window.OnePayments = OnePayments;
}
```

### 3.3 Separate Vite Config: `vite.config.browser.ts`

**Critical Settings**:

```typescript
build: {
  emptyOutDir: false,  // DO NOT delete existing ESM build
  lib: {
    entry: 'src/browser-entry.ts',  // Different entry point
    formats: ['iife'],               // Browser format
    name: 'OnePayments',             // window.OnePayments
  },
}
```

**Dependency Resolution**:

```typescript
resolve: {
  alias: {
    '@one-payments/core': resolve(__dirname, '../core/src/index.ts'),
    '@one-payments/adapters-web': resolve(__dirname, '../adapters-web/src/index.ts'),
  },
}
```

This ensures workspace packages are bundled from source into the IIFE.

### 3.4 Package.json Updates

**New Scripts**:

```json
{
  "scripts": {
    "build:browser": "vite build --config vite.config.browser.ts",
    "build:all": "pnpm build && pnpm build:browser"
  }
}
```

**New Exports**:

```json
{
  "exports": {
    "./browser": {
      "default": "./dist/one-payment.browser.iife.js"
    }
  },
  "browser": "./dist/one-payment.browser.iife.js",
  "unpkg": "./dist/one-payment.browser.iife.js",
  "jsdelivr": "./dist/one-payment.browser.iife.js"
}
```

---

## 4. Risk Analysis

### 4.1 Potential Risks and Mitigations

| Risk | Likelihood | Mitigation |
|------|------------|------------|
| ESM build accidentally modified | Very Low | Separate config file, `emptyOutDir: false` |
| Double registration error | Very Low | `customElements.get()` check |
| Framework wrappers break | Very Low | No changes to existing code paths |
| Bundle size bloat for ESM users | None | IIFE is separate file, not imported by ESM |
| Tree-shaking degraded | None | ESM build completely unchanged |
| window pollution | Very Low | Namespace under single `window.OnePayments` |

### 4.2 What Could Go Wrong

1. **Build order**: If `build:browser` runs before `build`, ESM files won't exist yet
   - **Solution**: Use `build:all` which runs sequentially: `pnpm build && pnpm build:browser`

2. **Version mismatch**: IIFE bundles old version while ESM is updated
   - **Solution**: Always run `build:all` for releases; VERSION is read from package.json at build time

3. **Missing dependency**: `@one-payments/adapters-web` not installed
   - **Solution**: Added as dependency in package.json

---

## 5. Verification Checklist

### Pre-Implementation Verification

- [x] Existing `src/index.ts` is NOT modified
- [x] Existing `vite.config.ts` is NOT modified
- [x] Existing `src/one-payment.ts` is NOT modified

### Build Verification

- [ ] `pnpm build` produces same output as before
- [ ] `pnpm build:browser` creates `dist/one-payment.browser.iife.js`
- [ ] Both builds can run sequentially without conflicts
- [ ] ESM output (`dist/index.js`) is identical to pre-change

### Runtime Verification

- [ ] ESM import works: `import { OnePayment } from '@one-payments/web-components'`
- [ ] React wrapper works: `import { OnePayment } from '@one-payments/react'`
- [ ] Vue wrapper works: `import { OnePayment } from '@one-payments/vue'`
- [ ] Angular wrapper works: `import { OnePaymentModule } from '@one-payments/angular'`
- [ ] CDN script tag works: `<script src="...iife.js"></script>`
- [ ] `window.OnePayments.createWebAdapters()` returns valid adapters
- [ ] `<one-payment>` renders correctly when loaded via CDN

### CDN Verification

- [ ] jsDelivr URL works: `https://cdn.jsdelivr.net/npm/@one-payments/web-components@X.Y.Z/dist/one-payment.browser.iife.js`
- [ ] unpkg URL works: `https://unpkg.com/@one-payments/web-components@X.Y.Z/dist/one-payment.browser.iife.js`

---

## 6. Build Commands Reference

```bash
# Build ESM only (existing behavior)
pnpm build

# Build IIFE only (new)
pnpm build:browser

# Build both (recommended for releases)
pnpm build:all

# Full workspace build
pnpm build:all  # in web-components package
```

---

## 7. Future Extensions (Optional)

These are NOT part of the current implementation but could be added later:

1. **UMD format**: Add `formats: ['iife', 'umd']` for AMD/CommonJS compatibility
2. **Slim bundle**: Create variant without QR code support for smaller size
3. **Async loading**: Add `async` script loading support with callback
4. **Custom builds**: Allow excluding specific payment methods at build time
5. **CDN-specific config endpoint**: Provide secure config fetching API

---

## 8. Rollback Plan

If issues are discovered after release:

1. **Immediate**: Remove CDN URLs from documentation
2. **Hotfix**: Publish patch version without IIFE bundle
3. **Files to remove**:
   - `src/browser-entry.ts`
   - `vite.config.browser.ts`
   - Revert package.json changes
4. **No ESM impact**: ESM users are completely unaffected

---

## 9. Summary

This implementation adds browser/CDN support to `@one-payments/web-components` through:

- A new entry point (`browser-entry.ts`)
- A separate Vite config (`vite.config.browser.ts`)
- Additive package.json changes

**Key Guarantee**: Zero changes to existing ESM behavior. All framework wrappers (React, Vue, Angular, React Native) continue to work exactly as before.

**CDN Usage**:

```html
<script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.27/dist/one-payment.browser.iife.js"></script>
<one-payment amount="5000" currency="USD" order-id="order-123"></one-payment>
<script>
  const el = document.querySelector('one-payment');
  el.config = { apiKey: 'pk_...', environment: 'demo' };
  el.adapters = OnePayments.createWebAdapters();
</script>
```
