sonamu 0.7.53 → 0.8.0

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 (271) hide show
  1. package/dist/api/config.d.ts +9 -1
  2. package/dist/api/config.d.ts.map +1 -1
  3. package/dist/api/config.js +1 -1
  4. package/dist/api/sonamu.d.ts +21 -1
  5. package/dist/api/sonamu.d.ts.map +1 -1
  6. package/dist/api/sonamu.js +159 -65
  7. package/dist/auth/plugins/entity-definitions/anonymous.d.ts +10 -0
  8. package/dist/auth/plugins/entity-definitions/anonymous.d.ts.map +1 -0
  9. package/dist/auth/plugins/entity-definitions/anonymous.js +23 -0
  10. package/dist/auth/plugins/entity-definitions/api-key.d.ts +9 -0
  11. package/dist/auth/plugins/entity-definitions/api-key.d.ts.map +1 -0
  12. package/dist/auth/plugins/entity-definitions/api-key.js +199 -0
  13. package/dist/auth/plugins/entity-definitions/index.d.ts +6 -0
  14. package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
  15. package/dist/auth/plugins/entity-definitions/index.js +20 -2
  16. package/dist/auth/plugins/entity-definitions/jwt.d.ts +9 -0
  17. package/dist/auth/plugins/entity-definitions/jwt.d.ts.map +1 -0
  18. package/dist/auth/plugins/entity-definitions/jwt.js +67 -0
  19. package/dist/auth/plugins/entity-definitions/organization.d.ts +9 -0
  20. package/dist/auth/plugins/entity-definitions/organization.d.ts.map +1 -0
  21. package/dist/auth/plugins/entity-definitions/organization.js +424 -0
  22. package/dist/auth/plugins/entity-definitions/passkey.d.ts +10 -0
  23. package/dist/auth/plugins/entity-definitions/passkey.d.ts.map +1 -0
  24. package/dist/auth/plugins/entity-definitions/passkey.js +129 -0
  25. package/dist/auth/plugins/entity-definitions/sso.d.ts +10 -0
  26. package/dist/auth/plugins/entity-definitions/sso.d.ts.map +1 -0
  27. package/dist/auth/plugins/entity-definitions/sso.js +110 -0
  28. package/dist/auth/plugins/entity-definitions/types.d.ts +1 -1
  29. package/dist/auth/plugins/entity-definitions/types.d.ts.map +1 -1
  30. package/dist/auth/plugins/entity-definitions/types.js +1 -1
  31. package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
  32. package/dist/auth/plugins/wrappers/admin.js +2 -4
  33. package/dist/auth/plugins/wrappers/anonymous.d.ts +18 -0
  34. package/dist/auth/plugins/wrappers/anonymous.d.ts.map +1 -0
  35. package/dist/auth/plugins/wrappers/anonymous.js +26 -0
  36. package/dist/auth/plugins/wrappers/api-key.d.ts +18 -0
  37. package/dist/auth/plugins/wrappers/api-key.d.ts.map +1 -0
  38. package/dist/auth/plugins/wrappers/api-key.js +38 -0
  39. package/dist/auth/plugins/wrappers/index.d.ts +6 -0
  40. package/dist/auth/plugins/wrappers/index.d.ts.map +1 -1
  41. package/dist/auth/plugins/wrappers/index.js +7 -1
  42. package/dist/auth/plugins/wrappers/jwt.d.ts +18 -0
  43. package/dist/auth/plugins/wrappers/jwt.d.ts.map +1 -0
  44. package/dist/auth/plugins/wrappers/jwt.js +30 -0
  45. package/dist/auth/plugins/wrappers/organization.d.ts +18 -0
  46. package/dist/auth/plugins/wrappers/organization.d.ts.map +1 -0
  47. package/dist/auth/plugins/wrappers/organization.js +67 -0
  48. package/dist/auth/plugins/wrappers/passkey.d.ts +18 -0
  49. package/dist/auth/plugins/wrappers/passkey.d.ts.map +1 -0
  50. package/dist/auth/plugins/wrappers/passkey.js +32 -0
  51. package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
  52. package/dist/auth/plugins/wrappers/phone-number.js +2 -4
  53. package/dist/auth/plugins/wrappers/sso.d.ts +853 -0
  54. package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -0
  55. package/dist/auth/plugins/wrappers/sso.js +36 -0
  56. package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
  57. package/dist/auth/plugins/wrappers/two-factor.js +2 -4
  58. package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
  59. package/dist/auth/plugins/wrappers/username.js +2 -4
  60. package/dist/bin/build-config.d.ts +2 -2
  61. package/dist/bin/build-config.js +6 -7
  62. package/dist/bin/cli.js +417 -32
  63. package/dist/bin/fixture.d.ts +27 -0
  64. package/dist/bin/fixture.d.ts.map +1 -0
  65. package/dist/bin/fixture.js +245 -0
  66. package/dist/cache/decorator.d.ts +4 -3
  67. package/dist/cache/decorator.d.ts.map +1 -1
  68. package/dist/cache/decorator.js +5 -4
  69. package/dist/cone/cone-generator.d.ts +33 -0
  70. package/dist/cone/cone-generator.d.ts.map +1 -0
  71. package/dist/cone/cone-generator.js +286 -0
  72. package/dist/database/_batch_update.d.ts.map +1 -1
  73. package/dist/database/_batch_update.js +16 -2
  74. package/dist/database/puri-subset.test-d.js +1 -1
  75. package/dist/database/puri-subset.types.d.ts +1 -1
  76. package/dist/database/puri-subset.types.d.ts.map +1 -1
  77. package/dist/database/puri-subset.types.js +1 -1
  78. package/dist/database/puri.d.ts +4 -0
  79. package/dist/database/puri.d.ts.map +1 -1
  80. package/dist/database/puri.js +20 -2
  81. package/dist/database/upsert-builder.d.ts.map +1 -1
  82. package/dist/database/upsert-builder.js +19 -3
  83. package/dist/dict/en.d.ts +15 -0
  84. package/dist/dict/en.d.ts.map +1 -1
  85. package/dist/dict/en.js +2 -1
  86. package/dist/dict/ko.d.ts +15 -0
  87. package/dist/dict/ko.d.ts.map +1 -1
  88. package/dist/dict/ko.js +2 -1
  89. package/dist/dict/rc-keys.d.ts +28 -0
  90. package/dist/dict/rc-keys.d.ts.map +1 -1
  91. package/dist/dict/rc-keys.js +31 -1
  92. package/dist/dict/sd.d.ts.map +1 -1
  93. package/dist/dict/sd.js +20 -4
  94. package/dist/entity/entity-manager.d.ts +298 -2
  95. package/dist/entity/entity-manager.d.ts.map +1 -1
  96. package/dist/entity/entity-manager.js +4 -1
  97. package/dist/entity/entity-template-cone.d.ts +14 -0
  98. package/dist/entity/entity-template-cone.d.ts.map +1 -0
  99. package/dist/entity/entity-template-cone.js +222 -0
  100. package/dist/entity/entity.d.ts +47 -2
  101. package/dist/entity/entity.d.ts.map +1 -1
  102. package/dist/entity/entity.js +161 -14
  103. package/dist/ssr/renderer.js +3 -3
  104. package/dist/syncer/api-parser.js +12 -1
  105. package/dist/syncer/checksum.d.ts +0 -14
  106. package/dist/syncer/checksum.d.ts.map +1 -1
  107. package/dist/syncer/checksum.js +1 -23
  108. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  109. package/dist/syncer/syncer-actions.js +8 -2
  110. package/dist/syncer/syncer.d.ts +1 -1
  111. package/dist/syncer/syncer.d.ts.map +1 -1
  112. package/dist/syncer/syncer.js +17 -10
  113. package/dist/tasks/workflow-manager.d.ts +13 -1
  114. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  115. package/dist/tasks/workflow-manager.js +18 -1
  116. package/dist/template/entity-converter.js +4 -4
  117. package/dist/template/helpers.d.ts +10 -0
  118. package/dist/template/helpers.d.ts.map +1 -1
  119. package/dist/template/helpers.js +48 -1
  120. package/dist/template/implementations/entry-server.template.d.ts +1 -1
  121. package/dist/template/implementations/entry-server.template.js +7 -2
  122. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  123. package/dist/template/implementations/generated.template.js +5 -1
  124. package/dist/template/implementations/generated_http.template.d.ts +1 -0
  125. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  126. package/dist/template/implementations/generated_http.template.js +6 -2
  127. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  128. package/dist/template/implementations/generated_sso.template.js +29 -8
  129. package/dist/template/implementations/queries.template.d.ts.map +1 -1
  130. package/dist/template/implementations/queries.template.js +9 -1
  131. package/dist/template/implementations/sd.template.d.ts +1 -1
  132. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  133. package/dist/template/implementations/sd.template.js +28 -4
  134. package/dist/template/implementations/services.template.d.ts.map +1 -1
  135. package/dist/template/implementations/services.template.js +12 -12
  136. package/dist/template/implementations/view_form.template.d.ts +11 -7
  137. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  138. package/dist/template/implementations/view_form.template.js +97 -87
  139. package/dist/template/implementations/view_list.template.d.ts +3 -3
  140. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  141. package/dist/template/implementations/view_list.template.js +115 -109
  142. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
  143. package/dist/template/implementations/view_search_input.template.js +18 -14
  144. package/dist/template/zod-converter.d.ts.map +1 -1
  145. package/dist/template/zod-converter.js +95 -7
  146. package/dist/testing/_relation-graph.js +1 -1
  147. package/dist/testing/data-explorer.d.ts +61 -0
  148. package/dist/testing/data-explorer.d.ts.map +1 -0
  149. package/dist/testing/data-explorer.js +274 -0
  150. package/dist/testing/faker-mappings.d.ts +20 -0
  151. package/dist/testing/faker-mappings.d.ts.map +1 -0
  152. package/dist/testing/faker-mappings.js +421 -0
  153. package/dist/testing/fixture-generator.d.ts +161 -0
  154. package/dist/testing/fixture-generator.d.ts.map +1 -0
  155. package/dist/testing/fixture-generator.js +954 -0
  156. package/dist/testing/fixture-manager.d.ts +6 -1
  157. package/dist/testing/fixture-manager.d.ts.map +1 -1
  158. package/dist/testing/fixture-manager.js +72 -4
  159. package/dist/testing/index.d.ts +3 -0
  160. package/dist/testing/index.d.ts.map +1 -1
  161. package/dist/testing/index.js +4 -1
  162. package/dist/types/types.d.ts +1520 -26
  163. package/dist/types/types.d.ts.map +1 -1
  164. package/dist/types/types.js +136 -22
  165. package/dist/ui/ai-client.d.ts.map +1 -1
  166. package/dist/ui/ai-client.js +9 -4
  167. package/dist/ui/api.d.ts.map +1 -1
  168. package/dist/ui/api.js +303 -24
  169. package/dist/ui-web/assets/index-CsUr-_pV.js +254 -0
  170. package/dist/ui-web/assets/index-T42zzs1K.css +1 -0
  171. package/dist/ui-web/index.html +2 -2
  172. package/dist/utils/fs-utils.d.ts +2 -1
  173. package/dist/utils/fs-utils.d.ts.map +1 -1
  174. package/dist/utils/fs-utils.js +14 -3
  175. package/package.json +19 -11
  176. package/src/api/config.ts +12 -1
  177. package/src/api/sonamu.ts +179 -65
  178. package/src/auth/plugins/entity-definitions/anonymous.ts +17 -0
  179. package/src/auth/plugins/entity-definitions/api-key.ts +93 -0
  180. package/src/auth/plugins/entity-definitions/index.ts +18 -0
  181. package/src/auth/plugins/entity-definitions/jwt.ts +35 -0
  182. package/src/auth/plugins/entity-definitions/organization.ts +215 -0
  183. package/src/auth/plugins/entity-definitions/passkey.ts +64 -0
  184. package/src/auth/plugins/entity-definitions/sso.ts +62 -0
  185. package/src/auth/plugins/entity-definitions/types.ts +11 -1
  186. package/src/auth/plugins/wrappers/admin.ts +1 -3
  187. package/src/auth/plugins/wrappers/anonymous.ts +30 -0
  188. package/src/auth/plugins/wrappers/api-key.ts +42 -0
  189. package/src/auth/plugins/wrappers/index.ts +6 -0
  190. package/src/auth/plugins/wrappers/jwt.ts +34 -0
  191. package/src/auth/plugins/wrappers/organization.ts +73 -0
  192. package/src/auth/plugins/wrappers/passkey.ts +36 -0
  193. package/src/auth/plugins/wrappers/phone-number.ts +1 -3
  194. package/src/auth/plugins/wrappers/sso.ts +40 -0
  195. package/src/auth/plugins/wrappers/two-factor.ts +1 -3
  196. package/src/auth/plugins/wrappers/username.ts +1 -3
  197. package/src/bin/build-config.ts +6 -6
  198. package/src/bin/cli.ts +452 -31
  199. package/src/bin/fixture.ts +302 -0
  200. package/src/cache/decorator.ts +4 -3
  201. package/src/cone/cone-generator.ts +363 -0
  202. package/src/database/_batch_update.ts +11 -0
  203. package/src/database/puri-subset.test-d.ts +13 -13
  204. package/src/database/puri-subset.types.ts +1 -1
  205. package/src/database/puri.ts +43 -1
  206. package/src/database/upsert-builder.ts +16 -2
  207. package/src/dict/en.ts +1 -0
  208. package/src/dict/ko.ts +1 -0
  209. package/src/dict/rc-keys.ts +32 -0
  210. package/src/dict/sd.ts +23 -3
  211. package/src/entity/entity-manager.ts +4 -0
  212. package/src/entity/entity-template-cone.ts +298 -0
  213. package/src/entity/entity.ts +189 -13
  214. package/src/shared/app.shared.ts.txt +5 -0
  215. package/src/shared/web.shared.ts.txt +9 -5
  216. package/src/skills/project/README.md +21 -0
  217. package/src/skills/project/architecture.md +373 -0
  218. package/src/skills/project/business-logic.md +270 -0
  219. package/src/skills/project/requirements.md +160 -0
  220. package/src/skills/sonamu/SKILL.md +168 -3
  221. package/src/skills/sonamu/api.md +102 -0
  222. package/src/skills/sonamu/database.md +220 -1
  223. package/src/skills/sonamu/entity-relations.md +89 -1
  224. package/src/skills/sonamu/fixture-cli.md +501 -0
  225. package/src/skills/sonamu/frontend.md +214 -0
  226. package/src/skills/sonamu/i18n.md +95 -0
  227. package/src/skills/sonamu/model.md +153 -0
  228. package/src/skills/sonamu/project-init.md +178 -8
  229. package/src/skills/sonamu/scaffolding.md +112 -0
  230. package/src/skills/sonamu/subset.md +9 -3
  231. package/src/skills/sonamu/testing.md +287 -2
  232. package/src/skills/sonamu/workflow.md +70 -5
  233. package/src/ssr/renderer.ts +2 -2
  234. package/src/syncer/api-parser.ts +12 -0
  235. package/src/syncer/checksum.ts +0 -38
  236. package/src/syncer/syncer-actions.ts +7 -1
  237. package/src/syncer/syncer.ts +16 -5
  238. package/src/tasks/workflow-manager.ts +29 -8
  239. package/src/template/entity-converter.ts +3 -3
  240. package/src/template/helpers.ts +49 -0
  241. package/src/template/implementations/entry-server.template.ts +1 -1
  242. package/src/template/implementations/generated.template.ts +4 -0
  243. package/src/template/implementations/generated_http.template.ts +1 -0
  244. package/src/template/implementations/generated_sso.template.ts +40 -11
  245. package/src/template/implementations/queries.template.ts +8 -0
  246. package/src/template/implementations/sd.template.ts +22 -3
  247. package/src/template/implementations/services.template.ts +11 -10
  248. package/src/template/implementations/view_form.template.ts +111 -101
  249. package/src/template/implementations/view_list.template.ts +120 -119
  250. package/src/template/implementations/view_search_input.template.ts +17 -13
  251. package/src/template/zod-converter.ts +103 -6
  252. package/src/testing/_relation-graph.ts +1 -1
  253. package/src/testing/data-explorer.ts +427 -0
  254. package/src/testing/faker-mappings.ts +434 -0
  255. package/src/testing/fixture-generator.ts +1166 -0
  256. package/src/testing/fixture-manager.ts +91 -6
  257. package/src/testing/index.ts +3 -0
  258. package/src/types/types.ts +222 -26
  259. package/src/ui/ai-client.ts +9 -1
  260. package/src/ui/api.ts +429 -23
  261. package/src/utils/fs-utils.ts +14 -1
  262. package/dist/template/implementations/view_enums_select.template.d.ts +0 -17
  263. package/dist/template/implementations/view_enums_select.template.d.ts.map +0 -1
  264. package/dist/template/implementations/view_enums_select.template.js +0 -62
  265. package/dist/template/implementations/view_id_async_select.template.d.ts +0 -17
  266. package/dist/template/implementations/view_id_async_select.template.d.ts.map +0 -1
  267. package/dist/template/implementations/view_id_async_select.template.js +0 -125
  268. package/dist/ui-web/assets/index-Bd_2AkLb.css +0 -1
  269. package/dist/ui-web/assets/index-BpSbhQWo.js +0 -225
  270. package/src/template/implementations/view_enums_select.template.ts +0 -65
  271. package/src/template/implementations/view_id_async_select.template.ts +0 -139
