create-kuckit-app 2.0.0 → 2.0.2

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.
Files changed (26) hide show
  1. package/package.json +1 -1
  2. package/templates/base/AGENTS.md +2 -2
  3. package/templates/base/apps/web/AGENTS.md +1 -1
  4. package/templates/base/apps/web/src/index.css +1 -0
  5. package/templates/base/apps/web/src/kuckit-modules.css +13 -0
  6. package/templates/base/apps/web/src/main.tsx +1 -1
  7. package/templates/base/kuckit.config.ts +1 -1
  8. package/templates/base/packages/items-module/AGENTS.md +79 -30
  9. package/templates/base/packages/items-module/README.md +132 -0
  10. package/templates/base/packages/items-module/package.json +12 -10
  11. package/templates/base/packages/items-module/src/server/api/items.router.ts +74 -0
  12. package/templates/base/packages/items-module/src/server/config.ts +27 -0
  13. package/templates/base/packages/items-module/src/{index.ts → server/index.ts} +1 -1
  14. package/templates/base/packages/items-module/src/{module.ts → server/module.ts} +22 -2
  15. package/templates/base/packages/items-module/src/server/usecases/update-item.ts +28 -0
  16. package/templates/base/packages/items-module/src/api/items.router.ts +0 -47
  17. package/templates/base/packages/items-module/src/ui/index.ts +0 -1
  18. /package/templates/base/packages/items-module/src/{client-module.ts → client/index.ts} +0 -0
  19. /package/templates/base/packages/items-module/src/{ui → client/ui}/ItemsPage.tsx +0 -0
  20. /package/templates/base/packages/items-module/src/{adapters → server/adapters}/item.drizzle.ts +0 -0
  21. /package/templates/base/packages/items-module/src/{domain → server/domain}/item.entity.ts +0 -0
  22. /package/templates/base/packages/items-module/src/{ports → server/ports}/item.repository.ts +0 -0
  23. /package/templates/base/packages/items-module/src/{usecases → server/usecases}/create-item.ts +0 -0
  24. /package/templates/base/packages/items-module/src/{usecases → server/usecases}/delete-item.ts +0 -0
  25. /package/templates/base/packages/items-module/src/{usecases → server/usecases}/get-item.ts +0 -0
  26. /package/templates/base/packages/items-module/src/{usecases → server/usecases}/list-items.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kuckit-app",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Create a new Kuckit application",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -83,7 +83,7 @@ import { createAuthClient } from 'better-auth/react'
83
83
  import config from '../kuckit.config'
84
84
 
85
85
  const authClient = createAuthClient({
86
- baseURL: import.meta.env.VITE_API_URL,
86
+ baseURL: import.meta.env.VITE_SERVER_URL,
87
87
  })
88
88
 
