sonamu 0.8.24 → 0.8.26
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/dist/api/__tests__/config.test.js +189 -0
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +7 -2
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +14 -10
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/auth/knex-adapter.d.ts +23 -0
- package/dist/auth/knex-adapter.d.ts.map +1 -0
- package/dist/auth/knex-adapter.js +163 -0
- package/dist/auth/plugins/wrappers/admin.d.ts +2 -2
- package/dist/bin/__tests__/ts-loader-register.test.js +45 -0
- package/dist/bin/cli.js +47 -9
- package/dist/bin/ts-loader-register.js +3 -29
- package/dist/bin/ts-loader-registration.d.ts +2 -0
- package/dist/bin/ts-loader-registration.d.ts.map +1 -0
- package/dist/bin/ts-loader-registration.js +42 -0
- package/dist/cone/cone-generator.js +3 -3
- package/dist/database/puri-subset.test-d.js +9 -1
- package/dist/database/puri-subset.types.d.ts +1 -1
- package/dist/database/puri-subset.types.d.ts.map +1 -1
- package/dist/database/puri-subset.types.js +1 -1
- package/dist/testing/fixture-generator.js +5 -5
- package/dist/ui/ai-client.js +2 -2
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +14 -14
- package/dist/ui/cdd-service.d.ts +15 -18
- package/dist/ui/cdd-service.d.ts.map +1 -1
- package/dist/ui/cdd-service.js +246 -222
- package/dist/ui/cdd-types.d.ts +41 -68
- package/dist/ui/cdd-types.d.ts.map +1 -1
- package/dist/ui/cdd-types.js +2 -2
- package/dist/ui-web/assets/index-CKo0Z2Iu.css +1 -0
- package/dist/ui-web/assets/{index-CxiydzeC.js → index-DK-2aacv.js} +83 -83
- package/dist/ui-web/index.html +2 -2
- package/package.json +6 -2
- package/src/api/__tests__/config.test.ts +225 -0
- package/src/api/config.ts +10 -4
- package/src/api/sonamu.ts +16 -13
- package/src/auth/index.ts +1 -0
- package/src/auth/knex-adapter.ts +208 -0
- package/src/bin/__tests__/ts-loader-register.test.ts +62 -0
- package/src/bin/cli.ts +52 -9
- package/src/bin/ts-loader-register.ts +2 -32
- package/src/bin/ts-loader-registration.ts +55 -0
- package/src/cone/cone-generator.ts +2 -2
- package/src/database/puri-subset.test-d.ts +102 -0
- package/src/database/puri-subset.types.ts +1 -1
- package/src/skills/commands/sonamu-skills.md +20 -0
- package/src/skills/sonamu/SKILL.md +179 -137
- package/src/skills/sonamu/ai-agents.md +69 -69
- package/src/skills/sonamu/api.md +147 -147
- package/src/skills/sonamu/auth-migration.md +220 -220
- package/src/skills/sonamu/auth-plugins.md +83 -83
- package/src/skills/sonamu/auth.md +106 -106
- package/src/skills/sonamu/cdd.md +65 -200
- package/src/skills/sonamu/cone.md +138 -138
- package/src/skills/sonamu/config.md +191 -191
- package/src/skills/sonamu/create-sonamu.md +66 -66
- package/src/skills/sonamu/database.md +158 -158
- package/src/skills/sonamu/entity-basic.md +292 -293
- package/src/skills/sonamu/entity-relations.md +246 -246
- package/src/skills/sonamu/entity-validation-checklist.md +124 -124
- package/src/skills/sonamu/fixture-cli.md +231 -231
- package/src/skills/sonamu/framework-change.md +37 -37
- package/src/skills/sonamu/frontend.md +223 -223
- package/src/skills/sonamu/i18n.md +82 -82
- package/src/skills/sonamu/migration.md +77 -77
- package/src/skills/sonamu/model.md +222 -222
- package/src/skills/sonamu/naite.md +86 -86
- package/src/skills/sonamu/project-init.md +228 -228
- package/src/skills/sonamu/puri.md +122 -122
- package/src/skills/sonamu/scaffolding.md +154 -154
- package/src/skills/sonamu/skill-contribution.md +124 -124
- package/src/skills/sonamu/subset.md +46 -46
- package/src/skills/sonamu/tasks.md +82 -82
- package/src/skills/sonamu/testing-devrunner.md +147 -147
- package/src/skills/sonamu/testing.md +673 -673
- package/src/skills/sonamu/upsert.md +79 -79
- package/src/skills/sonamu/vector.md +67 -67
- package/src/testing/fixture-generator.ts +4 -4
- package/src/ui/ai-client.ts +1 -1
- package/src/ui/api.ts +18 -17
- package/src/ui/cdd-service.ts +264 -254
- package/src/ui/cdd-types.ts +40 -75
- package/dist/ui-web/assets/index-BrQKU3j9.css +0 -1
- package/src/skills/sonamu/workflow.md +0 -317
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sonamu-scaffolding
|
|
3
|
-
description: Sonamu UI Scaffolding
|
|
3
|
+
description: Reference for using Sonamu UI Scaffolding. Common errors and solutions. Use when scaffolding models or views.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Scaffolding
|
|
6
|
+
# Scaffolding Troubleshooting
|
|
7
7
|
|
|
8
|
-
## CRITICAL: Scaffolding
|
|
8
|
+
## CRITICAL: Required Scaffolding Items
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
**The following 5 items must all be scaffolded for every entity:**
|
|
11
11
|
|
|
12
|
-
|
|
|
12
|
+
| Item | Description |
|
|
13
13
|
|------|------|
|
|
14
|
-
| `model` |
|
|
15
|
-
| `model_test` |
|
|
16
|
-
| `view_list` |
|
|
17
|
-
| `view_search_input` |
|
|
18
|
-
| `view_form` |
|
|
14
|
+
| `model` | CRUD model based on BaseModelClass |
|
|
15
|
+
| `model_test` | Model test file |
|
|
16
|
+
| `view_list` | List view component |
|
|
17
|
+
| `view_search_input` | Search input component |
|
|
18
|
+
| `view_form` | Create/edit form component |
|
|
19
19
|
|
|
20
|
-
**DO NOT:** model
|
|
20
|
+
**DO NOT:** scaffold only model and model_test and skip the view-related items
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
## Scaffolding
|
|
24
|
+
## Pre-Scaffolding Checklist
|
|
25
25
|
|
|
26
|
-
**`packages/api`**
|
|
26
|
+
Run from the **`packages/api`** directory:
|
|
27
27
|
|
|
28
|
-
1. **
|
|
29
|
-
2. **types.ts
|
|
30
|
-
3. **
|
|
31
|
-
4. **TypeScript
|
|
32
|
-
5.
|
|
28
|
+
1. **Wait for entity change detection**: After creating an entity, wait for the syncer to auto-generate `types.ts` (2-3 seconds)
|
|
29
|
+
2. **Check types.ts file**: If not auto-generated, create it manually
|
|
30
|
+
3. **Create and run migration**: Create migration from Sonamu UI → `pnpm sonamu migrate run`
|
|
31
|
+
4. **Complete TypeScript build**: Run `pnpm build` to generate `.js` files in `dist/`
|
|
32
|
+
5. **Restart dev server**: `pnpm dev` (restart required after build)
|
|
33
33
|
|
|
34
|
-
## Scaffolding
|
|
34
|
+
## Post-Scaffolding Required Checklist
|
|
35
35
|
|
|
36
|
-
**CRITICAL:
|
|
36
|
+
**CRITICAL: After scaffolding is complete, you must perform the following steps.**
|
|
37
37
|
|
|
38
|
-
### 1. Build
|
|
38
|
+
### 1. Build Test
|
|
39
39
|
```bash
|
|
40
40
|
cd packages/api
|
|
41
41
|
pnpm build
|
|
@@ -43,57 +43,57 @@ pnpm build
|
|
|
43
43
|
cd packages/web
|
|
44
44
|
pnpm build
|
|
45
45
|
```
|
|
46
|
-
- [ ] API
|
|
47
|
-
- [ ] Web
|
|
46
|
+
- [ ] API build succeeds
|
|
47
|
+
- [ ] Web build succeeds
|
|
48
48
|
|
|
49
|
-
### 2. Dev
|
|
49
|
+
### 2. Restart Dev Server
|
|
50
50
|
```bash
|
|
51
51
|
cd packages/api
|
|
52
52
|
pnpm dev
|
|
53
53
|
```
|
|
54
|
-
- [ ]
|
|
54
|
+
- [ ] Server running normally
|
|
55
55
|
|
|
56
|
-
### 3.
|
|
56
|
+
### 3. If Relations Exist (Add i18n Keys)
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
**Required**: Must be done if the entity has a BelongsToOne or any relation
|
|
59
59
|
|
|
60
60
|
```typescript
|
|
61
61
|
// packages/api/src/i18n/ko.ts
|
|
62
62
|
export default {
|
|
63
|
-
// ...
|
|
63
|
+
// ... existing keys
|
|
64
64
|
|
|
65
|
-
//
|
|
66
|
-
"entity.Post.author_id": "
|
|
67
|
-
"entity.Question.collection_id": "
|
|
68
|
-
"entity.Question.parent_id": "
|
|
69
|
-
"entity.Employee.department_id": "
|
|
70
|
-
"entity.Task.principal_investigator_id": "
|
|
65
|
+
// Add for each entity with relations
|
|
66
|
+
"entity.Post.author_id": "Author",
|
|
67
|
+
"entity.Question.collection_id": "Collection",
|
|
68
|
+
"entity.Question.parent_id": "Parent Question",
|
|
69
|
+
"entity.Employee.department_id": "Department",
|
|
70
|
+
"entity.Task.principal_investigator_id": "Principal Investigator",
|
|
71
71
|
|
|
72
72
|
// ...
|
|
73
73
|
} as const;
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
76
|
+
**Pattern**: `entity.{EntityId}.{relation}_id`
|
|
77
|
+
- Add `_id` suffix to the relation name
|
|
78
|
+
- Example: `author` relation → `author_id` key
|
|
79
79
|
|
|
80
|
-
- [ ]
|
|
80
|
+
- [ ] i18n keys added for all entities with relations
|
|
81
81
|
|
|
82
|
-
### 4. OrderBy
|
|
82
|
+
### 4. Add OrderBy Cases (When values other than id-desc are used)
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
**Optional**: Perform if the OrderBy enum in entity.json has values other than `id-desc`
|
|
85
85
|
|
|
86
86
|
```typescript
|
|
87
87
|
// packages/api/src/application/{entity}/{entity}.model.ts
|
|
88
88
|
|
|
89
|
-
//
|
|
89
|
+
// Generated code
|
|
90
90
|
if (params.orderBy === "id-desc") {
|
|
91
91
|
qb.orderBy("posts.id", "desc");
|
|
92
92
|
} else {
|
|
93
|
-
exhaustive(params.orderBy); //
|
|
93
|
+
exhaustive(params.orderBy); // type error!
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
//
|
|
96
|
+
// Fix: add the remaining cases
|
|
97
97
|
if (params.orderBy === "id-desc") {
|
|
98
98
|
qb.orderBy("posts.id", "desc");
|
|
99
99
|
} else if (params.orderBy === "created_at-desc") {
|
|
@@ -101,33 +101,33 @@ if (params.orderBy === "id-desc") {
|
|
|
101
101
|
} else if (params.orderBy === "name-asc") {
|
|
102
102
|
qb.orderBy("posts.name", "asc");
|
|
103
103
|
} else {
|
|
104
|
-
exhaustive(params.orderBy); //
|
|
104
|
+
exhaustive(params.orderBy); // no more type errors
|
|
105
105
|
}
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
- [ ] OrderBy
|
|
108
|
+
- [ ] OrderBy cases added
|
|
109
109
|
|
|
110
|
-
### 5. types.ts
|
|
110
|
+
### 5. Handle Nullable Fields in types.ts (Required Before Testing!)
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
**Required**: Handle nullable fields in types.ts for all entities
|
|
113
113
|
|
|
114
114
|
```typescript
|
|
115
115
|
// packages/api/src/application/{entity}/{entity}.types.ts
|
|
116
116
|
|
|
117
|
-
//
|
|
117
|
+
// Generated code
|
|
118
118
|
export const PostSaveParams = PostBaseSchema.partial({
|
|
119
119
|
id: true,
|
|
120
120
|
created_at: true,
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
//
|
|
123
|
+
// Fix: add nullable fields
|
|
124
124
|
export const PostSaveParams = PostBaseSchema
|
|
125
125
|
.partial({
|
|
126
126
|
id: true,
|
|
127
127
|
created_at: true,
|
|
128
|
-
updated_at: true, // nullable
|
|
129
|
-
category: true, // nullable
|
|
130
|
-
description: true, // nullable
|
|
128
|
+
updated_at: true, // nullable field
|
|
129
|
+
category: true, // nullable field
|
|
130
|
+
description: true, // nullable field
|
|
131
131
|
})
|
|
132
132
|
.extend({
|
|
133
133
|
updated_at: z.date().nullish(),
|
|
@@ -136,36 +136,36 @@ export const PostSaveParams = PostBaseSchema
|
|
|
136
136
|
});
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
**Detailed guide**: See "Tasks to do immediately after entity creation" in `testing.md`
|
|
140
140
|
|
|
141
|
-
- [ ]
|
|
141
|
+
- [ ] Nullable fields handled in types.ts for all entities
|
|
142
142
|
|
|
143
|
-
###
|
|
143
|
+
### Completion Confirmation
|
|
144
144
|
|
|
145
145
|
```
|
|
146
|
-
|
|
147
|
-
→
|
|
146
|
+
Post-scaffolding required checklist complete
|
|
147
|
+
→ Next step: write tests (testing.md)
|
|
148
148
|
|
|
149
|
-
⚠️ types.ts
|
|
150
|
-
|
|
149
|
+
⚠️ If nullable fields in types.ts are not handled,
|
|
150
|
+
type errors will occur when writing tests!
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
---
|
|
154
154
|
|
|
155
|
-
##
|
|
155
|
+
## Common Errors
|
|
156
156
|
|
|
157
|
-
|
|
|
157
|
+
| Error | Cause | Fix |
|
|
158
158
|
|------|------|------|
|
|
159
|
-
| "
|
|
160
|
-
| exhaustive()
|
|
161
|
-
| i18n
|
|
162
|
-
| IdAsyncSelect API
|
|
159
|
+
| "Non-existent module path requested {Type}" | types.ts not created or not compiled | Wait/create manually → build → restart dev |
|
|
160
|
+
| exhaustive() type error | Only the first OrderBy value is handled automatically | See "4. Add OrderBy Cases" above |
|
|
161
|
+
| Missing i18n key (relation) | `author_id` vs `author` | See "3. If Relations Exist" above |
|
|
162
|
+
| IdAsyncSelect API mismatch | Old scaffolding template used | See "IdAsyncSelect API Migration" below |
|
|
163
163
|
|
|
164
|
-
##
|
|
164
|
+
## Detailed Explanations
|
|
165
165
|
|
|
166
|
-
### "
|
|
166
|
+
### "Non-existent module path requested" Error
|
|
167
167
|
|
|
168
|
-
Scaffolding
|
|
168
|
+
Scaffolding reads types exported from `dist/application/{entity}/{entity}.types.js` to register module paths.
|
|
169
169
|
|
|
170
170
|
```typescript
|
|
171
171
|
// modules/sonamu/src/entity/entity.ts
|
|
@@ -174,16 +174,16 @@ const typesFilePath = path.join(
|
|
|
174
174
|
runtimePath(`dist/application/${typesModulePath}.js`),
|
|
175
175
|
);
|
|
176
176
|
if (await exists(typesFilePath)) {
|
|
177
|
-
//
|
|
177
|
+
// register type
|
|
178
178
|
}
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
-
### types.ts
|
|
181
|
+
### Automatic types.ts Generation Mechanism
|
|
182
182
|
|
|
183
|
-
|
|
183
|
+
When an entity is created, the syncer's `handleTruthSourceChanges` automatically runs the `init_types` template:
|
|
184
184
|
|
|
185
185
|
```typescript
|
|
186
|
-
// modules/sonamu/src/syncer/syncer.ts - handleTruthSourceChanges
|
|
186
|
+
// modules/sonamu/src/syncer/syncer.ts - handleTruthSourceChanges function
|
|
187
187
|
if (entityId) {
|
|
188
188
|
const entity = EntityManager.get(entityId);
|
|
189
189
|
const typeFilePath = path.join(...);
|
|
@@ -193,25 +193,25 @@ if (entityId) {
|
|
|
193
193
|
}
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
- `parentId
|
|
198
|
-
- `types.ts`
|
|
196
|
+
**Auto-generation conditions**:
|
|
197
|
+
- When `parentId` is absent (top-level entity)
|
|
198
|
+
- When the `types.ts` file does not yet exist
|
|
199
199
|
|
|
200
|
-
|
|
201
|
-
-
|
|
202
|
-
- types.ts
|
|
200
|
+
**Causes of errors**:
|
|
201
|
+
- Attempting scaffolding immediately after entity creation before the syncer has run
|
|
202
|
+
- types.ts was created but the build has not completed so the `.js` file is missing
|
|
203
203
|
|
|
204
|
-
|
|
205
|
-
1.
|
|
206
|
-
2. types.ts
|
|
207
|
-
3.
|
|
208
|
-
4. `pnpm build
|
|
209
|
-
5. `pnpm dev`
|
|
210
|
-
6.
|
|
204
|
+
**Resolution order** (run from `packages/api`):
|
|
205
|
+
1. Wait briefly after entity creation for the syncer to generate types.ts (2-3 seconds)
|
|
206
|
+
2. If types.ts is missing, create it manually (see template below)
|
|
207
|
+
3. Create migration (Sonamu UI) and run it (`pnpm sonamu migrate run`)
|
|
208
|
+
4. Compile TypeScript with `pnpm build`
|
|
209
|
+
5. Restart `pnpm dev`
|
|
210
|
+
6. Retry scaffolding
|
|
211
211
|
|
|
212
|
-
### types.ts
|
|
212
|
+
### Manual types.ts Creation (If Needed)
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
For cases where auto-generation did not occur due to a syncer timing issue:
|
|
215
215
|
|
|
216
216
|
```typescript
|
|
217
217
|
// {entity}.types.ts
|
|
@@ -229,38 +229,38 @@ export type {Entity}SaveParams = z.infer<typeof {Entity}SaveParams>;
|
|
|
229
229
|
|
|
230
230
|
**IMPORTANT: Entity with `updated_at` field**:
|
|
231
231
|
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
If the entity has an `updated_at` field defined, it must also be included in the partial of SaveParams.
|
|
233
|
+
Since the form does not accept `updated_at` as direct input, it must be optional to avoid type errors.
|
|
234
234
|
|
|
235
235
|
```typescript
|
|
236
|
-
//
|
|
236
|
+
// For entities with updated_at
|
|
237
237
|
export const {Entity}SaveParams = {Entity}BaseSchema.partial({
|
|
238
238
|
id: true,
|
|
239
239
|
created_at: true,
|
|
240
|
-
updated_at: true // ←
|
|
240
|
+
updated_at: true // ← add this
|
|
241
241
|
});
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
-
### exhaustive()
|
|
244
|
+
### exhaustive() Type Error
|
|
245
245
|
|
|
246
|
-
`exhaustive
|
|
246
|
+
`exhaustive` is a utility function provided by sonamu.
|
|
247
247
|
|
|
248
248
|
```typescript
|
|
249
249
|
import { exhaustive } from "sonamu";
|
|
250
250
|
```
|
|
251
251
|
|
|
252
|
-
|
|
252
|
+
The scaffolding template only handles the **first value** of the `OrderBy` enum automatically.
|
|
253
253
|
|
|
254
254
|
```typescript
|
|
255
|
-
//
|
|
255
|
+
// Generated code
|
|
256
256
|
if (params.orderBy === "id-desc") {
|
|
257
257
|
qb.orderBy("posts.id", "desc");
|
|
258
258
|
} else {
|
|
259
|
-
exhaustive(params.orderBy); //
|
|
259
|
+
exhaustive(params.orderBy); // remaining cases unhandled → type error
|
|
260
260
|
}
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
-
|
|
263
|
+
**Fix**: Manually add all OrderBy cases
|
|
264
264
|
|
|
265
265
|
```typescript
|
|
266
266
|
if (params.orderBy === "id-desc") {
|
|
@@ -272,63 +272,63 @@ if (params.orderBy === "id-desc") {
|
|
|
272
272
|
}
|
|
273
273
|
```
|
|
274
274
|
|
|
275
|
-
### i18n
|
|
275
|
+
### i18n Key Error (relation prop)
|
|
276
276
|
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
An entity's relation prop is defined as `author`, and the i18n label in `sd.generated.ts` is generated as `entity.Post.author`.
|
|
278
|
+
**However**, the scaffolded form.tsx template uses the FK column name `author_id`.
|
|
279
279
|
|
|
280
280
|
```typescript
|
|
281
|
-
//
|
|
282
|
-
{SD("entity.Post.author_id")} // ← _id
|
|
281
|
+
// Scaffolded form.tsx (actually generated code)
|
|
282
|
+
{SD("entity.Post.author_id")} // ← uses _id suffix
|
|
283
283
|
|
|
284
|
-
// sd.generated.ts (
|
|
285
|
-
"entity.Post.author": "
|
|
284
|
+
// sd.generated.ts (auto-generated keys)
|
|
285
|
+
"entity.Post.author": "Author" // ← no _id
|
|
286
286
|
```
|
|
287
287
|
|
|
288
|
-
|
|
288
|
+
**Fix (choose one)**:
|
|
289
289
|
|
|
290
|
-
1. **
|
|
290
|
+
1. **Manually add `_id` key to ko.ts** (recommended):
|
|
291
291
|
```typescript
|
|
292
292
|
// packages/api/src/i18n/ko.ts
|
|
293
293
|
export default {
|
|
294
|
-
// ...
|
|
295
|
-
"entity.Post.author_id": "
|
|
296
|
-
"entity.Question.collection_id": "
|
|
297
|
-
"entity.Question.parent_id": "
|
|
294
|
+
// ... existing keys
|
|
295
|
+
"entity.Post.author_id": "Author",
|
|
296
|
+
"entity.Question.collection_id": "Collection",
|
|
297
|
+
"entity.Question.parent_id": "Parent Question",
|
|
298
298
|
// ...
|
|
299
299
|
} as const;
|
|
300
300
|
```
|
|
301
301
|
|
|
302
|
-
2. **
|
|
302
|
+
2. **Remove `_id` from form.tsx** (requires manual edit):
|
|
303
303
|
```typescript
|
|
304
|
-
//
|
|
305
|
-
{SD("entity.Post.author")} // _id
|
|
304
|
+
// Manual edit after scaffolding
|
|
305
|
+
{SD("entity.Post.author")} // remove _id
|
|
306
306
|
```
|
|
307
307
|
|
|
308
|
-
|
|
308
|
+
**Recommended**: First option - add the `_id` key to ko.ts. It is preserved during sync and can be reused across multiple forms.
|
|
309
309
|
|
|
310
|
-
### IdAsyncSelect API
|
|
310
|
+
### IdAsyncSelect API Migration
|
|
311
311
|
|
|
312
|
-
####
|
|
312
|
+
#### Background
|
|
313
313
|
|
|
314
|
-
|
|
314
|
+
When the `@sonamu-kit/react-components` package was updated, the IdAsyncSelect API changed, but the scaffolding generation code (`scaffolding/react-components.ts`) still generates code based on the old API.
|
|
315
315
|
|
|
316
|
-
|
|
316
|
+
Therefore, running `pnpm sonamu scaffold` generates wrapper components based on the old API, causing build errors in projects using the latest package.
|
|
317
317
|
|
|
318
|
-
####
|
|
318
|
+
#### Specific API Changes
|
|
319
319
|
|
|
320
|
-
|
|
320
|
+
**Old API (code generated by scaffolding):**
|
|
321
321
|
```typescript
|
|
322
322
|
export function UserIdAsyncSelect<T extends UserSubsetKey>({
|
|
323
323
|
subset,
|
|
324
324
|
value,
|
|
325
325
|
onValueChange,
|
|
326
|
-
listParams, // ←
|
|
327
|
-
textField = "name", // ←
|
|
328
|
-
pageField, // ←
|
|
326
|
+
listParams, // ← old API
|
|
327
|
+
textField = "name", // ← old API
|
|
328
|
+
pageField, // ← old API
|
|
329
329
|
...
|
|
330
330
|
}: UserIdAsyncSelectProps<T>) {
|
|
331
|
-
//
|
|
331
|
+
// manual state management
|
|
332
332
|
const [searchText, setSearchText] = useState("");
|
|
333
333
|
|
|
334
334
|
const handleSearch = useCallback((text: string) => {
|
|
@@ -336,7 +336,7 @@ export function UserIdAsyncSelect<T extends UserSubsetKey>({
|
|
|
336
336
|
}, []);
|
|
337
337
|
|
|
338
338
|
return (
|
|
339
|
-
<AsyncSelect // ←
|
|
339
|
+
<AsyncSelect // ← old component
|
|
340
340
|
config={UserAsyncIdConfig}
|
|
341
341
|
subset={subset}
|
|
342
342
|
listParams={{ ...listParams, [textField]: searchText }}
|
|
@@ -349,71 +349,71 @@ export function UserIdAsyncSelect<T extends UserSubsetKey>({
|
|
|
349
349
|
}
|
|
350
350
|
```
|
|
351
351
|
|
|
352
|
-
|
|
352
|
+
**New API (actual package API):**
|
|
353
353
|
```typescript
|
|
354
354
|
export function UserIdAsyncSelect<T extends UserSubsetKey>({
|
|
355
355
|
subset,
|
|
356
356
|
value,
|
|
357
357
|
onValueChange,
|
|
358
|
-
baseListParams, // ←
|
|
359
|
-
displayField = "name", // ←
|
|
360
|
-
// pageField
|
|
358
|
+
baseListParams, // ← new API
|
|
359
|
+
displayField = "name", // ← new API
|
|
360
|
+
// pageField removed // ← removed
|
|
361
361
|
...
|
|
362
362
|
}: UserIdAsyncSelectProps<T>) {
|
|
363
|
-
//
|
|
363
|
+
// no state management (handled internally)
|
|
364
364
|
|
|
365
365
|
return (
|
|
366
|
-
<IdAsyncSelect<number> // ←
|
|
366
|
+
<IdAsyncSelect<number> // ← new component + generic
|
|
367
367
|
config={UserAsyncIdConfig}
|
|
368
368
|
subset={subset}
|
|
369
369
|
baseListParams={baseListParams}
|
|
370
370
|
displayField={displayField}
|
|
371
|
-
//
|
|
371
|
+
// search handled internally
|
|
372
372
|
...
|
|
373
373
|
/>
|
|
374
374
|
);
|
|
375
375
|
}
|
|
376
376
|
```
|
|
377
377
|
|
|
378
|
-
####
|
|
378
|
+
#### Key Changes
|
|
379
379
|
|
|
380
|
-
1.
|
|
381
|
-
2. **
|
|
380
|
+
1. **Component name**: `AsyncSelect` → `IdAsyncSelect<T>` (generic added)
|
|
381
|
+
2. **Prop names**:
|
|
382
382
|
- `listParams` → `baseListParams`
|
|
383
383
|
- `textField` → `displayField`
|
|
384
|
-
- `pageField`
|
|
385
|
-
3.
|
|
386
|
-
4.
|
|
384
|
+
- `pageField` removed
|
|
385
|
+
3. **Search logic**: external state management → internal handling (useState, useCallback, onSearch no longer needed)
|
|
386
|
+
4. **Generic type**: PK type must be specified explicitly (`<number>` or `<string>`)
|
|
387
387
|
|
|
388
|
-
####
|
|
388
|
+
#### Files That Need Updating
|
|
389
389
|
|
|
390
390
|
```
|
|
391
391
|
src/components/
|
|
392
392
|
├── user/UserIdAsyncSelect.tsx
|
|
393
393
|
├── account/AccountIdAsyncSelect.tsx
|
|
394
394
|
├── announcement/AnnouncementIdAsyncSelect.tsx
|
|
395
|
-
└── ... (
|
|
395
|
+
└── ... (all *IdAsyncSelect.tsx files)
|
|
396
396
|
```
|
|
397
397
|
|
|
398
|
-
####
|
|
398
|
+
#### Migration Checklist
|
|
399
399
|
|
|
400
|
-
- [ ]
|
|
401
|
-
- [ ]
|
|
402
|
-
- [ ] Props
|
|
400
|
+
- [ ] Change component import: `AsyncSelect` → `IdAsyncSelect`
|
|
401
|
+
- [ ] Add generic type parameter: `<number>` or `<string>` (depending on PK type)
|
|
402
|
+
- [ ] Update Props type definitions:
|
|
403
403
|
- [ ] `listParams` → `baseListParams`
|
|
404
404
|
- [ ] `textField` → `displayField`
|
|
405
|
-
- [ ] `pageField`
|
|
406
|
-
- [ ]
|
|
407
|
-
- [ ] `useState`, `useCallback`
|
|
408
|
-
- [ ] `onSearch`
|
|
409
|
-
- [ ]
|
|
405
|
+
- [ ] Remove `pageField`
|
|
406
|
+
- [ ] Remove manual state management:
|
|
407
|
+
- [ ] Remove `useState`, `useCallback`
|
|
408
|
+
- [ ] Remove `onSearch` handler
|
|
409
|
+
- [ ] Update prop names in JSX:
|
|
410
410
|
- [ ] `listParams={...}` → `baseListParams={...}`
|
|
411
411
|
- [ ] `textField={...}` → `displayField={...}`
|
|
412
|
-
- [ ] `pageField`
|
|
413
|
-
- [ ] `onSearch`
|
|
412
|
+
- [ ] Remove `pageField`
|
|
413
|
+
- [ ] Remove `onSearch`
|
|
414
414
|
|
|
415
|
-
####
|
|
415
|
+
#### Why does this happen?
|
|
416
416
|
|
|
417
|
-
|
|
417
|
+
This occurs when the scaffolding generation code in Sonamu has not been updated to reflect the latest package API, while the user has modified the local Sonamu source and the package has been updated but the scaffolding template has not.
|
|
418
418
|
|
|
419
|
-
|
|
419
|
+
**Fix**: Manually update the generated components according to the checklist above, or update the scaffolding template in the Sonamu core to use the latest API.
|