@@ -6,11 +6,14 @@ import { group, unique } from "radashi";
6
6
  import { z } from "zod";
7
7
  import { Sonamu } from "../api/sonamu";
8
8
  import {
9
+ type Cone,
9
10
  type EntityIndex,
10
11
  type EntityJson,
11
12
  type EntityProp,
12
13
  type EntityPropNode,
13
14
  type EntitySubsetRow,
15
+ getEnumDefValues,
16
+ getSubsetFields,
14
17
  isBelongsToOneRelationProp,
15
18
  isEnumProp,
16
19
  isHasManyRelationProp,
@@ -37,6 +40,7 @@ export class Entity {
37
40
  parentId?: string;
38
41
  table: string;
39
42
  title: string;
43
+ cone?: Cone;
40
44
  names: {
41
45
  parentFs: string;
42
46
  fs: string;
@@ -67,13 +71,20 @@ export class Entity {
67
71
  [key: string]: string;
68
72
  };
69
73
  } = {};
74
+ enumCones: {
75
+ [enumId: string]: Cone;
76
+ } = {};
77
+ subsetCones: {
78
+ [subsetKey: string]: Cone;
79
+ } = {};
70
80
 
71
- constructor({ id, parentId, table, title, props, indexes, subsets, enums }: EntityJson) {
81
+ constructor({ id, parentId, table, title, cone, props, indexes, subsets, enums }: EntityJson) {
72
82
  // id
73
83
  this.id = id;
74
84
  this.parentId = parentId;
75
85
  this.title = title ?? this.id;
76
86
  this.table = table ?? inflection.underscore(inflection.pluralize(id));
87
+ this.cone = cone;
77
88
 
78
89
  // props
79
90
  if (props) {
@@ -104,16 +115,30 @@ export class Entity {
104
115
  // indexes
105
116
  this.indexes = indexes ?? [];
106
117
 
107
- // subsets: SubsetField[]를 파싱하여 subsets(일반)와 subsetsInternal(internal)로 분리
118
+ // subsets: SubsetDef에서 SubsetField[]를 추출하여 subsets(일반)와 subsetsInternal(internal)로 분리
108
119
  this.subsets = {};
109
120
  this.subsetsInternal = {};
110
- for (const [key, fields] of Object.entries(subsets ?? {})) {
121
+ for (const [key, subsetDef] of Object.entries(subsets ?? {})) {
122
+ const fields = getSubsetFields(subsetDef);
111
123
  this.subsets[key] = fields.filter((f) => !isInternalSubsetField(f)).map(normalizeSubsetField);
112
124
  this.subsetsInternal[key] = fields.filter(isInternalSubsetField).map(normalizeSubsetField);
125
+
126
+ // cone 추출
127
+ if (!Array.isArray(subsetDef) && "cone" in subsetDef && subsetDef.cone) {
128
+ this.subsetCones[key] = subsetDef.cone;
129
+ }
113
130
  }
114
131
 
115
- // enums
116
- this.enumLabels = enums ?? {};
132
+ // enums: EnumDef에서 values와 cone를 추출하여 처리
133
+ this.enumLabels = Object.fromEntries(
134
+ Object.entries(enums ?? {}).map(([key, enumDef]) => {
135
+ // cone 추출
136
+ if ("values" in enumDef && "cone" in enumDef && enumDef.cone) {
137
+ this.enumCones[key] = enumDef.cone as Cone;
138
+ }
139
+ return [key, getEnumDefValues(enumDef)];
140
+ }),
141
+ );
117
142
  this.enums = Object.fromEntries(
118
143
  Object.entries(this.enumLabels).map(([key, enumLabel]) => {
119
144
  return [key, z.enum(Object.keys(enumLabel) as unknown as readonly [string, ...string[]])];
@@ -290,12 +315,17 @@ export class Entity {
290
315
  const loaderLines: string[] = [];
291
316
 
292
317
  for (const loader of loaders) {
293
- const { toTable, toCol, through } = loader.manyJoin;
318
+ const { toTable, toCol, through, fromTable } = loader.manyJoin;
319
+
320
+ // fromTable의 Entity를 가져와서 PK 타입 확인
321
+ const fromEntity = EntityManager.getByTable(fromTable);
322
+ const fromIdsType = fromEntity.getPkArrayType();
323
+
294
324
  loaderLines.push(
295
325
  "{",
296
326
  `as: "${loader.as}",`,
297
327
  `refId: "${loader.manyJoin.idField}",`,
298
- `qb: (qbWrapper: PuriWrapper<DatabaseSchemaExtend>, fromIds: number[]) => {`,
328
+ `qb: (qbWrapper: PuriWrapper<DatabaseSchemaExtend>, fromIds: number[] | string[]) => {`,
299
329
  );
300
330
 
301
331
  if (through === undefined) {
@@ -327,7 +357,7 @@ export class Entity {
327
357
  const selectObj = this.buildNestedSelectObject(loader.select);
328
358
  selectObj.refId = `"${toTable}.${toCol}"`;
329
359
  loaderLines.push(
330
- `.whereIn("${toTable}.${toCol}", fromIds)`,
360
+ `.whereIn("${toTable}.${toCol}", fromIds as ${fromIdsType})`,
331
361
  `.select(${this.stringifyNestedSelectObject(selectObj)});`,
332
362
  );
333
363
  } else {
@@ -359,7 +389,7 @@ export class Entity {
359
389
  const selectObj = this.buildNestedSelectObject(loader.select);
360
390
  selectObj.refId = `"${through.table}.${through.fromCol}"`;
361
391
  loaderLines.push(
362
- `.whereIn("${through.table}.${through.fromCol}", fromIds)`,
392
+ `.whereIn("${through.table}.${through.fromCol}", fromIds as ${fromIdsType})`,
363
393
  `.select(${this.stringifyNestedSelectObject(selectObj)});`,
364
394
  );
365
395
  }
@@ -841,15 +871,39 @@ export class Entity {
841
871
  }
842
872
 
843
873
  toJson(): EntityJson {
844
- // subsets와 subsetsInternal을 SubsetField[] 형태로 복원
845
- const subsets: { [key: string]: SubsetField[] } = {};
874
+ // subsets와 subsetsInternal을 SubsetDef 형태로 복원 (cone 포함)
875
+ const subsets: { [key: string]: import("../types/types").SubsetDef } = {};
846
876
  for (const key of Object.keys(this.subsets)) {
847
877
  const normalFields: SubsetField[] = this.subsets[key];
848
878
  const internalFields: SubsetField[] = (this.subsetsInternal[key] ?? []).map((field) => ({
849
879
  field,
850
880
  internal: true,
851
881
  }));
852
- subsets[key] = [...normalFields, ...internalFields];
882
+ const fields = [...normalFields, ...internalFields];
883
+
884
+ // cone이 있으면 새로운 객체 형태로, 없으면 배열 형태로
885
+ if (this.subsetCones[key]) {
886
+ subsets[key] = {
887
+ fields,
888
+ cone: this.subsetCones[key],
889
+ };
890
+ } else {
891
+ subsets[key] = fields;
892
+ }
893
+ }
894
+
895
+ // enums를 EnumDef 형태로 복원 (cone 포함)
896
+ const enums: { [key: string]: import("../types/types").EnumDef } = {};
897
+ for (const [key, values] of Object.entries(this.enumLabels)) {
898
+ // cone이 있으면 새로운 객체 형태로, 없으면 Record 형태로
899
+ if (this.enumCones[key]) {
900
+ enums[key] = {
901
+ values,
902
+ cone: this.enumCones[key],
903
+ };
904
+ } else {
905
+ enums[key] = values;
906
+ }
853
907
  }
854
908
 
855
909
  return {
@@ -857,10 +911,11 @@ export class Entity {
857
911
  parentId: this.parentId,
858
912
  table: this.table,
859
913
  title: this.title,
914
+ cone: this.cone,
860
915
  props: this.props,
861
916
  indexes: this.indexes,
862
917
  subsets,
863
- enums: this.enumLabels,
918
+ enums,
864
919
  };
865
920
  }
866
921
 
@@ -890,6 +945,118 @@ export class Entity {
890
945
  await EntityManager.register(json);
891
946
  }
892
947
 
948
+ /**
949
+ * 템플릿 cone 메타데이터를 생성합니다.
950
+ *
951
+ * LLM을 사용하지 않고 faker-mappings.ts를 활용하여 기본 cone을 생성합니다.
952
+ * stub entity 생성 시 자동으로 호출되어 최소한의 cone 메타데이터를 제공합니다.
953
+ *
954
+ * @param locale - 생성 시 사용할 locale (기본값: Sonamu.config.i18n.defaultLocale 또는 "ko")
955
+ */
956
+ async generateTemplateCones(locale?: "ko" | "en" | "ja"): Promise<void> {
957
+ const { generateTemplateCones } = await import("./entity-template-cone");
958
+ const configLocale = Sonamu.config.i18n?.defaultLocale;
959
+ const effectiveLocale =
960
+ locale ||
961
+ (configLocale === "ko" || configLocale === "en" || configLocale === "ja"
962
+ ? configLocale
963
+ : "ko");
964
+ const result = generateTemplateCones(this.toJson(), effectiveLocale);
965
+
966
+ // 결과를 Entity에 적용 (applyCones와 동일한 방식)
967
+ if (result.entityCone) {
968
+ this.cone = result.entityCone;
969
+ }
970
+
971
+ for (const [propName, cone] of Object.entries(result.propCones)) {
972
+ const prop = this.props.find((p) => p.name === propName);
973
+ if (prop) {
974
+ (prop as { cone?: Cone }).cone = cone;
975
+ }
976
+ }
977
+
978
+ this.enumCones = { ...this.enumCones, ...result.enumCones };
979
+ this.subsetCones = { ...this.subsetCones, ...result.subsetCones };
980
+
981
+ await this.save();
982
+ }
983
+
984
+ /**
985
+ * LLM을 사용하여 cone 메타데이터를 생성합니다.
986
+ *
987
+ * @param options.preserveExisting - 기존 cone 보존 여부 (기본값: true)
988
+ * @param options.onlyEmpty - fixtureHint가 없는 cone만 생성 (기본값: false)
989
+ * @param options.locale - 생성 시 사용할 locale (기본값: "ko")
990
+ */
991
+ async generateCones(options?: {
992
+ preserveExisting?: boolean;
993
+ onlyEmpty?: boolean;
994
+ locale?: "ko" | "en" | "ja";
995
+ }): Promise<import("../cone/cone-generator").ConeGenerationResult> {
996
+ const { generateCones } = await import("../cone/cone-generator");
997
+ const context: import("../cone/cone-generator").ConeGenerationContext = {
998
+ entity: this.toJson(),
999
+ locale: options?.locale || "ko",
1000
+ existingCones: options?.preserveExisting !== false ? this.collectExistingCones() : undefined,
1001
+ onlyEmpty: options?.onlyEmpty ?? false,
1002
+ };
1003
+
1004
+ const result = await generateCones(context);
1005
+ this.applyCones(result);
1006
+ await this.save();
1007
+ return result;
1008
+ }
1009
+
1010
+ /**
1011
+ * 기존 cone들을 수집합니다 (entity, props, enums, subsets).
1012
+ *
1013
+ * @returns 키가 "entity:id", "prop:name", "enum:enumId", "subset:key" 형식인 cone 맵
1014
+ */
1015
+ private collectExistingCones(): Record<string, Cone> {
1016
+ const cones: Record<string, Cone> = {};
1017
+
1018
+ if (this.cone) {
1019
+ cones[`entity:${this.id}`] = this.cone;
1020
+ }
1021
+
1022
+ for (const prop of this.props) {
1023
+ if (prop.cone) {
1024
+ cones[`prop:${prop.name}`] = prop.cone;
1025
+ }
1026
+ }
1027
+
1028
+ for (const [enumId, cone] of Object.entries(this.enumCones)) {
1029
+ cones[`enum:${enumId}`] = cone;
1030
+ }
1031
+
1032
+ for (const [subsetKey, cone] of Object.entries(this.subsetCones)) {
1033
+ cones[`subset:${subsetKey}`] = cone;
1034
+ }
1035
+
1036
+ return cones;
1037
+ }
1038
+
1039
+ /**
1040
+ * 생성된 cone들을 Entity에 적용합니다.
1041
+ *
1042
+ * @param result - LLM으로 생성된 cone 결과
1043
+ */
1044
+ private applyCones(result: import("../cone/cone-generator").ConeGenerationResult): void {
1045
+ if (result.entityCone) {
1046
+ this.cone = result.entityCone;
1047
+ }
1048
+
1049
+ for (const [propName, cone] of Object.entries(result.propCones)) {
1050
+ const prop = this.props.find((p) => p.name === propName);
1051
+ if (prop) {
1052
+ (prop as { cone?: Cone }).cone = cone;
1053
+ }
1054
+ }
1055
+
1056
+ this.enumCones = { ...this.enumCones, ...result.enumCones };
1057
+ this.subsetCones = { ...this.subsetCones, ...result.subsetCones };
1058
+ }
1059
+
893
1060
  getSubsetRows(
894
1061
  _subsets?: { [key: string]: string[] },
895
1062
  _subsetsInternal?: { [key: string]: string[] },
@@ -1179,4 +1346,13 @@ export class Entity {
1179
1346
  }
1180
1347
  return idProp;
1181
1348
  }
1349
+
1350
+ /**
1351
+ * 엔티티의 PK 배열 타입을 반환합니다.
1352
+ * LoaderQuery의 fromIds 타입으로 사용됩니다.
1353
+ */
1354
+ getPkArrayType(): string {
1355
+ const pkType = this.getPkType();
1356
+ return pkType === "integer" ? "number[]" : "string[]";
1357
+ }
1182
1358
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @generated
3
+ * 최초 1회 생성되며, 이후에는 덮어쓰지 않습니다.
4
+ * 필요시 직접 수정할 수 있습니다.
5
+ */
1
6
  /** biome-ignore-all lint/correctness/useExhaustiveDependencies: shared */
2
7
  /** biome-ignore-all lint/suspicious/noExplicitAny: shared */
3
8
 
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @generated
3
+ * 최초 1회 생성되며, 이후에는 덮어쓰지 않습니다.
4
+ * 필요시 직접 수정할 수 있습니다.
5
+ */
1
6
  /** biome-ignore-all lint/correctness/useExhaustiveDependencies: shared */
2
7
  /** biome-ignore-all lint/suspicious/noExplicitAny: shared */
3
8
 
@@ -368,12 +373,11 @@ export function useSSEStream<T extends Record<string, any>>(
368
373
  const fullUrl = queryString ? `${url}?${queryString}` : url;
369
374
 
370
375
  const eventSource = new EventSource(fullUrl, {
371
- fetch: (url, options) =>
372
- fetch({
373
- url: url.toString(),
374
- ...options,
376
+ fetch: (url, init) =>
377
+ globalThis.fetch(url, {
378
+ ...init,
375
379
  headers: {
376
- ...options?.headers,
380
+ ...init?.headers,
377
381
  "Accept-Language": getCurrentLocale(),
378
382
  },
379
383
  }),
@@ -0,0 +1,21 @@
1
+ # Project Skills
2
+
3
+ 이 디렉토리는 프로젝트 고유의 문서를 저장하는 공간입니다.
4
+
5
+ ## 용도
6
+
7
+ - **requirements.md**: 프로젝트 요구사항 명세
8
+ - **business-logic.md**: 비즈니스 로직 상세 (선택)
9
+ - **architecture.md**: 아키텍처 설계 문서 (선택)
10
+
11
+ ## 사용 방법
12
+
13
+ 1. 프로젝트 생성 시 AI가 요구사항을 받으면 `requirements.md`에 자동으로 저장됩니다.
14
+ 2. 이후 대화에서 AI는 이 문서들을 지속적으로 참고합니다.
15
+ 3. 사용자가 직접 추가하고 싶은 내용이 있으면 이 디렉토리에 새로운 .md 파일을 추가하거나 기존 파일을 수정하세요.
16
+
17
+ ## 주의사항
18
+
19
+ - 이 디렉토리의 파일들은 프로젝트별로 관리됩니다.
20
+ - Sonamu skills sync 시에도 덮어쓰지 않고 유지됩니다.
21
+ - 민감한 정보(비밀번호, API 키 등)는 절대 포함하지 마세요.