[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CXD26FPKCJ4F3STEAYR7YJ":3,"skill-same:01M6CXD26FPKCJ4F3STEAYR7YJ":66},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":33,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":46,"commitSha":47,"skillDirectory":5,"forksCount":48,"repositoryHtmlUrl":49,"repositoryHomepageUrl":6,"ownerHtmlUrl":50,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":51,"install":52,"resources":65},"01M6CXD26FPKCJ4F3STEAYR7YJ","pagination",null,"API pagination design and implementation","ffsshhttiikk\u002Fopencode-agents-skills","ffsshhttiikk","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F226346827?v=4","01M6CWD9RR3Y7VRQX3MXYC8FYH","01M6CWD9WVPYAZW0J82G1VKGHY",3,"MIT","https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills\u002Fblob\u002Fmain\u002Fpagination\u002FSKILL.md",[17,22,25,30],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":26,"categoryName":27,"taxonomyType":28,"taxonomyTypeDesc":29},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",{"categoryNo":31,"categoryName":32,"taxonomyType":28,"taxonomyTypeDesc":29},"01JBSEEDCAT000000000000032","设计师",[5,34,35,36,37],"design","api","opencode","implementation","2026-11-10 10:12:30",false,"---\nname: pagination\ndescription: API pagination design and implementation\nlicense: MIT\ncompatibility: opencode\nmetadata:\n  audience: developers\n  category: api-design\n---\n## What I do\n- Design pagination for REST APIs\n- Implement cursor-based pagination\n- Handle offset-based pagination\n- Optimize for large datasets\n- Support sorting and filtering\n- Design consistent response formats\n- Handle edge cases\n- Document pagination behavior\n\n## When to use me\nWhen implementing pagination in APIs or queries.\n\n## Pagination Strategies\n\n### Offset-Based Pagination\n```sql\n-- Simple offset pagination\nSELECT * FROM posts\nORDER BY created_at DESC\nLIMIT 20 OFFSET 40;  -- Page 3 (20 per page)\n```\n\n**Pros:**\n- Simple to implement\n- Easy to navigate to specific pages\n- URLs are shareable\n\n**Cons:**\n- Performance degrades with large offsets\n- Inconsistent results with changing data\n- Cannot efficiently skip to end\n\n### Cursor-Based Pagination\n```sql\n-- Cursor pagination using created_at and id\nSELECT * FROM posts\nWHERE (created_at, id) \u003C (LAST_CURSOR_CREATED_AT, LAST_CURSOR_ID)\nORDER BY created_at DESC, id DESC\nLIMIT 20;\n```\n\n**Pros:**\n- Consistent performance regardless of offset\n- Handles real-time data better\n- More efficient for large datasets\n\n**Cons:**\n- Cannot jump to random page\n- More complex implementation\n- Requires unique, ordered cursor\n\n### Keyset Pagination\n```sql\n-- Keyset pagination for sorted results\nSELECT * FROM posts\nWHERE status = 'published'\n  AND (score, id) \u003C (LAST_SCORE, LAST_ID)\nORDER BY score DESC, id DESC\nLIMIT 20;\n```\n\n## Cursor-Based Implementation\n```python\nfrom dataclasses import dataclass\nfrom typing import Generic, TypeVar, List, Optional, Dict, Any\nimport base64\nimport json\n\n\nT = TypeVar('T')\n\n\n@dataclass\nclass Cursor:\n    \"\"\"Base64-encoded cursor containing ordering values.\"\"\"\n    values: tuple\n    created_at: str  # ISO format timestamp\n\n    def encode(self) -> str:\n        \"\"\"Encode cursor to base64 string.\"\"\"\n        data = {\n            'v': list(self.values),\n            'c': self.created_at,\n        }\n        return base64.urlsafe_b64encode(\n            json.dumps(data).encode('utf-8')\n        ).decode('utf-8')\n\n    @classmethod\n    def decode(cls, cursor_str: str) -> Optional['Cursor']:\n        \"\"\"Decode cursor from base64 string.\"\"\"\n        try:\n            data = json.loads(\n                base64.urlsafe_b64decode(\n                    cursor_str.encode('utf-8')\n                ).decode('utf-8')\n            )\n            return cls(values=tuple(data['v']), created_at=data['c'])\n        except Exception:\n            return None\n\n\nclass Paginator(Generic[T]):\n    \"\"\"Cursor-based paginator for API results.\"\"\"\n\n    def __init__(\n        self,\n        queryset,\n        limit: int = 20,\n        max_limit: int = 100\n    ) -> None:\n        self.queryset = queryset\n        self.limit = limit\n        self.max_limit = min(limit, max_limit)\n\n    def paginate(\n        self,\n        cursor_str: Optional[str] = None,\n        sort_by: str = 'created_at',\n        sort_order: str = 'desc'\n    ) -> Dict[str, Any]:\n        \"\"\"Get paginated results.\"\"\"\n        limit = self.max_limit\n\n        # Decode cursor\n        cursor = None\n        if cursor_str:\n            cursor = Cursor.decode(cursor_str)\n            if cursor:\n                # Extract cursor values (exclude timestamp)\n                cursor_values = cursor.values\n            else:\n                cursor_values = None\n        else:\n            cursor_values = None\n\n        # Build query\n        query = self.queryset\n\n        if cursor_values and sort_order == 'desc':\n            # For descending, use \u003C comparison\n            filters = {\n                f'{sort_by}__lt': cursor_values[0],\n            }\n            if len(cursor_values) > 1:\n                filters['id__lt'] = cursor_values[1]\n            query = query.filter(**filters)\n\n        # Order and limit\n        order = '-' + sort_by if sort_order == 'desc' else sort_by\n        items = query.order_by(order)[:limit + 1]\n\n        # Check if there are more results\n        has_next = len(items) > limit\n        items = items[:limit]\n\n        # Build response\n        next_cursor = None\n        if has_next and items:\n            last_item = items[-1]\n            next_cursor = Cursor(\n                values=(getattr(last_item, sort_by), last_item.id),\n                created_at=datetime.utcnow().isoformat()\n            ).encode()\n\n        return {\n            'items': items,\n            'next_cursor': next_cursor,\n            'has_next': has_next,\n        }\n\n\ndef paginated_response(\n    items: List[Any],\n    next_cursor: Optional[str] = None,\n    has_next: bool = False,\n    total_count: Optional[int] = None\n) -> Dict[str, Any]:\n    \"\"\"Build standardized paginated API response.\"\"\"\n    response = {\n        'data': items,\n        'pagination': {\n            'next_cursor': next_cursor,\n            'has_next': has_next,\n        }\n    }\n\n    if total_count is not None:\n        response['pagination']['total'] = total_count\n\n    return response\n```\n\n## API Response Format\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"507f1f77bcf86cd799439011\",\n      \"title\": \"First Post\",\n      \"author\": {\n        \"id\": \"123\",\n        \"name\": \"John Doe\"\n      },\n      \"created_at\": \"2024-01-15T10:30:00Z\"\n    },\n    {\n      \"id\": \"507f1f77bcf86cd799439012\",\n      \"title\": \"Second Post\",\n      \"author\": {\n        \"id\": \"456\",\n        \"name\": \"Jane Smith\"\n      },\n      \"created_at\": \"2024-01-14T15:20:00Z\"\n    }\n  ],\n  \"links\": {\n    \"self\": \"\u002Fapi\u002Fv1\u002Fposts?cursor=abc123&limit=20\",\n    \"first\": \"\u002Fapi\u002Fv1\u002Fposts?limit=20\",\n    \"next\": \"\u002Fapi\u002Fv1\u002Fposts?cursor=def456&limit=20\",\n    \"prev\": null\n  },\n  \"meta\": {\n    \"total_count\": 1500,\n    \"page_size\": 20,\n    \"current_page\": 1\n  }\n}\n```\n\n## Sorting and Filtering\n```python\nfrom enum import Enum\n\n\nclass SortOrder(str, Enum):\n    ASC = \"asc\"\n    DESC = \"desc\"\n\n\nclass SortField:\n    \"\"\"Validate and map sort fields.\"\"\"\n    \n    ALLOWED_FIELDS = {\n        'created_at',\n        'updated_at',\n        'title',\n        'author_name',\n        'popularity',\n    }\n    \n    @classmethod\n    def validate(cls, field: str) -> Optional[str]:\n        \"\"\"Return validated field or None.\"\"\"\n        if field in cls.ALLOWED_FIELDS:\n            return field\n        return None\n\n\nclass FilterParser:\n    \"\"\"Parse and apply filter parameters.\"\"\"\n    \n    SUPPORTED_FILTERS = {\n        'status': {'draft', 'published', 'archived'},\n        'author_id': None,  # Any string\n        'created_after': None,  # ISO date\n        'created_before': None,\n        'has_tags': None,  # Comma-separated\n    }\n    \n    @classmethod\n    def parse(cls, params: Dict[str, str]) -> Dict[str, Any]:\n        \"\"\"Parse filter parameters.\"\"\"\n        filters = {}\n        \n        for key, value in params.items():\n            if key in cls.SUPPORTED_FILTERS:\n                if key.startswith('created_'):\n                    filters[key] = cls._parse_date(value)\n                elif key == 'has_tags':\n                    filters['tags__in'] = value.split(',')\n                else:\n                    allowed = cls.SUPPORTED_FILTERS[key]\n                    if allowed is None or value in allowed:\n                        filters[key] = value\n        \n        return filters\n    \n    @staticmethod\n    def _parse_date(value: str) -> datetime:\n        \"\"\"Parse ISO date string.\"\"\"\n        try:\n            return datetime.fromisoformat(value.replace('Z', '+00:00'))\n        except ValueError:\n            raise ValueError(f\"Invalid date format: {value}\")\n```\n\n## Edge Cases\n```python\nclass PaginationEdgeCases:\n    \"\"\"Handle pagination edge cases.\"\"\"\n    \n    @staticmethod\n    def handle_empty_results(cursor: Optional[str]) -> Dict[str, Any]:\n        \"\"\"Handle empty result set.\"\"\"\n        return {\n            'data': [],\n            'links': {\n                'self': f\"\u002Fapi\u002Fv1\u002Fposts?cursor={cursor or ''}\",\n                'first': \"\u002Fapi\u002Fv1\u002Fposts\",\n                'next': None,\n                'prev': None,\n            },\n            'meta': {\n                'total': 0,\n                'page_size': 20,\n            },\n        }\n    \n    @staticmethod\n    def handle_single_page(cursor: str, items: List) -> Dict[str, Any]:\n        \"\"\"Handle result set that fits on one page.\"\"\"\n        return {\n            'data': items,\n            'links': {\n                'self': f\"\u002Fapi\u002Fv1\u002Fposts?cursor={cursor}\",\n                'first': \"\u002Fapi\u002Fv1\u002Fposts\",\n                'next': None,\n                'prev': None,\n            },\n            'meta': {\n                'total': len(items),\n                'page_size': len(items),\n            },\n        }\n    \n    @staticmethod\n    def validate_cursor(\n        cursor: str,\n        max_age_seconds: int = 86400\n    ) -> bool:\n        \"\"\"Validate cursor hasn't expired.\"\"\"\n        decoded = Cursor.decode(cursor)\n        if not decoded:\n            return False\n        \n        # Check timestamp\n        cursor_time = datetime.fromisoformat(decoded.created_at)\n        max_age = timedelta(seconds=max_age_seconds)\n        \n        return datetime.utcnow() - cursor_time \u003C max_age\n```\n\n## Different Pagination Styles\n```json\n\u002F\u002F Offset-based (page 2 of 10 items per page)\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"page\": 2,\n    \"per_page\": 10,\n    \"total\": 100,\n    \"total_pages\": 10,\n    \"has_next\": true,\n    \"has_prev\": true\n  }\n}\n\n\u002F\u002F Cursor-based\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"next_cursor\": \"abc123...\",\n    \"has_next\": true,\n    \"has_prev\": false\n  }\n}\n\n\u002F\u002F Relative (links for next\u002Fprev)\n{\n  \"data\": [...],\n  \"links\": {\n    \"self\": \"\u002Fposts?page=2\",\n    \"first\": \"\u002Fposts?page=1\",\n    \"prev\": \"\u002Fposts?page=1\",\n    \"next\": \"\u002Fposts?page=3\",\n    \"last\": \"\u002Fposts?page=10\"\n  }\n}\n\n\u002F\u002F Header-based\n\u002F\u002F Link: \u003C\u002Fposts?cursor=abc>; rel=\"next\", \u003C\u002Fposts?cursor=def>; rel=\"prev\"\n```\n","## What I do\n- Design pagination for REST APIs\n- Implement cursor-based pagination\n- Handle offset-based pagination\n- Optimize for large datasets\n- Support sorting and filtering\n- Design consistent response formats\n- Handle edge cases\n- Document pagination behavior\n\n## When to use me\nWhen implementing pagination in APIs or queries.\n\n## Pagination Strategies\n\n### Offset-Based Pagination\n```sql\n-- Simple offset pagination\nSELECT * FROM posts\nORDER BY created_at DESC\nLIMIT 20 OFFSET 40;  -- Page 3 (20 per page)\n```\n\n**Pros:**\n- Simple to implement\n- Easy to navigate to specific pages\n- URLs are shareable\n\n**Cons:**\n- Performance degrades with large offsets\n- Inconsistent results with changing data\n- Cannot efficiently skip to end\n\n### Cursor-Based Pagination\n```sql\n-- Cursor pagination using created_at and id\nSELECT * FROM posts\nWHERE (created_at, id) \u003C (LAST_CURSOR_CREATED_AT, LAST_CURSOR_ID)\nORDER BY created_at DESC, id DESC\nLIMIT 20;\n```\n\n**Pros:**\n- Consistent performance regardless of offset\n- Handles real-time data better\n- More efficient for large datasets\n\n**Cons:**\n- Cannot jump to random page\n- More complex implementation\n- Requires unique, ordered cursor\n\n### Keyset Pagination\n```sql\n-- Keyset pagination for sorted results\nSELECT * FROM posts\nWHERE status = 'published'\n  AND (score, id) \u003C (LAST_SCORE, LAST_ID)\nORDER BY score DESC, id DESC\nLIMIT 20;\n```\n\n## Cursor-Based Implementation\n```python\nfrom dataclasses import dataclass\nfrom typing import Generic, TypeVar, List, Optional, Dict, Any\nimport base64\nimport json\n\n\nT = TypeVar('T')\n\n\n@dataclass\nclass Cursor:\n    \"\"\"Base64-encoded cursor containing ordering values.\"\"\"\n    values: tuple\n    created_at: str  # ISO format timestamp\n\n    def encode(self) -> str:\n        \"\"\"Encode cursor to base64 string.\"\"\"\n        data = {\n            'v': list(self.values),\n            'c': self.created_at,\n        }\n        return base64.urlsafe_b64encode(\n            json.dumps(data).encode('utf-8')\n        ).decode('utf-8')\n\n    @classmethod\n    def decode(cls, cursor_str: str) -> Optional['Cursor']:\n        \"\"\"Decode cursor from base64 string.\"\"\"\n        try:\n            data = json.loads(\n                base64.urlsafe_b64decode(\n                    cursor_str.encode('utf-8')\n                ).decode('utf-8')\n            )\n            return cls(values=tuple(data['v']), created_at=data['c'])\n        except Exception:\n            return None\n\n\nclass Paginator(Generic[T]):\n    \"\"\"Cursor-based paginator for API results.\"\"\"\n\n    def __init__(\n        self,\n        queryset,\n        limit: int = 20,\n        max_limit: int = 100\n    ) -> None:\n        self.queryset = queryset\n        self.limit = limit\n        self.max_limit = min(limit, max_limit)\n\n    def paginate(\n        self,\n        cursor_str: Optional[str] = None,\n        sort_by: str = 'created_at',\n        sort_order: str = 'desc'\n    ) -> Dict[str, Any]:\n        \"\"\"Get paginated results.\"\"\"\n        limit = self.max_limit\n\n        # Decode cursor\n        cursor = None\n        if cursor_str:\n            cursor = Cursor.decode(cursor_str)\n            if cursor:\n                # Extract cursor values (exclude timestamp)\n                cursor_values = cursor.values\n            else:\n                cursor_values = None\n        else:\n            cursor_values = None\n\n        # Build query\n        query = self.queryset\n\n        if cursor_values and sort_order == 'desc':\n            # For descending, use \u003C comparison\n            filters = {\n                f'{sort_by}__lt': cursor_values[0],\n            }\n            if len(cursor_values) > 1:\n                filters['id__lt'] = cursor_values[1]\n            query = query.filter(**filters)\n\n        # Order and limit\n        order = '-' + sort_by if sort_order == 'desc' else sort_by\n        items = query.order_by(order)[:limit + 1]\n\n        # Check if there are more results\n        has_next = len(items) > limit\n        items = items[:limit]\n\n        # Build response\n        next_cursor = None\n        if has_next and items:\n            last_item = items[-1]\n            next_cursor = Cursor(\n                values=(getattr(last_item, sort_by), last_item.id),\n                created_at=datetime.utcnow().isoformat()\n            ).encode()\n\n        return {\n            'items': items,\n            'next_cursor': next_cursor,\n            'has_next': has_next,\n        }\n\n\ndef paginated_response(\n    items: List[Any],\n    next_cursor: Optional[str] = None,\n    has_next: bool = False,\n    total_count: Optional[int] = None\n) -> Dict[str, Any]:\n    \"\"\"Build standardized paginated API response.\"\"\"\n    response = {\n        'data': items,\n        'pagination': {\n            'next_cursor': next_cursor,\n            'has_next': has_next,\n        }\n    }\n\n    if total_count is not None:\n        response['pagination']['total'] = total_count\n\n    return response\n```\n\n## API Response Format\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"507f1f77bcf86cd799439011\",\n      \"title\": \"First Post\",\n      \"author\": {\n        \"id\": \"123\",\n        \"name\": \"John Doe\"\n      },\n      \"created_at\": \"2024-01-15T10:30:00Z\"\n    },\n    {\n      \"id\": \"507f1f77bcf86cd799439012\",\n      \"title\": \"Second Post\",\n      \"author\": {\n        \"id\": \"456\",\n        \"name\": \"Jane Smith\"\n      },\n      \"created_at\": \"2024-01-14T15:20:00Z\"\n    }\n  ],\n  \"links\": {\n    \"self\": \"\u002Fapi\u002Fv1\u002Fposts?cursor=abc123&limit=20\",\n    \"first\": \"\u002Fapi\u002Fv1\u002Fposts?limit=20\",\n    \"next\": \"\u002Fapi\u002Fv1\u002Fposts?cursor=def456&limit=20\",\n    \"prev\": null\n  },\n  \"meta\": {\n    \"total_count\": 1500,\n    \"page_size\": 20,\n    \"current_page\": 1\n  }\n}\n```\n\n## Sorting and Filtering\n```python\nfrom enum import Enum\n\n\nclass SortOrder(str, Enum):\n    ASC = \"asc\"\n    DESC = \"desc\"\n\n\nclass SortField:\n    \"\"\"Validate and map sort fields.\"\"\"\n    \n    ALLOWED_FIELDS = {\n        'created_at',\n        'updated_at',\n        'title',\n        'author_name',\n        'popularity',\n    }\n    \n    @classmethod\n    def validate(cls, field: str) -> Optional[str]:\n        \"\"\"Return validated field or None.\"\"\"\n        if field in cls.ALLOWED_FIELDS:\n            return field\n        return None\n\n\nclass FilterParser:\n    \"\"\"Parse and apply filter parameters.\"\"\"\n    \n    SUPPORTED_FILTERS = {\n        'status': {'draft', 'published', 'archived'},\n        'author_id': None,  # Any string\n        'created_after': None,  # ISO date\n        'created_before': None,\n        'has_tags': None,  # Comma-separated\n    }\n    \n    @classmethod\n    def parse(cls, params: Dict[str, str]) -> Dict[str, Any]:\n        \"\"\"Parse filter parameters.\"\"\"\n        filters = {}\n        \n        for key, value in params.items():\n            if key in cls.SUPPORTED_FILTERS:\n                if key.startswith('created_'):\n                    filters[key] = cls._parse_date(value)\n                elif key == 'has_tags':\n                    filters['tags__in'] = value.split(',')\n                else:\n                    allowed = cls.SUPPORTED_FILTERS[key]\n                    if allowed is None or value in allowed:\n                        filters[key] = value\n        \n        return filters\n    \n    @staticmethod\n    def _parse_date(value: str) -> datetime:\n        \"\"\"Parse ISO date string.\"\"\"\n        try:\n            return datetime.fromisoformat(value.replace('Z', '+00:00'))\n        except ValueError:\n            raise ValueError(f\"Invalid date format: {value}\")\n```\n\n## Edge Cases\n```python\nclass PaginationEdgeCases:\n    \"\"\"Handle pagination edge cases.\"\"\"\n    \n    @staticmethod\n    def handle_empty_results(cursor: Optional[str]) -> Dict[str, Any]:\n        \"\"\"Handle empty result set.\"\"\"\n        return {\n            'data': [],\n            'links': {\n                'self': f\"\u002Fapi\u002Fv1\u002Fposts?cursor={cursor or ''}\",\n                'first': \"\u002Fapi\u002Fv1\u002Fposts\",\n                'next': None,\n                'prev': None,\n            },\n            'meta': {\n                'total': 0,\n                'page_size': 20,\n            },\n        }\n    \n    @staticmethod\n    def handle_single_page(cursor: str, items: List) -> Dict[str, Any]:\n        \"\"\"Handle result set that fits on one page.\"\"\"\n        return {\n            'data': items,\n            'links': {\n                'self': f\"\u002Fapi\u002Fv1\u002Fposts?cursor={cursor}\",\n                'first': \"\u002Fapi\u002Fv1\u002Fposts\",\n                'next': None,\n                'prev': None,\n            },\n            'meta': {\n                'total': len(items),\n                'page_size': len(items),\n            },\n        }\n    \n    @staticmethod\n    def validate_cursor(\n        cursor: str,\n        max_age_seconds: int = 86400\n    ) -> bool:\n        \"\"\"Validate cursor hasn't expired.\"\"\"\n        decoded = Cursor.decode(cursor)\n        if not decoded:\n            return False\n        \n        # Check timestamp\n        cursor_time = datetime.fromisoformat(decoded.created_at)\n        max_age = timedelta(seconds=max_age_seconds)\n        \n        return datetime.utcnow() - cursor_time \u003C max_age\n```\n\n## Different Pagination Styles\n```json\n\u002F\u002F Offset-based (page 2 of 10 items per page)\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"page\": 2,\n    \"per_page\": 10,\n    \"total\": 100,\n    \"total_pages\": 10,\n    \"has_next\": true,\n    \"has_prev\": true\n  }\n}\n\n\u002F\u002F Cursor-based\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"next_cursor\": \"abc123...\",\n    \"has_next\": true,\n    \"has_prev\": false\n  }\n}\n\n\u002F\u002F Relative (links for next\u002Fprev)\n{\n  \"data\": [...],\n  \"links\": {\n    \"self\": \"\u002Fposts?page=2\",\n    \"first\": \"\u002Fposts?page=1\",\n    \"prev\": \"\u002Fposts?page=1\",\n    \"next\": \"\u002Fposts?page=3\",\n    \"last\": \"\u002Fposts?page=10\"\n  }\n}\n\n\u002F\u002F Header-based\n\u002F\u002F Link: \u003C\u002Fposts?cursor=abc>; rel=\"next\", \u003C\u002Fposts?cursor=def>; rel=\"prev\"\n```\n",{"name":5,"license":14,"metadata":43,"description":7,"compatibility":36},{"audience":44,"category":45},"developers","api-design","main","5f7a3e453c98261f93d19a6a7de44ad8f7b72d41",2,"https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills","https:\u002F\u002Fgithub.com\u002Fffsshhttiikk","2026-03-01 06:55:40",{"source":8,"skillName":5,"commands":53,"prompt":63,"zipAvailable":64},[54,57,60],{"tool":55,"command":56},"npx","npx skills add ffsshhttiikk\u002Fopencode-agents-skills --skill pagination",{"tool":58,"command":59},"bunx","bunx skills add ffsshhttiikk\u002Fopencode-agents-skills --skill pagination",{"tool":61,"command":62},"pnpm","pnpm dlx skills add ffsshhttiikk\u002Fopencode-agents-skills --skill pagination","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills\u002Fblob\u002Fmain\u002Fpagination\u002FSKILL.md",true,[],[67,78,88,97,107,116],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":38},"01M6CXT9TXDF79BWJTMQAPB49G","xamarin","Xamarin cross-platform development","https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills\u002Fblob\u002Fmain\u002Fxamarin\u002FSKILL.md",[],[69,74,75,76,36,77],"platform","cross-platform","mobile","development",{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":38},"01M6CXT8AD04MFYDA32VW3FKAG","wrangling","Data wrangling fundamentals","https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills\u002Fblob\u002Fmain\u002Fwrangling\u002FSKILL.md",[],[80,85,36,86,87],"data wrangling","science","data",{"skillNo":89,"name":90,"nameZh":6,"description":91,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":38},"01M6CXT717GCN7SRRNPBDP4508","windows","Windows operating system administration and scripting","https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills\u002Fblob\u002Fmain\u002Fwindows\u002FSKILL.md",[],[90,95,36,96],"system","scripting",{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":38},"01M6CXT54K794NMEM3XAPZZDKT","wide-column","Wide-column data model","https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills\u002Fblob\u002Fmain\u002Fwide-column\u002FSKILL.md",[],[104,105,36,106,87],"wide column","databases","model",{"skillNo":108,"name":109,"nameZh":6,"description":110,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":113,"publishedAt":38},"01M6CXT28FMT2P4V9GZE67WA8E","wide-column-stores","Wide-column database stores","https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills\u002Fblob\u002Fmain\u002Fwide-column-stores\u002FSKILL.md",[],[114,105,36,115],"wide column stores","database",{"skillNo":117,"name":118,"nameZh":6,"description":119,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":120,"categories":121,"keywords":122,"publishedAt":38},"01M6CXT0D0M0Q4T2N7C2RX7DSN","websockets","WebSocket implementation and best practices","https:\u002F\u002Fgithub.com\u002Fffsshhttiikk\u002Fopencode-agents-skills\u002Fblob\u002Fmain\u002Fwebsockets\u002FSKILL.md",[],[118,123,124,125,36,126,37],"websocket","real-time","time","best practices"]