{"slug":"developers/PHASE_4_GATEWAY_SDK_FOUNDATION","title":"Phase 4: Gateway SDK Foundation","section":"developers","sectionLabel":"Developers","status":"unclassified","type":"document","path":"developers/PHASE_4_GATEWAY_SDK_FOUNDATION.mdx","bytes":11367,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n\n> **Tier C — Historical.** This document is a point-in-time snapshot preserved for reference. For current architecture, see [CANONICAL_PLATFORM_ARCHITECTURE.md](../architecture/CANONICAL_PLATFORM_ARCHITECTURE.md).\n\nThe minimal, reusable SDK that every frontend imports. Platform capabilities only—no business logic.\n\n## What It Does\n\nThe Gateway SDK is a **thin HTTP client** that:\n- Handles authentication (Stack Auth tokens → Gateway tokens)\n- Manages request/response envelopes\n- Implements retry logic with exponential backoff\n- Provides React hooks for common patterns\n- Streams SSE and WebSocket events\n- Handles errors consistently\n- Provides TypeScript types for all namespaces\n\n## What It Does NOT Do\n\n- Business logic (getting \"customers\" vs \"deals\")\n- UI components\n- State management beyond request/response caching\n- Feature flags or A/B testing\n\nThose belong in the application layer.\n\n---\n\n## File Structure\n\n```\npackages/gateway-sdk/\n├── package.json\n├── tsconfig.json\n├── src/\n│   ├── client/\n│   │   ├── index.ts              # createGatewayClient()\n│   │   ├── httpClient.ts         # HTTP request logic\n│   │   ├── auth.ts               # Stack Auth token → Gateway token exchange\n│   │   ├── retry.ts              # Exponential backoff\n│   │   └── envelope.ts           # Request/response shape\n│   ├── hooks/\n│   │   ├── index.ts\n│   │   ├── useGateway.ts         # Get client context\n│   │   ├── useQuery.ts           # Fetch + cache + refetch\n│   │   ├── useMutation.ts        # POST/PUT/DELETE + error handling\n│   │   ├── useStream.ts          # SSE streaming\n│   │   ├── useRealtime.ts        # WebSocket subscriptions\n│   │   └── useInfinite.ts        # Pagination with cursor\n│   ├── types/\n│   │   ├── index.ts\n│   │   ├── auth.ts               # AuthToken, GatewayToken, User\n│   │   ├── request.ts            # Request envelope\n│   │   ├── response.ts           # Response envelope\n│   │   ├── error.ts              # Error types\n│   │   └── namespaces.ts         # Workspace, Memory, Twin, etc.\n│   ├── errors/\n│   │   ├── index.ts\n│   │   ├── GatewayError.ts\n│   │   ├── AuthError.ts\n│   │   └── handlers.ts           # Error handling strategies\n│   ├── realtime/\n│   │   ├── index.ts\n│   │   ├── websocket.ts          # WebSocket manager\n│   │   ├── eventEmitter.ts       # Event subscription\n│   │   └── reconnection.ts       # Automatic reconnect\n│   ├── cache/\n│   │   ├── index.ts\n│   │   ├── queryCache.ts         # SWR-like cache\n│   │   └── invalidation.ts       # Cache busting strategies\n│   ├── context/\n│   │   ├── index.ts\n│   │   ├── GatewayProvider.tsx   # React context provider\n│   │   └── useGatewayContext.ts\n│   ├── mock/\n│   │   ├── index.ts\n│   │   ├── mockClient.ts         # In-memory client for testing\n│   │   └── fixtures.ts           # Sample data\n│   └── index.ts                  # Public API\n├── __tests__/\n│   ├── client.test.ts\n│   ├── auth.test.ts\n│   ├── hooks.test.ts\n│   └── realtime.test.ts\n└── README.md\n```\n\n---\n\n## Public API (Main Exports)\n\n### 1. Client Creation\n\n```typescript\n\nconst gateway = createGatewayClient({\n  gatewayUrl: 'https://gateway.integratewise.com',\n  stackAuthToken: '<from-stack-auth>',\n  org_id: 'org_456',\n  team_id: 'team_789'\n})\n\n// On success, gateway.auth returns Gateway token\n// Automatically renewed on expiry\n```\n\n### 2. Request Method\n\n```typescript\nconst response = await gateway.request({\n  namespace: 'workspace',\n  action: 'listEntities',\n  version: 'v1',\n  params: {\n    type: 'customer',\n    limit: 50\n  }\n})\n\n// Returns: { success: true, data: {...}, context: {...} }\n```\n\n### 3. React Hook: useQuery\n\n```typescript\n\nfunction CustomerList() {\n  const { data, isLoading, error, refetch } = useQuery({\n    namespace: 'workspace',\n    action: 'listEntities',\n    params: { type: 'customer' }\n  })\n\n  if (isLoading) return <Loading />\n  if (error) return <Error error={error} />\n\n  return (\n    <>\n      {data.entities.map(e => <Customer key={e.id} entity={e} />)}\n      <button onClick={refetch}>Refresh</button>\n    </>\n  )\n}\n```\n\n### 4. React Hook: useMutation\n\n```typescript\n\nfunction UpdateCustomer({ customerId }) {\n  const mutation = useMutation({\n    namespace: 'workspace',\n    action: 'updateEntity',\n    onSuccess: () => queryClient.invalidateQueries('workspace')\n  })\n\n  const handleUpdate = async (changes) => {\n    await mutation.mutate({\n      params: { id: customerId, ...changes }\n    })\n  }\n\n  return (\n    <form onSubmit={e => {\n      e.preventDefault()\n      handleUpdate({ status: 'active' })\n    }}>\n      <button disabled={mutation.isLoading}>\n        {mutation.isLoading ? 'Saving...' : 'Save'}\n      </button>\n    </form>\n  )\n}\n```\n\n### 5. React Hook: useRealtime\n\n```typescript\n\nfunction LiveCustomers() {\n  const events = useRealtime({\n    namespaces: ['workspace'],\n    filters: { workspace: { type: 'customer' } }\n  })\n\n  useEffect(() => {\n    const unsubscribe = events.subscribe((event) => {\n      console.log('Customer updated:', event.entity_id)\n      queryClient.invalidateQueries('workspace')\n    })\n    return unsubscribe\n  }, [])\n\n  return <div>Listening for live updates...</div>\n}\n```\n\n### 6. React Hook: useStream\n\n```typescript\n\nfunction Search({ query }) {\n  const { isStreaming, results, error, stop } = useStream({\n    namespace: 'workspace',\n    action: 'search',\n    params: { query }\n  })\n\n  return (\n    <div>\n      {results.map(r => <Result key={r.id} result={r} />)}\n      {isStreaming && <LoadingIndicator />}\n      {error && <Error error={error} />}\n      <button onClick={stop}>Stop</button>\n    </div>\n  )\n}\n```\n\n### 7. Mock Client (for testing)\n\n```typescript\n\nconst gateway = createMockGateway({\n  fixtures: {\n    'workspace.listEntities': [\n      { id: 'ent_1', type: 'customer', name: 'Acme' },\n      { id: 'ent_2', type: 'customer', name: 'TechCorp' }\n    ]\n  }\n})\n\n// Behaves identically to real Gateway\n// No network calls, no auth needed\n```\n\n---\n\n## Type Definitions\n\n```typescript\n// From packages/gateway-sdk/src/types/index.ts\n\nexport interface GatewayRequest {\n  namespace: 'workspace' | 'memory' | 'twin' | 'approvals' | 'integrations' | 'skills' | 'entity360' | 'identity'\n  action: string\n  version?: string\n  params: Record<string, any>\n  context?: {\n    request_id?: string\n    trace_id?: string\n  }\n}\n\nexport interface GatewayResponse<T = any> {\n  success: boolean\n  data?: T\n  error?: GatewayError\n  context: {\n    request_id: string\n    processed_at: number\n    latency_ms: number\n  }\n}\n\nexport interface GatewayError {\n  code: string\n  message: string\n  details?: Record<string, any>\n  request_id: string\n  timestamp: number\n}\n\nexport interface User {\n  user_id: string\n  org_id: string\n  team_id: string\n  role: string\n  permissions: string[]\n}\n\nexport interface GatewayToken {\n  access_token: string\n  refresh_token?: string\n  expires_at: number\n  scope: string[]\n}\n```\n\n---\n\n## Configuration\n\n```typescript\n// packages/gateway-sdk/src/client/index.ts\n\ninterface GatewayClientOptions {\n  // Required\n  gatewayUrl: string\n  stackAuthToken: string\n  org_id: string\n  team_id: string\n\n  // Optional\n  maxRetries?: number            // default: 3\n  retryDelay?: number            // default: 1000ms\n  requestTimeout?: number        // default: 30000ms\n  cacheTime?: number             // default: 60000ms\n  staleTime?: number             // default: 0ms (immediately stale)\n\n  // Callbacks\n  onAuthRefresh?: (token: GatewayToken) => void\n  onError?: (error: GatewayError) => void\n  onRateLimit?: (retryAfter: number) => void\n}\n```\n\n---\n\n## Example: Provider Setup\n\n```typescript\n// apps/ai-workspace/app/layout.tsx\n\n\n  const { stackAuthToken, isAuthenticated } = useAuth()\n\n  if (!isAuthenticated) {\n    return <LoginPage />\n  }\n\n  return (\n    <GatewayProvider\n      gatewayUrl={process.env.NEXT_PUBLIC_GATEWAY_URL}\n      stackAuthToken={stackAuthToken}\n      org_id={getCurrentOrgId()}\n      team_id={getCurrentTeamId()}\n    >\n      {children}\n    </GatewayProvider>\n  )\n}\n```\n\n---\n\n## Retry & Error Handling\n\n```typescript\n// Automatic retry with exponential backoff\n// Retries on: 408, 429, 500, 502, 503, 504\n// Not on: 400, 401, 403, 404, 409\n\n// Example: fails with 429 (rate limit)\n// Retry 1: wait 1000ms → fails\n// Retry 2: wait 2000ms → fails\n// Retry 3: wait 4000ms → succeeds\n\n// On auth error (401)\n// No retry — request onAuthRefresh callback\n// App must get new Stack Auth token\n// Gateway SDK automatically exchanges it for new Gateway token\n```\n\n---\n\n## Testing\n\n```typescript\n// apps/ai-workspace/__tests__/customers.test.tsx\n\n\ntest('loads customers', async () => {\n  const gateway = createMockGateway({\n    fixtures: {\n      'workspace.listEntities': {\n        entities: [\n          { id: '1', type: 'customer', name: 'Acme' }\n        ]\n      }\n    }\n  })\n\n  const wrapper = ({ children }) => (\n    <GatewayProvider gateway={gateway}>\n      {children}\n    </GatewayProvider>\n  )\n\n  const { result } = renderHook(() =>\n    useQuery({\n      namespace: 'workspace',\n      action: 'listEntities',\n      params: { type: 'customer' }\n    }),\n    { wrapper }\n  )\n\n  await waitFor(() => expect(result.current.isLoading).toBe(false))\n  expect(result.current.data.entities).toHaveLength(1)\n})\n```\n\n---\n\n## Implementation Checklist\n\n- [ ] Create `packages/gateway-sdk` folder structure\n- [ ] Implement HTTP client and envelope handling\n- [ ] Implement auth token exchange (Stack → Gateway)\n- [ ] Implement retry logic with backoff\n- [ ] Implement React hooks (useQuery, useMutation, useStream, useRealtime)\n- [ ] Implement cache invalidation strategies\n- [ ] Implement mock client for testing\n- [ ] Implement WebSocket manager for realtime\n- [ ] Write comprehensive tests\n- [ ] Write documentation\n- [ ] Create example app using Gateway SDK\n- [ ] Publish to npm registry\n\n---\n\n## Next Steps\n\n1. Build Gateway SDK Foundation (this phase)\n2. Use it in AI Workspace (Phase 5)\n3. Validate all namespace contracts work\n4. Document patterns other apps should follow\n5. Migrate Wise Docs, Wise Ops, Wise ERMS, Wise Branding (Phase 6+)\n\nEvery app after AI Workspace will import the same SDK and follow the same patterns. No variations.\n"}