rdc-endpoint-setup

Set up @data-client/endpoint for custom async operations. Wraps existing async functions with Endpoint for use with Data Client hooks. Use after rdc-setup detects non-REST/GraphQL async patterns.

16 stars

Best use case

rdc-endpoint-setup is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Set up @data-client/endpoint for custom async operations. Wraps existing async functions with Endpoint for use with Data Client hooks. Use after rdc-setup detects non-REST/GraphQL async patterns.

Teams using rdc-endpoint-setup should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/rdc-endpoint-setup/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/development/rdc-endpoint-setup/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/rdc-endpoint-setup/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How rdc-endpoint-setup Compares

Feature / Agentrdc-endpoint-setupStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Set up @data-client/endpoint for custom async operations. Wraps existing async functions with Endpoint for use with Data Client hooks. Use after rdc-setup detects non-REST/GraphQL async patterns.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Custom Endpoint Setup

This skill configures `@data-client/endpoint` for wrapping existing async functions. It should be applied after `rdc-setup` detects custom async patterns that aren't REST or GraphQL.

## Installation

Install the endpoint package alongside the core package:

```bash
# npm
npm install @data-client/endpoint

# yarn
yarn add @data-client/endpoint

# pnpm
pnpm add @data-client/endpoint
```

## When to Use

Use `@data-client/endpoint` when:
- Working with third-party SDK clients (Firebase, Supabase, AWS SDK, etc.)
- Using WebSocket connections for data fetching
- Accessing local async storage (IndexedDB, AsyncStorage)
- Any async function that doesn't fit REST or GraphQL patterns

## Wrapping Async Functions

See [Endpoint](references/Endpoint.md) for full API documentation.

### Detection

Scan for existing async functions that fetch data:
- Functions returning `Promise<T>`
- SDK client methods
- WebSocket message handlers
- IndexedDB operations

### Basic Wrapping Pattern

**Before (existing code):**
```ts
// src/api/users.ts
export async function getUser(id: string): Promise<User> {
  const response = await sdk.users.get(id);
  return response.data;
}

export async function listUsers(filters: UserFilters): Promise<User[]> {
  const response = await sdk.users.list(filters);
  return response.data;
}
```

**After (with Endpoint wrapper):**
```ts
// src/api/users.ts
import { Endpoint } from '@data-client/endpoint';
import { User } from '../schemas/User';

// Original functions (keep for reference or direct use)
async function fetchUser(id: string): Promise<User> {
  const response = await sdk.users.get(id);
  return response.data;
}

async function fetchUsers(filters: UserFilters): Promise<User[]> {
  const response = await sdk.users.list(filters);
  return response.data;
}

// Wrapped as Endpoints for use with Data Client hooks
export const getUser = new Endpoint(fetchUser, {
  schema: User,
  name: 'getUser',
});

export const listUsers = new Endpoint(fetchUsers, {
  schema: [User],
  name: 'listUsers',
});
```

## Endpoint Options

Configure based on the function's behavior:

```ts
export const getUser = new Endpoint(fetchUser, {
  // Required for normalization
  schema: User,
  
  // Unique name (important if function names get mangled in production)
  name: 'getUser',
  
  // Mark as side-effect if it modifies data
  sideEffect: true, // for mutations
  
  // Cache configuration
  dataExpiryLength: 60000, // 1 minute
  errorExpiryLength: 5000, // 5 seconds
  
  // Enable polling
  pollFrequency: 30000, // poll every 30 seconds
  
  // Optimistic updates
  getOptimisticResponse(snap, id) {
    return snap.get(User, { id });
  },
});
```

## Custom Key Function

If the default key function doesn't work for your use case:

```ts
export const searchUsers = new Endpoint(fetchSearchUsers, {
  schema: [User],
  name: 'searchUsers',
  key({ query, page }) {
    // Custom key for complex parameters
    return `searchUsers:${query}:${page}`;
  },
});
```

