refactor(advancedSearch): reorder exports and improve type definitions
refactor(types): reorganize SearchCondition and AdvancedSearchState interfaces refactor(filterPresets): streamline useFilterPresets hook and localStorage handling refactor(filtering): clean up ColumnFilterButton and ColumnFilterPopover components refactor(loading): separate GriddyLoadingOverlay from GriddyLoadingSkeleton refactor(searchHistory): enhance useSearchHistory hook with persistence refactor(index): update exports for adapters and core components refactor(rendering): improve EditableCell and TableCell components for clarity refactor(rendering): enhance TableHeader and VirtualBody components for better readability
This commit is contained in:
263
llm/docs/resolvespec-js.md
Normal file
263
llm/docs/resolvespec-js.md
Normal file
@@ -0,0 +1,263 @@
|
||||
# @warkypublic/resolvespec-js v1.0.0
|
||||
|
||||
TypeScript client library for ResolveSpec APIs. Supports body-based REST, header-based REST, and WebSocket protocols. Aligns with Go backend types.
|
||||
|
||||
## Clients
|
||||
|
||||
| Client | Protocol | Singleton Factory |
|
||||
|---|---|---|
|
||||
| `ResolveSpecClient` | REST (body JSON) | `getResolveSpecClient(config)` |
|
||||
| `HeaderSpecClient` | REST (HTTP headers) | `getHeaderSpecClient(config)` |
|
||||
| `WebSocketClient` | WebSocket | `getWebSocketClient(config)` |
|
||||
|
||||
Singleton factories cache instances keyed by URL.
|
||||
|
||||
## Config
|
||||
|
||||
```typescript
|
||||
interface ClientConfig {
|
||||
baseUrl: string;
|
||||
token?: string; // Bearer token
|
||||
}
|
||||
|
||||
interface WebSocketClientConfig {
|
||||
url: string;
|
||||
reconnect?: boolean;
|
||||
reconnectInterval?: number;
|
||||
maxReconnectAttempts?: number;
|
||||
heartbeatInterval?: number;
|
||||
debug?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
## ResolveSpecClient (Body-Based REST)
|
||||
|
||||
```typescript
|
||||
import { ResolveSpecClient, getResolveSpecClient } from '@warkypublic/resolvespec-js';
|
||||
|
||||
const client = new ResolveSpecClient({ baseUrl: 'http://localhost:3000', token: 'your-token' });
|
||||
|
||||
// CRUD - signature: (schema, entity, id?, options?)
|
||||
await client.read('public', 'users', undefined, { columns: ['id', 'name'], limit: 10 });
|
||||
await client.read('public', 'users', 42); // by ID
|
||||
await client.create('public', 'users', { name: 'New' }); // create
|
||||
await client.update('public', 'users', { name: 'Updated' }, 42); // update
|
||||
await client.delete('public', 'users', 42); // delete
|
||||
await client.getMetadata('public', 'users'); // table metadata
|
||||
```
|
||||
|
||||
**Method signatures:**
|
||||
- `read<T>(schema, entity, id?: number|string|string[], options?): Promise<APIResponse<T>>`
|
||||
- `create<T>(schema, entity, data: any|any[], options?): Promise<APIResponse<T>>`
|
||||
- `update<T>(schema, entity, data: any|any[], id?: number|string|string[], options?): Promise<APIResponse<T>>`
|
||||
- `delete(schema, entity, id: number|string): Promise<APIResponse<void>>`
|
||||
- `getMetadata(schema, entity): Promise<APIResponse<TableMetadata>>`
|
||||
|
||||
## HeaderSpecClient (Header-Based REST)
|
||||
|
||||
```typescript
|
||||
import { HeaderSpecClient, getHeaderSpecClient } from '@warkypublic/resolvespec-js';
|
||||
|
||||
const client = new HeaderSpecClient({ baseUrl: 'http://localhost:3000', token: 'your-token' });
|
||||
|
||||
// CRUD - HTTP methods: GET=read, POST=create, PUT=update, DELETE=delete
|
||||
await client.read('public', 'users', undefined, { columns: ['id', 'name'], limit: 50 });
|
||||
await client.create('public', 'users', { name: 'New' });
|
||||
await client.update('public', 'users', '42', { name: 'Updated' });
|
||||
await client.delete('public', 'users', '42');
|
||||
```
|
||||
|
||||
**Method signatures:**
|
||||
- `read<T>(schema, entity, id?: string, options?): Promise<APIResponse<T>>`
|
||||
- `create<T>(schema, entity, data, options?): Promise<APIResponse<T>>`
|
||||
- `update<T>(schema, entity, id: string, data, options?): Promise<APIResponse<T>>`
|
||||
- `delete(schema, entity, id: string): Promise<APIResponse<void>>`
|
||||
|
||||
### Header Mapping
|
||||
|
||||
| Header | Options Field | Format |
|
||||
|---|---|---|
|
||||
| `X-Select-Fields` | `columns` | comma-separated |
|
||||
| `X-Not-Select-Fields` | `omit_columns` | comma-separated |
|
||||
| `X-FieldFilter-{col}` | `filters` (eq, AND) | value |
|
||||
| `X-SearchOp-{op}-{col}` | `filters` (AND) | value |
|
||||
| `X-SearchOr-{op}-{col}` | `filters` (OR) | value |
|
||||
| `X-Sort` | `sort` | `+col` asc, `-col` desc |
|
||||
| `X-Limit` / `X-Offset` | `limit` / `offset` | number |
|
||||
| `X-Cursor-Forward` | `cursor_forward` | string |
|
||||
| `X-Cursor-Backward` | `cursor_backward` | string |
|
||||
| `X-Preload` | `preload` | `Rel:col1,col2` pipe-separated |
|
||||
| `X-Fetch-RowNumber` | `fetch_row_number` | string |
|
||||
| `X-CQL-SEL-{col}` | `computedColumns` | expression |
|
||||
| `X-Custom-SQL-W` | `customOperators` | SQL AND-joined |
|
||||
|
||||
### Utility Functions
|
||||
|
||||
```typescript
|
||||
import { buildHeaders, encodeHeaderValue, decodeHeaderValue } from '@warkypublic/resolvespec-js';
|
||||
|
||||
buildHeaders({ columns: ['id', 'name'], limit: 10 });
|
||||
// => { 'X-Select-Fields': 'id,name', 'X-Limit': '10' }
|
||||
|
||||
encodeHeaderValue('complex value'); // 'ZIP_...' (base64 encoded)
|
||||
decodeHeaderValue(encoded); // original string
|
||||
```
|
||||
|
||||
## WebSocketClient
|
||||
|
||||
```typescript
|
||||
import { WebSocketClient, getWebSocketClient } from '@warkypublic/resolvespec-js';
|
||||
|
||||
const ws = new WebSocketClient({ url: 'ws://localhost:8080/ws', reconnect: true, heartbeatInterval: 30000 });
|
||||
await ws.connect();
|
||||
|
||||
// CRUD
|
||||
await ws.read('users', { schema: 'public', limit: 10, filters: [...], columns: [...] });
|
||||
await ws.create('users', { name: 'New' }, { schema: 'public' });
|
||||
await ws.update('users', '1', { name: 'Updated' }, { schema: 'public' });
|
||||
await ws.delete('users', '1', { schema: 'public' });
|
||||
await ws.meta('users', { schema: 'public' });
|
||||
|
||||
// Subscriptions
|
||||
const subId = await ws.subscribe('users', (notification) => { ... }, { schema: 'public', filters: [...] });
|
||||
await ws.unsubscribe(subId);
|
||||
ws.getSubscriptions();
|
||||
|
||||
// Connection
|
||||
ws.getState(); // 'connecting' | 'connected' | 'disconnecting' | 'disconnected' | 'reconnecting'
|
||||
ws.isConnected();
|
||||
ws.disconnect();
|
||||
|
||||
// Events
|
||||
ws.on('connect', () => {});
|
||||
ws.on('disconnect', (event: CloseEvent) => {});
|
||||
ws.on('error', (error: Error) => {});
|
||||
ws.on('message', (message: WSMessage) => {});
|
||||
ws.on('stateChange', (state: ConnectionState) => {});
|
||||
ws.off('connect');
|
||||
```
|
||||
|
||||
## Options (Query Parameters)
|
||||
|
||||
```typescript
|
||||
interface Options {
|
||||
columns?: string[];
|
||||
omit_columns?: string[];
|
||||
filters?: FilterOption[];
|
||||
sort?: SortOption[];
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
preload?: PreloadOption[];
|
||||
customOperators?: CustomOperator[];
|
||||
computedColumns?: ComputedColumn[];
|
||||
parameters?: Parameter[];
|
||||
cursor_forward?: string;
|
||||
cursor_backward?: string;
|
||||
fetch_row_number?: string;
|
||||
}
|
||||
```
|
||||
|
||||
### FilterOption
|
||||
|
||||
```typescript
|
||||
interface FilterOption {
|
||||
column: string;
|
||||
operator: Operator | string;
|
||||
value: any;
|
||||
logic_operator?: 'AND' | 'OR';
|
||||
}
|
||||
|
||||
// Operators: eq, neq, gt, gte, lt, lte, like, ilike, in,
|
||||
// contains, startswith, endswith, between,
|
||||
// between_inclusive, is_null, is_not_null
|
||||
```
|
||||
|
||||
### SortOption
|
||||
|
||||
```typescript
|
||||
interface SortOption {
|
||||
column: string;
|
||||
direction: 'asc' | 'desc' | 'ASC' | 'DESC';
|
||||
}
|
||||
```
|
||||
|
||||
### PreloadOption
|
||||
|
||||
```typescript
|
||||
interface PreloadOption {
|
||||
relation: string;
|
||||
table_name?: string;
|
||||
columns?: string[];
|
||||
omit_columns?: string[];
|
||||
sort?: SortOption[];
|
||||
filters?: FilterOption[];
|
||||
where?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
updatable?: boolean;
|
||||
computed_ql?: Record<string, string>;
|
||||
recursive?: boolean;
|
||||
primary_key?: string;
|
||||
related_key?: string;
|
||||
foreign_key?: string;
|
||||
recursive_child_key?: string;
|
||||
sql_joins?: string[];
|
||||
join_aliases?: string[];
|
||||
}
|
||||
```
|
||||
|
||||
### Other Types
|
||||
|
||||
```typescript
|
||||
interface ComputedColumn { name: string; expression: string; }
|
||||
interface CustomOperator { name: string; sql: string; }
|
||||
interface Parameter { name: string; value: string; sequence?: number; }
|
||||
```
|
||||
|
||||
## Response Types
|
||||
|
||||
```typescript
|
||||
interface APIResponse<T = any> {
|
||||
success: boolean;
|
||||
data: T;
|
||||
metadata?: Metadata;
|
||||
error?: APIError;
|
||||
}
|
||||
|
||||
interface APIError { code: string; message: string; details?: any; detail?: string; }
|
||||
interface Metadata { total: number; count: number; filtered: number; limit: number; offset: number; row_number?: number; }
|
||||
|
||||
interface TableMetadata {
|
||||
schema: string;
|
||||
table: string;
|
||||
columns: Column[];
|
||||
relations: string[];
|
||||
}
|
||||
|
||||
interface Column { name: string; type: string; is_nullable: boolean; is_primary: boolean; is_unique: boolean; has_index: boolean; }
|
||||
```
|
||||
|
||||
## WebSocket Message Types
|
||||
|
||||
```typescript
|
||||
type MessageType = 'request' | 'response' | 'notification' | 'subscription' | 'error' | 'ping' | 'pong';
|
||||
type WSOperation = 'read' | 'create' | 'update' | 'delete' | 'subscribe' | 'unsubscribe' | 'meta';
|
||||
|
||||
interface WSMessage {
|
||||
id?: string; type: MessageType; operation?: WSOperation;
|
||||
schema?: string; entity?: string; record_id?: string;
|
||||
data?: any; options?: WSOptions; subscription_id?: string;
|
||||
success?: boolean; error?: WSErrorInfo; metadata?: Record<string, any>; timestamp?: string;
|
||||
}
|
||||
|
||||
interface WSNotificationMessage {
|
||||
type: 'notification'; operation: WSOperation; subscription_id: string;
|
||||
schema?: string; entity: string; data: any; timestamp: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Runtime: `uuid`
|
||||
- Peer: none
|
||||
- Node >= 18
|
||||
131
llm/docs/zustandsyncstore.md
Normal file
131
llm/docs/zustandsyncstore.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# @warkypublic/zustandsyncstore v1.0.0
|
||||
|
||||
React library providing synchronized Zustand stores with prop-based state management and persistence support.
|
||||
|
||||
## Peer Dependencies
|
||||
|
||||
- `react` >= 19.0.0
|
||||
- `zustand` >= 5.0.0
|
||||
- `use-sync-external-store` >= 1.4.0
|
||||
|
||||
## Runtime Dependencies
|
||||
|
||||
- `@warkypublic/artemis-kit`
|
||||
|
||||
## API
|
||||
|
||||
Single export: `createSyncStore`
|
||||
|
||||
```typescript
|
||||
import { createSyncStore } from '@warkypublic/zustandsyncstore';
|
||||
```
|
||||
|
||||
### createSyncStore<TState, TProps>(createState?, useValue?)
|
||||
|
||||
**Parameters:**
|
||||
- `createState` (optional): Zustand `StateCreator<TState>` function
|
||||
- `useValue` (optional): Custom hook receiving `{ useStore, useStoreApi } & TProps`, returns additional state to merge
|
||||
|
||||
**Returns:** `SyncStoreReturn<TState, TProps>` containing:
|
||||
- `Provider` — React context provider component
|
||||
- `useStore` — Hook to access the store
|
||||
|
||||
### Provider Props
|
||||
|
||||
| Prop | Type | Description |
|
||||
|---|---|---|
|
||||
| `children` | `ReactNode` | Required |
|
||||
| `firstSyncProps` | `string[]` | Props to sync only on first render |
|
||||
| `persist` | `PersistOptions<Partial<TProps & TState>>` | Zustand persist config |
|
||||
| `waitForSync` | `boolean` | Wait for sync before rendering children |
|
||||
| `fallback` | `ReactNode` | Shown while waiting for sync |
|
||||
| `...TProps` | `TProps` | Custom props synced to store state |
|
||||
|
||||
### useStore Hook
|
||||
|
||||
```typescript
|
||||
const state = useStore(); // entire state (TState & TProps)
|
||||
const count = useStore(state => state.count); // with selector
|
||||
const count = useStore(state => state.count, (a, b) => a === b); // with equality fn
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic
|
||||
|
||||
```tsx
|
||||
interface MyState { count: number; increment: () => void; }
|
||||
interface MyProps { initialCount: number; }
|
||||
|
||||
const { Provider, useStore } = createSyncStore<MyState, MyProps>(
|
||||
(set) => ({
|
||||
count: 0,
|
||||
increment: () => set((state) => ({ count: state.count + 1 })),
|
||||
})
|
||||
);
|
||||
|
||||
function Counter() {
|
||||
const { count, increment } = useStore();
|
||||
return <button onClick={increment}>Count: {count}</button>;
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Provider initialCount={10}>
|
||||
<Counter />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### With Custom Hook Logic
|
||||
|
||||
```tsx
|
||||
const { Provider, useStore } = createSyncStore<MyState, MyProps>(
|
||||
(set) => ({ count: 0, increment: () => set((s) => ({ count: s.count + 1 })) }),
|
||||
({ useStore, useStoreApi, initialCount }) => {
|
||||
const currentCount = useStore(state => state.count);
|
||||
return { computedValue: initialCount * 2 };
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### With Persistence
|
||||
|
||||
```tsx
|
||||
<Provider initialCount={10} persist={{ name: 'my-store', storage: localStorage }}>
|
||||
<Counter />
|
||||
</Provider>
|
||||
```
|
||||
|
||||
### Selective Prop Syncing
|
||||
|
||||
```tsx
|
||||
<Provider initialCount={10} otherProp="value" firstSyncProps={['initialCount']}>
|
||||
<Counter />
|
||||
</Provider>
|
||||
```
|
||||
|
||||
## Internal Types
|
||||
|
||||
```typescript
|
||||
type LocalUseStore<TState, TProps> = TState & TProps;
|
||||
|
||||
// Store state includes a $sync method for internal prop syncing
|
||||
type InternalStoreState<TState, TProps> = TState & TProps & {
|
||||
$sync: (props: TProps) => void;
|
||||
};
|
||||
|
||||
type SyncStoreReturn<TState, TProps> = {
|
||||
Provider: (props: { children: ReactNode } & {
|
||||
firstSyncProps?: string[];
|
||||
persist?: PersistOptions<Partial<TProps & TState>>;
|
||||
waitForSync?: boolean;
|
||||
fallback?: ReactNode;
|
||||
} & TProps) => React.ReactNode;
|
||||
useStore: {
|
||||
(): LocalUseStore<TState, TProps>;
|
||||
<U>(selector: (state: LocalUseStore<TState, TProps>) => U, equalityFn?: (a: U, b: U) => boolean): U;
|
||||
};
|
||||
};
|
||||
```
|
||||
Reference in New Issue
Block a user