89
89
  const KuckitProvider = createKuckitWebProvider({
@@ -452,7 +452,7 @@ See `.env.example` for required variables:
452
452
  - `BETTER_AUTH_SECRET` - Auth session secret
453
453
  - `BETTER_AUTH_URL` - Auth callback URL
454
454
  - `PORT` - Server port (default: 3000)
455
- - `VITE_API_URL` - API URL for frontend
455
+ - `VITE_SERVER_URL` - API URL for frontend
456
456
 
457
457
  ## Troubleshooting
458
458
 
@@ -29,7 +29,7 @@ import { getClientModuleSpecs } from './modules.client'
29
29
  import './index.css'
30
30
 
31
31
  const KuckitApp = createKuckitWebProvider({
32
- serverUrl: import.meta.env.VITE_API_URL || 'http://localhost:3000',
32
+ serverUrl: import.meta.env.VITE_SERVER_URL || 'http://localhost:3000',
33
33
  modules: getClientModuleSpecs(),
34
34
  env: import.meta.env.MODE,
35
35
  routeTree,
@@ -1,4 +1,5 @@
1
1
  @import "tailwindcss";
2
+ @import "./kuckit-modules.css";
2
3
 
3
4
  @custom-variant dark (&:where(.dark, .dark *));
4
5
 
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Kuckit Module Styles Aggregator
3
+ *
4
+ * This file is managed by the kuckit CLI. Do not edit the section between
5
+ * the markers manually - it will be overwritten when modules are added/removed.
6
+ *
7
+ * Module styles are automatically injected here when you run:
8
+ * bunx kuckit add <module-name>
9
+ */
10
+
11
+ /* KUCKIT_MODULE_STYLES_START */
12
+ /* Module CSS imports will be injected here by the CLI */
13
+ /* KUCKIT_MODULE_STYLES_END */
@@ -6,7 +6,7 @@ import { getClientModuleSpecs } from './modules.client'
6
6
  import './index.css'
7
7
 
8
8
  const KuckitApp = createKuckitWebProvider({
9
- serverUrl: import.meta.env.VITE_API_URL || 'http://localhost:3000',
9
+ serverUrl: import.meta.env.VITE_SERVER_URL || 'http://localhost:3000',
10
10
  modules: getClientModuleSpecs(),
11
11
  env: import.meta.env.MODE,
12
12
  routeTree,
@@ -11,7 +11,7 @@ import { defineConfig } from '@kuckit/sdk/config'
11
11
  export default defineConfig({
12
12
  modules: [
13
13
  // KUCKIT_MODULES_START
14
- { package: '@__APP_NAME_KEBAB__/items-module', schemaDir: 'src/adapters' },
14
+ { package: '@__APP_NAME_KEBAB__/items-module' },
15
15
  // KUCKIT_MODULES_END
16
16
  ],
17
17
 
@@ -15,26 +15,74 @@ Use this module as a template when creating new modules.
15
15
 
16
16
  ```
17
17
  src/
18
- ├── domain/
19
- └── item.entity.ts # Entity schema (Zod)
20
- ├── ports/
21
- └── item.repository.ts # Repository interface
22
- ├── adapters/
23
- └── item.drizzle.ts # Drizzle implementation
24
- ├── usecases/
25
- │ ├── create-item.ts # Create item use case
26
- │ ├── get-item.ts # Get single item
27
- │ ├── list-items.ts # List all items
28
- └── delete-item.ts # Delete item
29
- ├── api/
30
- │ └── items.router.ts # oRPC router
31
- ├── ui/
32
- │ └── ItemsPage.tsx # React component
33
- ├── module.ts # Server module definition
34
- ├── client-module.ts # Client module definition
35
- └── index.ts # Public exports
18
+ ├── server/
19
+ ├── domain/
20
+ │ │ └── item.entity.ts # Entity schema (Zod)
21
+ ├── ports/
22
+ │ │ └── item.repository.ts # Repository interface
23
+ ├── adapters/
24
+ │ │ └── item.drizzle.ts # Drizzle implementation
25
+ │ ├── usecases/
26
+ ├── create-item.ts # Create item use case
27
+ ├── get-item.ts # Get single item
28
+ │ ├── list-items.ts # List all items
29
+ │ │ ├── update-item.ts # Update item
30
+ └── delete-item.ts # Delete item
31
+ ├── api/
32
+ └── items.router.ts # oRPC router
33
+ ├── config.ts # Module config with Zod schema
34
+ ├── module.ts # Server module definition
35
+ └── index.ts # Server exports
36
+ └── client/
37
+ ├── ui/
38
+ │ └── ItemsPage.tsx # React component
39
+ └── index.ts # Client module + exports
36
40
  ```
37
41
 
42
+ ## Configuration Options
43
+
44
+ | Option | Type | Default | Description |
45
+ | ------------------ | --------- | ------- | ------------------------------------------------ |
46
+ | `maxItemsPerPage` | `number` | `100` | Maximum items returned per list request (1-1000) |
47
+ | `enableSoftDelete` | `boolean` | `false` | Mark items as deleted instead of hard delete |
48
+
49
+ Configure via `kuckit.config.ts`:
50
+
51
+ ```typescript
52
+ modules: [
53
+ {
54
+ spec: itemsModule,
55
+ config: {
56
+ maxItemsPerPage: 50,
57
+ enableSoftDelete: true,
58
+ },
59
+ },
60
+ ]
61
+ ```
62
+
63
+ ## DI Registrations
64
+
65
+ | Token | Type | Lifetime | Description |
66
+ | ---------------- | ------------------- | -------- | --------------------------- |
67
+ | `itemRepository` | `ItemRepository` | Scoped | Data access for items table |
68
+ | `listItems` | `ListItemsUseCase` | Scoped | List items by user |
69
+ | `createItem` | `CreateItemUseCase` | Scoped | Create new item |
70
+ | `getItem` | `GetItemUseCase` | Scoped | Get single item by ID |
71
+ | `updateItem` | `UpdateItemUseCase` | Scoped | Update existing item |
72
+ | `deleteItem` | `DeleteItemUseCase` | Scoped | Delete item by ID |
73
+
74
+ ## API Endpoints
75
+
76
+ All endpoints require authentication (`protectedProcedure`).
77
+
78
+ | Endpoint | Method | Input | Output | Description |
79
+ | -------------- | ------ | ---------------------------------------- | ------------------- | ----------------- |
80
+ | `items.list` | RPC | `{}` | `Item[]` | List user's items |
81
+ | `items.get` | RPC | `{ id: string }` | `Item \| null` | Get item by ID |
82
+ | `items.create` | RPC | `{ name: string, description?: string }` | `Item` | Create new item |
83
+ | `items.update` | RPC | `{ id, name?, description? }` | `Item` | Update item |
84
+ | `items.delete` | RPC | `{ id: string }` | `{ success: bool }` | Delete item |
85
+
38
86
  ## Key Patterns
39
87
 
40
88
  ### Domain Layer
@@ -139,7 +187,7 @@ export const clientModules = [{ module: itemsClient }]
139
187
  The client module registers routes, navigation items, and slots:
140
188
 
141
189
  ```typescript
142
- // client-module.ts
190
+ // src/client/index.ts
143
191
  import { defineKuckitClientModule } from '@kuckit/sdk-react'
144
192
  import { ItemsPage } from './ui/ItemsPage'
145
193
 
@@ -147,23 +195,24 @@ export const kuckitClientModule = defineKuckitClientModule({
147
195
  id: 'items',
148
196
  displayName: 'Items',
149
197
 
150
- routes: [
151
- {
198
+ register(ctx) {
199
+ ctx.registerComponent('ItemsPage', ItemsPage)
200
+
201
+ ctx.addRoute({
152
202
  id: 'items-page',
153
203
  path: '/items',
154
204
  component: ItemsPage,
155
205
  meta: { requiresAuth: true },
156
- },
157
- ],
206
+ })
158
207
 
159
- navItems: [
160
- {
208
+ ctx.addNavItem({
161
209
  id: 'items-nav',
162
210
  label: 'Items',
163
- href: '/items',
164
- order: 20,
165
- },
166
- ],
211
+ path: '/items',
212
+ icon: 'list',
213
+ order: 10,
214
+ })
215
+ },
167
216
  })
168
217
  ```
169
218
 
@@ -172,7 +221,7 @@ export const kuckitClientModule = defineKuckitClientModule({
172
221
  Module components access the API via the `useRpc` hook:
173
222
 
174
223
  ```typescript
175
- // ui/ItemsPage.tsx
224
+ // src/client/ui/ItemsPage.tsx
176
225
  import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
177
226
  import { useRpc } from '@kuckit/sdk-react'
178
227
 
@@ -0,0 +1,132 @@
1
+ # Items Module
2
+
3
+ > **Reference implementation** of a Kuckit module demonstrating Clean Architecture patterns.
4
+
5
+ Use this module as a template when creating new modules for your Kuckit application.
6
+
7
+ ## Features
8
+
9
+ - **CRUD operations** for items with full validation
10
+ - **Clean Architecture** with domain, ports, adapters, use cases, and API layers
11
+ - **Type-safe API** using oRPC with Zod schemas
12
+ - **React components** with TanStack Query integration
13
+ - **Configurable** via `kuckit.config.ts`
14
+
15
+ ## Installation
16
+
17
+ The items-module is included by default in projects scaffolded with `create-kuckit-app`.
18
+
19
+ For manual installation:
20
+
21
+ ```bash
22
+ # Copy the module to your project
23
+ cp -r packages/items-module packages/your-module
24
+
25
+ # Update package.json name
26
+ # Edit packages/your-module/package.json
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Server Registration
32
+
33
+ ```typescript
34
+ // apps/server/src/config/modules.ts
35
+ import { kuckitModule as itemsModule } from '@your-app/items-module'
36
+
37
+ export const getModuleSpecs = () => [{ spec: itemsModule }]
38
+ ```
39
+
40
+ ### Client Registration
41
+
42
+ ```typescript
43
+ // apps/web/src/modules.client.ts
44
+ import { kuckitClientModule as itemsClient } from '@your-app/items-module/client'
45
+
46
+ export const clientModules = [{ module: itemsClient }]
47
+ ```
48
+
49
+ ### Database Setup
50
+
51
+ Add the module's schema to your Drizzle config:
52
+
53
+ ```typescript
54
+ // drizzle.config.ts
55
+ schema: [
56
+ './node_modules/@kuckit/db/dist/schema/auth.js',
57
+ './packages/items-module/src/server/adapters',
58
+ ],
59
+ ```
60
+
61
+ Then run migrations:
62
+
63
+ ```bash
64
+ bun run db:push # Development
65
+ bun run db:migrate # Production
66
+ ```
67
+
68
+ ## Configuration
69
+
70
+ Configure the module in `kuckit.config.ts`:
71
+
72
+ ```typescript
73
+ import { kuckitModule as itemsModule } from '@your-app/items-module'
74
+
75
+ export default defineKuckitConfig({
76
+ modules: [
77
+ {
78
+ spec: itemsModule,
79
+ config: {
80
+ maxItemsPerPage: 50, // Default: 100
81
+ enableSoftDelete: true, // Default: false
82
+ },
83
+ },
84
+ ],
85
+ })
86
+ ```
87
+
88
+ ## API Reference
89
+
90
+ All endpoints require authentication.
91
+
92
+ | Endpoint | Input | Output | Description |
93
+ | -------------- | ---------------------------------------- | -------------- | ----------------- |
94
+ | `items.list` | `{}` | `Item[]` | List user's items |
95
+ | `items.get` | `{ id: string }` | `Item \| null` | Get item by ID |
96
+ | `items.create` | `{ name: string, description?: string }` | `Item` | Create new item |
97
+ | `items.update` | `{ id, name?, description? }` | `Item` | Update item |
98
+ | `items.delete` | `{ id: string }` | `{ success }` | Delete item |
99
+
100
+ ## Project Structure
101
+
102
+ ```
103
+ src/
104
+ ├── server/ # Backend code
105
+ │ ├── domain/ # Entity schemas (Zod)
106
+ │ ├── ports/ # Repository interfaces
107
+ │ ├── adapters/ # Drizzle implementations
108
+ │ ├── usecases/ # Business logic
109
+ │ ├── api/ # oRPC router
110
+ │ ├── config.ts # Module configuration
111
+ │ └── module.ts # Server module definition
112
+ └── client/ # Frontend code
113
+ ├── ui/ # React components
114
+ └── index.ts # Client module definition
115
+ ```
116
+
117
+ ## Creating a New Module
118
+
119
+ 1. Copy this module: `cp -r packages/items-module packages/your-module`
120
+ 2. Update `package.json` name to `@your-app/your-module`
121
+ 3. Replace domain entities in `src/server/domain/`
122
+ 4. Update ports and adapters
123
+ 5. Implement use cases
124
+ 6. Create API router
125
+ 7. Register in both server and client configs
126
+ 8. Add schema path to `drizzle.config.ts`
127
+ 9. Run `bun run db:push`
128
+
129
+ ## Documentation
130
+
131
+ - [AGENTS.md](./AGENTS.md) - AI assistant guidance and detailed patterns
132
+ - [Kuckit SDK](https://github.com/draphonix/kuckit) - Framework documentation
@@ -3,22 +3,24 @@
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
5
  "type": "module",
6
- "main": "src/index.ts",
7
- "types": "src/index.ts",
6
+ "main": "src/server/module.ts",
7
+ "types": "src/server/module.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "types": "./src/index.ts",
11
- "default": "./src/index.ts"
10
+ "types": "./src/server/index.ts",
11
+ "default": "./src/server/index.ts"
12
12
  },
13
13
  "./client": {
14
- "types": "./src/client-module.ts",
15
- "default": "./src/client-module.ts"
16
- },
17
- "./ui": {
18
- "types": "./src/ui/index.ts",
19
- "default": "./src/ui/index.ts"
14
+ "types": "./src/client/index.ts",
15
+ "default": "./src/client/index.ts"
20
16
  }
21
17
  },
18
+ "kuckit": {
19
+ "id": "items",
20
+ "server": ".",
21
+ "client": "./client",
22
+ "schemaDir": "src/server/adapters"
23
+ },
22
24
  "peerDependencies": {
23
25
  "typescript": "^5"
24
26
  },
@@ -0,0 +1,74 @@
1
+ import { z } from 'zod'
2
+ import { protectedProcedure } from '@kuckit/api'
3
+ import { CreateItemInputSchema, UpdateItemInputSchema } from '../domain/item.entity'
4
+ import type { Item } from '../domain/item.entity'
5
+ import type { ListItemsInput, ListItemsOutput } from '../usecases/list-items'
6
+ import type { CreateItemUseCaseInput } from '../usecases/create-item'
7
+ import type { GetItemInput } from '../usecases/get-item'
8
+ import type { DeleteItemInput } from '../usecases/delete-item'
9
+ import type { UpdateItemUseCaseInput } from '../usecases/update-item'
10
+
11
+ /**
12
+ * Items cradle interface for DI resolution
13
+ */
14
+ interface ItemsCradle {
15
+ listItems: (input: ListItemsInput) => Promise<ListItemsOutput>
16
+ createItem: (input: CreateItemUseCaseInput) => Promise<Item>
17
+ getItem: (input: GetItemInput) => Promise<Item | null>
18
+ deleteItem: (input: DeleteItemInput) => Promise<boolean>
19
+ updateItem: (input: UpdateItemUseCaseInput) => Promise<Item>
20
+ }
21
+
22
+ /**
23
+ * Items oRPC router
24
+ * Provides CRUD operations for items
25
+ */
26
+ export const itemsRouter = {
27
+ list: protectedProcedure.input(z.object({})).handler(async ({ context }) => {
28
+ const userId = context.session?.user?.id
29
+ if (!userId) throw new Error('User not authenticated')
30
+
31
+ const { listItems } = context.di.cradle as ItemsCradle
32
+ return listItems({ userId })
33
+ }),
34
+
35
+ get: protectedProcedure
36
+ .input(z.object({ id: z.string() }))
37
+ .handler(async ({ input, context }) => {
38
+ const { getItem } = context.di.cradle as ItemsCradle
39
+ return getItem({ id: input.id })
40
+ }),
41
+
42
+ create: protectedProcedure.input(CreateItemInputSchema).handler(async ({ input, context }) => {
43
+ const userId = context.session?.user?.id
44
+ if (!userId) throw new Error('User not authenticated')
45
+
46
+ const { createItem } = context.di.cradle as ItemsCradle
47
+ return createItem({
48
+ name: input.name,
49
+ description: input.description,
50
+ userId,
51
+ })
52
+ }),
53
+
54
+ delete: protectedProcedure
55
+ .input(z.object({ id: z.string() }))
56
+ .handler(async ({ input, context }) => {
57
+ const { deleteItem } = context.di.cradle as ItemsCradle
58
+ const success = await deleteItem({ id: input.id })
59
+ return { success }
60
+ }),
61
+
62
+ update: protectedProcedure.input(UpdateItemInputSchema).handler(async ({ input, context }) => {
63
+ const userId = context.session?.user?.id
64
+ if (!userId) throw new Error('User not authenticated')
65
+
66
+ const { updateItem } = context.di.cradle as ItemsCradle
67
+ return updateItem({
68
+ id: input.id,
69
+ name: input.name,
70
+ description: input.description,
71
+ userId,
72
+ })
73
+ }),
74
+ }
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod'
2
+
3
+ /**
4
+ * Items module configuration schema
5
+ *
6
+ * This is an example module with minimal configuration.
7
+ * Real modules might include settings for:
8
+ * - Feature flags
9
+ * - Pagination limits
10
+ * - Cache TTLs
11
+ * - External service URLs
12
+ */
13
+ export const itemsModuleConfigSchema = z.object({
14
+ /**
15
+ * Maximum number of items to return per list request
16
+ * @default 100
17
+ */
18
+ maxItemsPerPage: z.number().min(1).max(1000).default(100),
19
+
20
+ /**
21
+ * Enable soft delete (mark as deleted instead of hard delete)
22
+ * @default false
23
+ */
24
+ enableSoftDelete: z.boolean().default(false),
25
+ })
26
+
27
+ export type ItemsModuleConfig = z.infer<typeof itemsModuleConfigSchema>
@@ -1,6 +1,6 @@
1
1
  // Server module exports
2
2
  export { kuckitModule } from './module'
3
- export type { ItemsModuleConfig } from './module'
3
+ export { itemsModuleConfigSchema, type ItemsModuleConfig } from './config'
4
4
 
5
5
  // Domain exports
6
6
  export * from './domain/item.entity'
@@ -1,8 +1,14 @@
1
1
  import { defineKuckitModule, asFunction, type KuckitModuleContext } from '@kuckit/sdk'
2
2
  import { itemsTable, makeItemRepository } from './adapters/item.drizzle'
3
3
  import { itemsRouter } from './api/items.router'
4
+ import { itemsModuleConfigSchema, type ItemsModuleConfig } from './config'
5
+ import { makeListItems } from './usecases/list-items'
6
+ import { makeCreateItem } from './usecases/create-item'
7
+ import { makeGetItem } from './usecases/get-item'
8
+ import { makeDeleteItem } from './usecases/delete-item'
9
+ import { makeUpdateItem } from './usecases/update-item'
4
10
 
5
- export type ItemsModuleConfig = Record<string, never>
11
+ export type { ItemsModuleConfig }
6
12
 
7
13
  /**
8
14
  * Items module - example Kuckit module demonstrating the full pattern
@@ -20,15 +26,29 @@ export const kuckitModule = defineKuckitModule<ItemsModuleConfig>({
20
26
  version: '0.1.0',
21
27
 
22
28
  async register(ctx: KuckitModuleContext<ItemsModuleConfig>) {
23
- const { container } = ctx
29
+ const { container, config } = ctx
30
+ const resolvedConfig = itemsModuleConfigSchema.parse(config ?? {})
24
31
 
25
32
  // Register schema for migrations
26
33
  ctx.registerSchema('items', itemsTable)
27
34
 
35
+ // Log configuration
36
+ const logger = container.resolve('logger')
37
+ logger.debug('Items module config', { config: resolvedConfig })
38
+
28
39
  // Register repository
29
40
  container.register({
30
41
  itemRepository: asFunction(({ db }) => makeItemRepository(db)).scoped(),
31
42
  })
43
+
44
+ // Register use cases
45
+ container.register({
46
+ listItems: asFunction(({ itemRepository }) => makeListItems({ itemRepository })).scoped(),
47
+ createItem: asFunction(({ itemRepository }) => makeCreateItem({ itemRepository })).scoped(),
48
+ getItem: asFunction(({ itemRepository }) => makeGetItem({ itemRepository })).scoped(),
49
+ deleteItem: asFunction(({ itemRepository }) => makeDeleteItem({ itemRepository })).scoped(),
50
+ updateItem: asFunction(({ itemRepository }) => makeUpdateItem({ itemRepository })).scoped(),
51
+ })
32
52
  },
33
53
 
34
54
  registerApi(ctx) {
@@ -0,0 +1,28 @@
1
+ import type { ItemRepository } from '../ports/item.repository'
2
+ import type { Item, UpdateItemInput } from '../domain/item.entity'
3
+
4
+ export interface UpdateItemUseCaseInput extends UpdateItemInput {
5
+ userId: string
6
+ }
7
+
8
+ interface UpdateItemDeps {
9
+ itemRepository: ItemRepository
10
+ }
11
+
12
+ /**
13
+ * Update item use case
14
+ * Validates ownership before allowing update
15
+ */
16
+ export function makeUpdateItem(deps: UpdateItemDeps) {
17
+ return async (input: UpdateItemUseCaseInput): Promise<Item> => {
18
+ const existing = await deps.itemRepository.findById(input.id)
19
+ if (!existing || existing.userId !== input.userId) {
20
+ throw new Error('Item not found')
21
+ }
22
+ const updated = await deps.itemRepository.update(input)
23
+ if (!updated) {
24
+ throw new Error('Failed to update item')
25
+ }
26
+ return updated
27
+ }
28
+ }
@@ -1,47 +0,0 @@
1
- import { z } from 'zod'
2
- import { protectedProcedure } from '@kuckit/api'
3
- import { CreateItemInputSchema } from '../domain/item.entity'
4
- import type { ItemRepository } from '../ports/item.repository'
5
-
6
- /**
7
- * Items oRPC router
8
- * Provides CRUD operations for items
9
- */
10
- export const itemsRouter = {
11
- list: protectedProcedure.input(z.object({})).handler(async ({ context }) => {
12
- const userId = context.session?.user?.id
13
- if (!userId) throw new Error('User not authenticated')
14
-
15
- // In a real app, you'd resolve this from the DI container
16
- const items = await context.di.resolve<ItemRepository>('itemRepository').findByUserId(userId)
17
- return items
18
- }),
19
-
20
- get: protectedProcedure
21
- .input(z.object({ id: z.string() }))
22
- .handler(async ({ input, context }) => {
23
- const item = await context.di.resolve<ItemRepository>('itemRepository').findById(input.id)
24
- return item
25
- }),
26
-
27
- create: protectedProcedure.input(CreateItemInputSchema).handler(async ({ input, context }) => {
28
- const userId = context.session?.user?.id
29
- if (!userId) throw new Error('User not authenticated')
30
-
31
- const id = crypto.randomUUID()
32
- const item = await context.di.resolve<ItemRepository>('itemRepository').create({
33
- id,
34
- name: input.name,
35
- description: input.description,
36
- userId,
37
- })
38
- return item
39
- }),
40
-
41
- delete: protectedProcedure
42
- .input(z.object({ id: z.string() }))
43
- .handler(async ({ input, context }) => {
44
- const success = await context.di.resolve<ItemRepository>('itemRepository').delete(input.id)
45
- return { success }
46
- }),
47
- }
@@ -1 +0,0 @@
1
- export { ItemsPage } from './ItemsPage'