## Common Patterns

### Firebase/Firestore

```ts
import { Endpoint } from '@data-client/endpoint';
import { doc, getDoc, collection, getDocs } from 'firebase/firestore';
import { db } from './firebase';
import { User } from '../schemas/User';

async function fetchUser(id: string): Promise<User> {
  const docRef = doc(db, 'users', id);
  const docSnap = await getDoc(docRef);
  return { id: docSnap.id, ...docSnap.data() } as User;
}

async function fetchUsers(): Promise<User[]> {
  const querySnapshot = await getDocs(collection(db, 'users'));
  return querySnapshot.docs.map(doc => ({
    id: doc.id,
    ...doc.data(),
  })) as User[];
}

export const getUser = new Endpoint(fetchUser, {
  schema: User,
  name: 'getUser',
});

export const listUsers = new Endpoint(fetchUsers, {
  schema: [User],
  name: 'listUsers',
});
```

### Supabase

```ts
import { Endpoint } from '@data-client/endpoint';
import { supabase } from './supabase';
import { User } from '../schemas/User';

async function fetchUser(id: string): Promise<User> {
  const { data, error } = await supabase
    .from('users')
    .select('*')
    .eq('id', id)
    .single();
  if (error) throw error;
  return data;
}

async function fetchUsers(filters?: { role?: string }): Promise<User[]> {
  let query = supabase.from('users').select('*');
  if (filters?.role) {
    query = query.eq('role', filters.role);
  }
  const { data, error } = await query;
  if (error) throw error;
  return data;
}

export const getUser = new Endpoint(fetchUser, {
  schema: User,
  name: 'getUser',
});

export const listUsers = new Endpoint(fetchUsers, {
  schema: [User],
  name: 'listUsers',
});
```

### IndexedDB

```ts
import { Endpoint } from '@data-client/endpoint';
import { User } from '../schemas/User';

async function fetchUserFromCache(id: string): Promise<User | undefined> {
  const db = await openDB('myapp', 1);
  return db.get('users', id);
}

async function fetchUsersFromCache(): Promise<User[]> {
  const db = await openDB('myapp', 1);
  return db.getAll('users');
}

export const getCachedUser = new Endpoint(fetchUserFromCache, {
  schema: User,
  name: 'getCachedUser',
  dataExpiryLength: Infinity, // Never expires
});

export const listCachedUsers = new Endpoint(fetchUsersFromCache, {
  schema: [User],
  name: 'listCachedUsers',
  dataExpiryLength: Infinity,
});
```

### WebSocket Fetch

```ts
import { Endpoint } from '@data-client/endpoint';
import { socket } from './socket';
import { Message } from '../schemas/Message';

async function fetchMessages(roomId: string): Promise<Message[]> {
  return new Promise((resolve, reject) => {
    socket.emit('getMessages', { roomId }, (response: any) => {
      if (response.error) reject(response.error);
      else resolve(response.data);
    });
  });
}

export const getMessages = new Endpoint(fetchMessages, {
  schema: [Message],
  name: 'getMessages',
});
```

## Mutations with Side Effects

```ts
export const createUser = new Endpoint(
  async (userData: Omit<User, 'id'>): Promise<User> => {
    const { data, error } = await supabase
      .from('users')
      .insert(userData)
      .select()
      .single();
    if (error) throw error;
    return data;
  },
  {
    schema: User,
    name: 'createUser',
    sideEffect: true,
  },
);

export const deleteUser = new Endpoint(
  async (id: string): Promise<{ id: string }> => {
    const { error } = await supabase.from('users').delete().eq('id', id);
    if (error) throw error;
    return { id };
  },
  {
    name: 'deleteUser',
    sideEffect: true,
  },
);
```

## Using extend() for Variations

