# tsview - Project Hints

## Overview

tsview is a CLI tool for viewing S3 and MongoDB data through a web UI.

## Key Patterns

### Configuration

- Reads from `.nogit/env.json` (created by `gitzone service`)
- Environment variables: MONGODB_URL, S3_HOST, S3_ACCESSKEY, etc.

### CLI Commands

- `tsview` - Start viewer (auto-finds free port from 3010+)
- `tsview --port 3000` - Force specific port
- `tsview s3` - S3 viewer only
- `tsview mongo` - MongoDB viewer only

### Dependencies

- Uses `@push.rocks/smartbucket` for S3 operations
- Uses `@push.rocks/smartdata` for MongoDB operations
- Uses `@api.global/typedserver` + `@api.global/typedrequest` for API
- Uses `@design.estate/dees-catalog` for UI components

### Build Process

- Run `pnpm build` to compile TypeScript and bundle web UI
- UI is bundled from `ts_web/` to `ts/bundled_ui.ts` as base64

### Web UI Structure

- `ts_web/elements/` - Web components (LitElement-based)
- `ts_web/services/` - API service for backend communication
- `ts_web/utilities/` - Shared formatting functions (formatSize, formatCount, getFileName)
- `ts_web/styles/` - Shared CSS custom properties (themeStyles)

### TypedRequest Pattern

```typescript
// Interface definition
export interface IReq_ListBuckets extends plugins.typedrequest.implementsTR<
  plugins.typedrequest.ITypedRequest,
  IReq_ListBuckets
> {
  method: 'listBuckets';
  request: {};
  response: { buckets: string[] };
}

// Handler registration
typedrouter.addTypedHandler(
  new plugins.typedrequest.TypedHandler<IReq_ListBuckets>(
    'listBuckets',
    async (reqData) => {
      return { buckets: [...] };
    }
  )
);
```

## Real-Time Streaming (v1.5.0+)

### Architecture

- `ts/streaming/` - Backend streaming infrastructure
  - `classes.changestream-manager.ts` - Manages MongoDB and S3 watchers
  - `interfaces.streaming.ts` - TypedRequest interfaces for subscriptions
- `ts_web/services/changestream.service.ts` - Frontend WebSocket client

### MongoDB Change Streams

- Uses native MongoDB Change Streams via `SmartdataDb.mongoDbClient`
- Subscription per collection: `db/collection`
- Events: insert, update, delete, replace, drop

### S3 Change Detection

- Uses `@push.rocks/smartbucket` BucketWatcher (polling-based)
- Polling interval: 5 seconds
- Events: add, modify, delete

### Frontend Components

- `tsview-activity-stream.ts` - Combined activity view with filtering
- MongoDB/S3 browsers auto-subscribe to current resource
- Visual indicators for "Live" status and recent change count

### Key Streaming Interfaces

```typescript
// Subscribe to collection changes
IReq_SubscribeMongo: { database, collection } -> { success, subscriptionId }

// Subscribe to bucket changes
IReq_SubscribeS3: { bucket, prefix? } -> { success, subscriptionId }

// Subscribe to activity stream (all changes)
IReq_SubscribeActivity: {} -> { success, subscriptionId }

// Server pushes changes to subscribed clients
IReq_PushMongoChange: { event: IMongoChangeEvent } -> { received }
IReq_PushS3Change: { event: IS3ChangeEvent } -> { received }
IReq_PushActivityEvent: { event: IActivityEvent } -> { received }
```

### WebSocket Context Pattern

When a TypedHandler receives a WebSocket request, the transport context is available via the second argument (`TypedTools` instance). SmartServe attaches the WebSocket peer to `localData.peer`:

```typescript
// In a TypedHandler callback:
async (reqData, context) => {
  // context is a TypedTools instance
  const peerId = context.localData?.peer?.id; // unique WebSocket connection ID
}
```

To push events back to a specific client, use `findTargetConnection`:

```typescript
const conn = await typedSocket.findTargetConnection(async (c: any) => {
  return c.peer?.id === connectionId;
});
const request = typedSocket.createTypedRequest<IReq_Push>('pushEvent', conn);
await request.fire({ event });
```

### Dependencies Added

- `@api.global/typedsocket` - WebSocket client/server
- `@push.rocks/smartrx` - RxJS utilities
