@nby.ai/ucm 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,260 @@
1
+ # @nby.ai/ucm
2
+
3
+ > Universal Content Module - Supabase-based multilingual CMS
4
+
5
+ [![npm version](https://badge.fury.io/js/@nby.ai%2Fucm.svg)](https://www.npmjs.com/package/@nby.ai/ucm)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7+-blue.svg)](https://www.typescriptlang.org/)
7
+
8
+ ## Features
9
+
10
+ - **Multi-language content** - JSONB storage, unlimited languages (zh, en, ja, ko, etc.)
11
+ - **Multiple content types** - news, blog, doc, event, thought, digest, briefing, case_study, faq
12
+ - **Hierarchical categories** - Multi-level category tree support
13
+ - **Framework-agnostic core** - Works with Node.js, scripts, any framework
14
+ - **React integration** - Provider + Hooks with TanStack React Query
15
+ - **Full TypeScript support** - Complete type definitions
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # Core package
21
+ pnpm add @nby.ai/ucm @supabase/supabase-js
22
+
23
+ # If using React hooks
24
+ pnpm add @tanstack/react-query react
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### Core API (Node.js / Scripts)
30
+
31
+ ```typescript
32
+ import { createUCMClient } from '@nby.ai/ucm'
33
+
34
+ const ucm = createUCMClient({
35
+ url: process.env.SUPABASE_URL!,
36
+ anonKey: process.env.SUPABASE_ANON_KEY!,
37
+ })
38
+
39
+ // List blog posts
40
+ const posts = await ucm.contents.list({ type: 'blog', limit: 10 })
41
+
42
+ // Get single content by slug
43
+ const post = await ucm.contents.getBySlug('hello-world')
44
+
45
+ // Full-text search
46
+ const results = await ucm.contents.search('AI Agent')
47
+
48
+ // Get category tree
49
+ const categories = await ucm.categories.getTree()
50
+
51
+ // Create content (requires service key)
52
+ await ucm.contents.create({
53
+ slug: 'new-post',
54
+ type: 'blog',
55
+ title: { zh: '新文章', en: 'New Post' },
56
+ content: { zh: '正文...', en: 'Body...' },
57
+ })
58
+ ```
59
+
60
+ ### React Integration
61
+
62
+ ```tsx
63
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
64
+ import { UCMProvider, useContents, useContent, getLocalizedText } from '@nby.ai/ucm'
65
+
66
+ const queryClient = new QueryClient()
67
+
68
+ function App() {
69
+ return (
70
+ <QueryClientProvider client={queryClient}>
71
+ <UCMProvider
72
+ config={{
73
+ url: import.meta.env.VITE_SUPABASE_URL,
74
+ anonKey: import.meta.env.VITE_SUPABASE_ANON_KEY,
75
+ }}
76
+ >
77
+ <BlogList />
78
+ </UCMProvider>
79
+ </QueryClientProvider>
80
+ )
81
+ }
82
+
83
+ function BlogList() {
84
+ const { contents, isLoading, error, loadMore, hasMore } = useContents({
85
+ type: 'blog',
86
+ limit: 10,
87
+ })
88
+
89
+ if (isLoading) return <div>Loading...</div>
90
+ if (error) return <div>Error: {error.message}</div>
91
+
92
+ return (
93
+ <>
94
+ <ul>
95
+ {contents.map(post => (
96
+ <li key={post.id}>
97
+ {getLocalizedText(post.title, 'zh')}
98
+ </li>
99
+ ))}
100
+ </ul>
101
+ {hasMore && <button onClick={loadMore}>Load More</button>}
102
+ </>
103
+ )
104
+ }
105
+ ```
106
+
107
+ ## API Reference
108
+
109
+ ### createUCMClient(config)
110
+
111
+ Creates a UCM client instance.
112
+
113
+ ```typescript
114
+ interface UCMClientConfig {
115
+ url: string // Supabase project URL
116
+ anonKey: string // Supabase anon key (or service key for admin ops)
117
+ options?: {
118
+ persistSession?: boolean // Default: false
119
+ autoRefreshToken?: boolean // Default: false
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### UCMClient Methods
125
+
126
+ #### contents
127
+
128
+ | Method | Description |
129
+ |--------|-------------|
130
+ | `list(params?)` | List contents with filtering and pagination |
131
+ | `getBySlug(slug)` | Get content by slug |
132
+ | `getById(id)` | Get content by ID |
133
+ | `count(params?)` | Count contents matching params |
134
+ | `search(query, type?)` | Full-text search |
135
+ | `getTags(type?)` | Get all unique tags |
136
+ | `create(input)` | Create content (requires service key) |
137
+ | `update(id, input)` | Update content |
138
+ | `delete(id)` | Delete content |
139
+ | `incrementView(id)` | Increment view count |
140
+
141
+ #### categories
142
+
143
+ | Method | Description |
144
+ |--------|-------------|
145
+ | `list(params?)` | List categories |
146
+ | `getTree()` | Get hierarchical category tree |
147
+ | `getBySlug(slug)` | Get category by slug |
148
+ | `getById(id)` | Get category by ID |
149
+ | `getChildren(parentId)` | Get child categories |
150
+ | `getRoots()` | Get root categories |
151
+ | `getBreadcrumb(categoryId)` | Get category breadcrumb path |
152
+
153
+ ### React Hooks
154
+
155
+ | Hook | Description |
156
+ |------|-------------|
157
+ | `useContents(options)` | Fetch content list with infinite scroll |
158
+ | `useContent(options)` | Fetch single content by slug or ID |
159
+ | `useCategories(options)` | Fetch categories (flat or tree) |
160
+ | `useSearchContents(options)` | Search with debounce |
161
+ | `useTags(options)` | Fetch all tags |
162
+ | `useAdjacentContents(options)` | Get prev/next navigation |
163
+ | `useThoughts(options)` | Fetch agent thoughts |
164
+
165
+ ### Utility Functions
166
+
167
+ ```typescript
168
+ import { getLocalizedText, buildCategoryTree } from '@nby.ai/ucm'
169
+
170
+ // Get localized text with fallback
171
+ const title = getLocalizedText(content.title, 'zh', 'en')
172
+
173
+ // Build category tree from flat list
174
+ const tree = buildCategoryTree(flatCategories)
175
+ ```
176
+
177
+ ## Types
178
+
179
+ ```typescript
180
+ import type {
181
+ // Core types
182
+ Content,
183
+ ContentType,
184
+ ContentStatus,
185
+ ContentVisibility,
186
+ Category,
187
+ I18nText,
188
+
189
+ // Query params
190
+ ContentQueryParams,
191
+ CategoryQueryParams,
192
+ CreateContentInput,
193
+ UpdateContentInput,
194
+
195
+ // Metadata types
196
+ BlogMetadata,
197
+ NewsMetadata,
198
+ ThoughtMetadata,
199
+ ThoughtMood,
200
+ ThoughtType,
201
+ DigestMetadata,
202
+ BriefingMetadata,
203
+ CaseStudyMetadata,
204
+ EventMetadata,
205
+ DocMetadata,
206
+ } from '@nby.ai/ucm'
207
+ ```
208
+
209
+ ### Content Types
210
+
211
+ | Type | Description |
212
+ |------|-------------|
213
+ | `blog` | Blog posts, tutorials |
214
+ | `news` | Announcements, press releases |
215
+ | `doc` | Documentation, API docs |
216
+ | `event` | Events with time/location |
217
+ | `thought` | Agent thoughts (social feed style) |
218
+ | `digest` | Daily/weekly digests |
219
+ | `briefing` | Project briefings (daily/weekly/monthly) |
220
+ | `case_study` | Customer case studies |
221
+ | `faq` | Frequently asked questions |
222
+
223
+ ### I18nText
224
+
225
+ Multi-language text stored as JSONB:
226
+
227
+ ```typescript
228
+ interface I18nText {
229
+ zh?: string // Chinese
230
+ en?: string // English
231
+ ja?: string // Japanese
232
+ ko?: string // Korean
233
+ // ... more languages
234
+ }
235
+ ```
236
+
237
+ ## Database Schema
238
+
239
+ Requires Supabase with the following tables:
240
+
241
+ - `contents` - Main content table
242
+ - `categories` - Hierarchical categories
243
+
244
+ See [migrations](./supabase/migrations/) for full schema.
245
+
246
+ ## Peer Dependencies
247
+
248
+ | Package | Version | Required |
249
+ |---------|---------|----------|
250
+ | `@supabase/supabase-js` | ^2.0.0 | Yes |
251
+ | `@tanstack/react-query` | ^5.0.0 | For React hooks |
252
+ | `react` | ^18.0.0 \|\| ^19.0.0 | For React hooks |
253
+
254
+ ## License
255
+
256
+ MIT
257
+
258
+ ---
259
+
260
+ *Version 1.0.0 | Last updated: 2026-02-15*