```ts
const baseUserEndpoint = new Endpoint(fetchUser, {
  schema: User,
  name: 'getUser',
});

// With different cache settings
export const getUserFresh = baseUserEndpoint.extend({
  dataExpiryLength: 0, // Always refetch
});

// With polling
export const getUserLive = baseUserEndpoint.extend({
  pollFrequency: 5000, // Poll every 5 seconds
});
```

## Important: Function Name Mangling

In production builds, function names may be mangled. **Always provide explicit `name` option**:

```ts
// Bad - name may become 'a' or similar in production
const getUser = new Endpoint(fetchUser);

// Good - explicit name survives minification
const getUser = new Endpoint(fetchUser, { name: 'getUser' });
```

## Usage in with hooks and controller

```tsx
useSuspense(getUser, id);
ctrl.fetch(createUser, userData);
```

Both hooks and controller methods take endpoint as first argument, with the endpoint's function arguments following.

## Next Steps

1. Apply skill "rdc-schema" to define Entity classes
2. Apply skill "rdc-react" or "rdc-vue" for usage

## References

- [Endpoint](references/Endpoint.md) - Full Endpoint API

Related Skills

rdc-setup

16
from diegosouzapw/awesome-omni-skill

Install and set up @data-client/react or @data-client/vue in a project. Detects project type (NextJS, Expo, React Native, Vue, plain React) and protocol (REST, GraphQL, custom), then hands off to protocol-specific setup skills.

python-setup-dev-environment

16
from diegosouzapw/awesome-omni-skill

Set up and run a reproducible Python dev environment with uv, ruff, mypy, and VSCode.

prisma-database-setup

16
from diegosouzapw/awesome-omni-skill

Guides for configuring Prisma with different database providers (PostgreSQL, MySQL, SQLite, MongoDB, etc.). Use when setting up a new project, changing databases, or troubleshooting connection issues. Triggers on "configure postgres", "connect to mysql", "setup mongodb", "sqlite setup".

nestjs-setup-guide

16
from diegosouzapw/awesome-omni-skill

NestJS 프로젝트 아키텍처, 기술 스택 선택, 모듈 구조에 대한 질문이나 계획 수립 시 자동으로 가이드 제공

ln-774-healthcheck-setup

16
from diegosouzapw/awesome-omni-skill

Configures health check endpoints for Kubernetes readiness/liveness/startup

hive-endpoint

16
from diegosouzapw/awesome-omni-skill

How to create API endpoints in Hive framework

gainforest-oauth-setup

16
from diegosouzapw/awesome-omni-skill

Implement ATProto OAuth authentication in a Next.js App Router application using gainforest-sdk-nextjs. Use when adding login, logout, session management, or authentication flows that integrate with GainForest, Hypercerts, or ATProto PDSes (climateai.org, gainforest.id).

flowglad-setup

16
from diegosouzapw/awesome-omni-skill

Install and configure the Flowglad SDK for Next.js, Express, and React applications. Use this skill when adding billing to an app, setting up Flowglad for the first time, or configuring SDK providers and route handlers.

data-client-setup

16
from diegosouzapw/awesome-omni-skill

Install and set up @data-client/react or @data-client/vue in a project. Detects project type (NextJS, Expo, React Native, Vue, plain React) and protocol (REST, GraphQL, custom), then hands off to protocol-specific setup skills.

conda-env-setup

16
from diegosouzapw/awesome-omni-skill

This skill should be used when the user asks to "setup conda environment", "configure Python environment", "activate conda automatically", "set conda environment for workspace", or mentions conda environment activation for Claude Code. Provides automatic conda environment configuration for workspaces.

clerk-setup

16
from diegosouzapw/awesome-omni-skill

Add Clerk authentication to any project by following the official quickstart guides.

ccw-maven-setup

16
from diegosouzapw/awesome-omni-skill

Prepares Maven build environment for Claude Code Web by installing Java 25 and configuring Maven proxy. Run automatically before Maven operations in CCW.