@pattern-stack/codegen 0.2.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 (279) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +214 -0
  3. package/dist/runtime/analytics/index.d.ts +6 -0
  4. package/dist/runtime/analytics/index.js +49 -0
  5. package/dist/runtime/analytics/index.js.map +1 -0
  6. package/dist/runtime/analytics/metrics.d.ts +75 -0
  7. package/dist/runtime/analytics/metrics.js +1 -0
  8. package/dist/runtime/analytics/metrics.js.map +1 -0
  9. package/dist/runtime/analytics/packs/crm-entity-measures.d.ts +21 -0
  10. package/dist/runtime/analytics/packs/crm-entity-measures.js +1 -0
  11. package/dist/runtime/analytics/packs/crm-entity-measures.js.map +1 -0
  12. package/dist/runtime/analytics/packs/index.d.ts +3 -0
  13. package/dist/runtime/analytics/packs/index.js +1 -0
  14. package/dist/runtime/analytics/packs/index.js.map +1 -0
  15. package/dist/runtime/analytics/packs/monetary-measures.d.ts +21 -0
  16. package/dist/runtime/analytics/packs/monetary-measures.js +1 -0
  17. package/dist/runtime/analytics/packs/monetary-measures.js.map +1 -0
  18. package/dist/runtime/analytics/specs.d.ts +49 -0
  19. package/dist/runtime/analytics/specs.js +1 -0
  20. package/dist/runtime/analytics/specs.js.map +1 -0
  21. package/dist/runtime/analytics/types.d.ts +85 -0
  22. package/dist/runtime/analytics/types.js +49 -0
  23. package/dist/runtime/analytics/types.js.map +1 -0
  24. package/dist/runtime/base-classes/activity-entity-repository.d.ts +26 -0
  25. package/dist/runtime/base-classes/activity-entity-repository.js +195 -0
  26. package/dist/runtime/base-classes/activity-entity-repository.js.map +1 -0
  27. package/dist/runtime/base-classes/activity-entity-service.d.ts +39 -0
  28. package/dist/runtime/base-classes/activity-entity-service.js +214 -0
  29. package/dist/runtime/base-classes/activity-entity-service.js.map +1 -0
  30. package/dist/runtime/base-classes/base-read-use-cases.d.ts +68 -0
  31. package/dist/runtime/base-classes/base-read-use-cases.js +32 -0
  32. package/dist/runtime/base-classes/base-read-use-cases.js.map +1 -0
  33. package/dist/runtime/base-classes/base-repository.d.ts +99 -0
  34. package/dist/runtime/base-classes/base-repository.js +160 -0
  35. package/dist/runtime/base-classes/base-repository.js.map +1 -0
  36. package/dist/runtime/base-classes/base-service.d.ts +98 -0
  37. package/dist/runtime/base-classes/base-service.js +186 -0
  38. package/dist/runtime/base-classes/base-service.js.map +1 -0
  39. package/dist/runtime/base-classes/index.d.ts +18 -0
  40. package/dist/runtime/base-classes/index.js +617 -0
  41. package/dist/runtime/base-classes/index.js.map +1 -0
  42. package/dist/runtime/base-classes/knowledge-entity-repository.d.ts +17 -0
  43. package/dist/runtime/base-classes/knowledge-entity-repository.js +166 -0
  44. package/dist/runtime/base-classes/knowledge-entity-repository.js.map +1 -0
  45. package/dist/runtime/base-classes/knowledge-entity-service.d.ts +15 -0
  46. package/dist/runtime/base-classes/knowledge-entity-service.js +192 -0
  47. package/dist/runtime/base-classes/knowledge-entity-service.js.map +1 -0
  48. package/dist/runtime/base-classes/lifecycle-events.d.ts +49 -0
  49. package/dist/runtime/base-classes/lifecycle-events.js +76 -0
  50. package/dist/runtime/base-classes/lifecycle-events.js.map +1 -0
  51. package/dist/runtime/base-classes/metadata-entity-repository.d.ts +27 -0
  52. package/dist/runtime/base-classes/metadata-entity-repository.js +212 -0
  53. package/dist/runtime/base-classes/metadata-entity-repository.js.map +1 -0
  54. package/dist/runtime/base-classes/metadata-entity-service.d.ts +39 -0
  55. package/dist/runtime/base-classes/metadata-entity-service.js +214 -0
  56. package/dist/runtime/base-classes/metadata-entity-service.js.map +1 -0
  57. package/dist/runtime/base-classes/synced-entity-repository.d.ts +32 -0
  58. package/dist/runtime/base-classes/synced-entity-repository.js +203 -0
  59. package/dist/runtime/base-classes/synced-entity-repository.js.map +1 -0
  60. package/dist/runtime/base-classes/synced-entity-service.d.ts +41 -0
  61. package/dist/runtime/base-classes/synced-entity-service.js +215 -0
  62. package/dist/runtime/base-classes/synced-entity-service.js.map +1 -0
  63. package/dist/runtime/base-classes/with-analytics.d.ts +18 -0
  64. package/dist/runtime/base-classes/with-analytics.js +11 -0
  65. package/dist/runtime/base-classes/with-analytics.js.map +1 -0
  66. package/dist/runtime/constants/tokens.d.ts +29 -0
  67. package/dist/runtime/constants/tokens.js +8 -0
  68. package/dist/runtime/constants/tokens.js.map +1 -0
  69. package/dist/runtime/subsystems/analytics/analytics-query.protocol.d.ts +30 -0
  70. package/dist/runtime/subsystems/analytics/analytics-query.protocol.js +1 -0
  71. package/dist/runtime/subsystems/analytics/analytics-query.protocol.js.map +1 -0
  72. package/dist/runtime/subsystems/analytics/analytics.module.d.ts +34 -0
  73. package/dist/runtime/subsystems/analytics/analytics.module.js +117 -0
  74. package/dist/runtime/subsystems/analytics/analytics.module.js.map +1 -0
  75. package/dist/runtime/subsystems/analytics/analytics.tokens.d.ts +24 -0
  76. package/dist/runtime/subsystems/analytics/analytics.tokens.js +10 -0
  77. package/dist/runtime/subsystems/analytics/analytics.tokens.js.map +1 -0
  78. package/dist/runtime/subsystems/analytics/cube-backend.d.ts +28 -0
  79. package/dist/runtime/subsystems/analytics/cube-backend.js +71 -0
  80. package/dist/runtime/subsystems/analytics/cube-backend.js.map +1 -0
  81. package/dist/runtime/subsystems/analytics/index.d.ts +6 -0
  82. package/dist/runtime/subsystems/analytics/index.js +122 -0
  83. package/dist/runtime/subsystems/analytics/index.js.map +1 -0
  84. package/dist/runtime/subsystems/analytics/noop-backend.d.ts +7 -0
  85. package/dist/runtime/subsystems/analytics/noop-backend.js +25 -0
  86. package/dist/runtime/subsystems/analytics/noop-backend.js.map +1 -0
  87. package/dist/runtime/subsystems/cache/cache.drizzle-backend.d.ts +43 -0
  88. package/dist/runtime/subsystems/cache/cache.drizzle-backend.js +133 -0
  89. package/dist/runtime/subsystems/cache/cache.drizzle-backend.js.map +1 -0
  90. package/dist/runtime/subsystems/cache/cache.memory-backend.d.ts +21 -0
  91. package/dist/runtime/subsystems/cache/cache.memory-backend.js +100 -0
  92. package/dist/runtime/subsystems/cache/cache.memory-backend.js.map +1 -0
  93. package/dist/runtime/subsystems/cache/cache.module.d.ts +37 -0
  94. package/dist/runtime/subsystems/cache/cache.module.js +272 -0
  95. package/dist/runtime/subsystems/cache/cache.module.js.map +1 -0
  96. package/dist/runtime/subsystems/cache/cache.protocol.d.ts +42 -0
  97. package/dist/runtime/subsystems/cache/cache.protocol.js +1 -0
  98. package/dist/runtime/subsystems/cache/cache.protocol.js.map +1 -0
  99. package/dist/runtime/subsystems/cache/cache.schema.d.ts +64 -0
  100. package/dist/runtime/subsystems/cache/cache.schema.js +18 -0
  101. package/dist/runtime/subsystems/cache/cache.schema.js.map +1 -0
  102. package/dist/runtime/subsystems/cache/cache.tokens.d.ts +18 -0
  103. package/dist/runtime/subsystems/cache/cache.tokens.js +8 -0
  104. package/dist/runtime/subsystems/cache/cache.tokens.js.map +1 -0
  105. package/dist/runtime/subsystems/cache/index.d.ts +11 -0
  106. package/dist/runtime/subsystems/cache/index.js +277 -0
  107. package/dist/runtime/subsystems/cache/index.js.map +1 -0
  108. package/dist/runtime/subsystems/events/domain-events.schema.d.ts +187 -0
  109. package/dist/runtime/subsystems/events/domain-events.schema.js +32 -0
  110. package/dist/runtime/subsystems/events/domain-events.schema.js.map +1 -0
  111. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.d.ts +38 -0
  112. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +199 -0
  113. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -0
  114. package/dist/runtime/subsystems/events/event-bus.memory-backend.d.ts +18 -0
  115. package/dist/runtime/subsystems/events/event-bus.memory-backend.js +71 -0
  116. package/dist/runtime/subsystems/events/event-bus.memory-backend.js.map +1 -0
  117. package/dist/runtime/subsystems/events/event-bus.protocol.d.ts +52 -0
  118. package/dist/runtime/subsystems/events/event-bus.protocol.js +1 -0
  119. package/dist/runtime/subsystems/events/event-bus.protocol.js.map +1 -0
  120. package/dist/runtime/subsystems/events/event-bus.redis-backend.d.ts +95 -0
  121. package/dist/runtime/subsystems/events/event-bus.redis-backend.js +229 -0
  122. package/dist/runtime/subsystems/events/event-bus.redis-backend.js.map +1 -0
  123. package/dist/runtime/subsystems/events/events.module.d.ts +46 -0
  124. package/dist/runtime/subsystems/events/events.module.js +531 -0
  125. package/dist/runtime/subsystems/events/events.module.js.map +1 -0
  126. package/dist/runtime/subsystems/events/events.tokens.d.ts +19 -0
  127. package/dist/runtime/subsystems/events/events.tokens.js +8 -0
  128. package/dist/runtime/subsystems/events/events.tokens.js.map +1 -0
  129. package/dist/runtime/subsystems/events/index.d.ts +12 -0
  130. package/dist/runtime/subsystems/events/index.js +536 -0
  131. package/dist/runtime/subsystems/events/index.js.map +1 -0
  132. package/dist/runtime/subsystems/index.d.ts +24 -0
  133. package/dist/runtime/subsystems/index.js +1643 -0
  134. package/dist/runtime/subsystems/index.js.map +1 -0
  135. package/dist/runtime/subsystems/jobs/index.d.ts +14 -0
  136. package/dist/runtime/subsystems/jobs/index.js +680 -0
  137. package/dist/runtime/subsystems/jobs/index.js.map +1 -0
  138. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.d.ts +54 -0
  139. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.js +186 -0
  140. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.js.map +1 -0
  141. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.d.ts +38 -0
  142. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.js +228 -0
  143. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.js.map +1 -0
  144. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.d.ts +12 -0
  145. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.js +44 -0
  146. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.js.map +1 -0
  147. package/dist/runtime/subsystems/jobs/job-queue.protocol.d.ts +48 -0
  148. package/dist/runtime/subsystems/jobs/job-queue.protocol.js +1 -0
  149. package/dist/runtime/subsystems/jobs/job-queue.protocol.js.map +1 -0
  150. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.d.ts +46 -0
  151. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.js +187 -0
  152. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.js.map +1 -0
  153. package/dist/runtime/subsystems/jobs/job-queue.schema.d.ts +237 -0
  154. package/dist/runtime/subsystems/jobs/job-queue.schema.js +44 -0
  155. package/dist/runtime/subsystems/jobs/job-queue.schema.js.map +1 -0
  156. package/dist/runtime/subsystems/jobs/jobs.module.d.ts +18 -0
  157. package/dist/runtime/subsystems/jobs/jobs.module.js +676 -0
  158. package/dist/runtime/subsystems/jobs/jobs.module.js.map +1 -0
  159. package/dist/runtime/subsystems/jobs/jobs.tokens.d.ts +13 -0
  160. package/dist/runtime/subsystems/jobs/jobs.tokens.js +8 -0
  161. package/dist/runtime/subsystems/jobs/jobs.tokens.js.map +1 -0
  162. package/dist/runtime/subsystems/storage/index.d.ts +6 -0
  163. package/dist/runtime/subsystems/storage/index.js +204 -0
  164. package/dist/runtime/subsystems/storage/index.js.map +1 -0
  165. package/dist/runtime/subsystems/storage/storage.local-backend.d.ts +18 -0
  166. package/dist/runtime/subsystems/storage/storage.local-backend.js +108 -0
  167. package/dist/runtime/subsystems/storage/storage.local-backend.js.map +1 -0
  168. package/dist/runtime/subsystems/storage/storage.memory-backend.d.ts +28 -0
  169. package/dist/runtime/subsystems/storage/storage.memory-backend.js +72 -0
  170. package/dist/runtime/subsystems/storage/storage.memory-backend.js.map +1 -0
  171. package/dist/runtime/subsystems/storage/storage.module.d.ts +40 -0
  172. package/dist/runtime/subsystems/storage/storage.module.js +201 -0
  173. package/dist/runtime/subsystems/storage/storage.module.js.map +1 -0
  174. package/dist/runtime/subsystems/storage/storage.protocol.d.ts +69 -0
  175. package/dist/runtime/subsystems/storage/storage.protocol.js +1 -0
  176. package/dist/runtime/subsystems/storage/storage.protocol.js.map +1 -0
  177. package/dist/runtime/subsystems/storage/storage.tokens.d.ts +11 -0
  178. package/dist/runtime/subsystems/storage/storage.tokens.js +6 -0
  179. package/dist/runtime/subsystems/storage/storage.tokens.js.map +1 -0
  180. package/dist/runtime/subsystems/storage/storage.utils.d.ts +9 -0
  181. package/dist/runtime/subsystems/storage/storage.utils.js +18 -0
  182. package/dist/runtime/subsystems/storage/storage.utils.js.map +1 -0
  183. package/dist/runtime/types/drizzle.d.ts +17 -0
  184. package/dist/runtime/types/drizzle.js +1 -0
  185. package/dist/runtime/types/drizzle.js.map +1 -0
  186. package/dist/src/cli/index.d.ts +1 -0
  187. package/dist/src/cli/index.js +7365 -0
  188. package/dist/src/cli/index.js.map +1 -0
  189. package/dist/src/index.d.ts +2384 -0
  190. package/dist/src/index.js +2198 -0
  191. package/dist/src/index.js.map +1 -0
  192. package/package.json +114 -0
  193. package/templates/broadcast/new/backend-interface.ejs.t +47 -0
  194. package/templates/broadcast/new/bridge-listener.ejs.t +67 -0
  195. package/templates/broadcast/new/channel.ejs.t +77 -0
  196. package/templates/broadcast/new/index.ejs.t +21 -0
  197. package/templates/broadcast/new/memory-backend.ejs.t +87 -0
  198. package/templates/broadcast/new/module.ejs.t +57 -0
  199. package/templates/broadcast/new/prompt.js +268 -0
  200. package/templates/broadcast/new/websocket-backend.ejs.t +259 -0
  201. package/templates/entity/new/backend/application/commands/create.ejs.t +55 -0
  202. package/templates/entity/new/backend/application/commands/delete.ejs.t +45 -0
  203. package/templates/entity/new/backend/application/commands/grouped-index.ejs.t +149 -0
  204. package/templates/entity/new/backend/application/commands/index.ejs.t +15 -0
  205. package/templates/entity/new/backend/application/commands/update.ejs.t +58 -0
  206. package/templates/entity/new/backend/application/queries/declarative-queries.ejs.t +36 -0
  207. package/templates/entity/new/backend/application/queries/get-by-id.ejs.t +42 -0
  208. package/templates/entity/new/backend/application/queries/grouped-index.ejs.t +81 -0
  209. package/templates/entity/new/backend/application/queries/index.ejs.t +14 -0
  210. package/templates/entity/new/backend/application/queries/list.ejs.t +36 -0
  211. package/templates/entity/new/backend/application/schemas/_inject-index.ejs.t +7 -0
  212. package/templates/entity/new/backend/application/schemas/dto.ejs.t +45 -0
  213. package/templates/entity/new/backend/database/_inject-index.ejs.t +7 -0
  214. package/templates/entity/new/backend/database/electric-migration.ejs.t +21 -0
  215. package/templates/entity/new/backend/database/repository.ejs.t +450 -0
  216. package/templates/entity/new/backend/database/schema.ejs.t +248 -0
  217. package/templates/entity/new/backend/domain/_inject-index.ejs.t +12 -0
  218. package/templates/entity/new/backend/domain/entity.ejs.t +108 -0
  219. package/templates/entity/new/backend/domain/grouped-index.ejs.t +163 -0
  220. package/templates/entity/new/backend/domain/index.ejs.t +15 -0
  221. package/templates/entity/new/backend/domain/repository-interface.ejs.t +71 -0
  222. package/templates/entity/new/backend/modules/core/_ensure-anchor-tokens.ejs.t +10 -0
  223. package/templates/entity/new/backend/modules/core/_inject-token.ejs.t +7 -0
  224. package/templates/entity/new/backend/modules/core/module.ejs.t +67 -0
  225. package/templates/entity/new/backend/modules/trpc/module.ejs.t +67 -0
  226. package/templates/entity/new/backend/presentation/controller.ejs.t +201 -0
  227. package/templates/entity/new/clean-lite-ps/controller.ejs.t +37 -0
  228. package/templates/entity/new/clean-lite-ps/dto/create.ejs.t +17 -0
  229. package/templates/entity/new/clean-lite-ps/dto/output.ejs.t +25 -0
  230. package/templates/entity/new/clean-lite-ps/dto/update.ejs.t +11 -0
  231. package/templates/entity/new/clean-lite-ps/entity.ejs.t +52 -0
  232. package/templates/entity/new/clean-lite-ps/index.ejs.t +20 -0
  233. package/templates/entity/new/clean-lite-ps/module.ejs.t +43 -0
  234. package/templates/entity/new/clean-lite-ps/prompt-extension.js +617 -0
  235. package/templates/entity/new/clean-lite-ps/repository.ejs.t +62 -0
  236. package/templates/entity/new/clean-lite-ps/service.ejs.t +34 -0
  237. package/templates/entity/new/clean-lite-ps/use-cases/declarative-queries.ejs.t +34 -0
  238. package/templates/entity/new/clean-lite-ps/use-cases/find-by-id.ejs.t +16 -0
  239. package/templates/entity/new/clean-lite-ps/use-cases/list.ejs.t +16 -0
  240. package/templates/entity/new/frontend/_inject-entities-entry.ejs.t +7 -0
  241. package/templates/entity/new/frontend/_inject-entities-import.ejs.t +7 -0
  242. package/templates/entity/new/frontend/collections/_ensure-anchor-collections.ejs.t +10 -0
  243. package/templates/entity/new/frontend/collections/_inject-index.ejs.t +9 -0
  244. package/templates/entity/new/frontend/collections/_inject-schema-import.ejs.t +9 -0
  245. package/templates/entity/new/frontend/collections/collection.ejs.t +61 -0
  246. package/templates/entity/new/frontend/collections/collections-base.ejs.t +24 -0
  247. package/templates/entity/new/frontend/entity/collection.ejs.t +172 -0
  248. package/templates/entity/new/frontend/entity/combined.ejs.t +474 -0
  249. package/templates/entity/new/frontend/entity/fields.ejs.t +104 -0
  250. package/templates/entity/new/frontend/entity/hooks.ejs.t +73 -0
  251. package/templates/entity/new/frontend/entity/index.ejs.t +21 -0
  252. package/templates/entity/new/frontend/entity/mutation-hooks.ejs.t +84 -0
  253. package/templates/entity/new/frontend/entity/mutations.ejs.t +38 -0
  254. package/templates/entity/new/frontend/entity/types.ejs.t +59 -0
  255. package/templates/entity/new/frontend/generated/_inject-index-export.ejs.t +7 -0
  256. package/templates/entity/new/frontend/generated/_inject-index-import.ejs.t +7 -0
  257. package/templates/entity/new/frontend/generated/_inject-index-registry.ejs.t +7 -0
  258. package/templates/entity/new/frontend/store/_inject-collection-import.ejs.t +9 -0
  259. package/templates/entity/new/frontend/store/_inject-collections.ejs.t +9 -0
  260. package/templates/entity/new/frontend/store/_inject-entity.ejs.t +9 -0
  261. package/templates/entity/new/frontend/store/_inject-import.ejs.t +9 -0
  262. package/templates/entity/new/frontend/store/_inject-lookups.ejs.t +9 -0
  263. package/templates/entity/new/frontend/store/_inject-resolve.ejs.t +10 -0
  264. package/templates/entity/new/frontend/store/hooks.ejs.t +72 -0
  265. package/templates/entity/new/frontend/unified-entity.ejs.t +28 -0
  266. package/templates/entity/new/prompt.js +1421 -0
  267. package/templates/relationship/new/controller.ejs.t +36 -0
  268. package/templates/relationship/new/dto/create.ejs.t +41 -0
  269. package/templates/relationship/new/dto/output.ejs.t +44 -0
  270. package/templates/relationship/new/dto/update.ejs.t +10 -0
  271. package/templates/relationship/new/entity.ejs.t +98 -0
  272. package/templates/relationship/new/index.ejs.t +19 -0
  273. package/templates/relationship/new/module.ejs.t +35 -0
  274. package/templates/relationship/new/prompt.js +682 -0
  275. package/templates/relationship/new/repository.ejs.t +54 -0
  276. package/templates/relationship/new/service.ejs.t +31 -0
  277. package/templates/relationship/new/use-cases/declarative-queries.ejs.t +34 -0
  278. package/templates/relationship/new/use-cases/find-by-id.ejs.t +16 -0
  279. package/templates/relationship/new/use-cases/list.ejs.t +16 -0
@@ -0,0 +1,474 @@
1
+ ---
2
+ to: "<%= generate.structure === 'monolithic' ? `${locations.frontendGenerated.path}/${generate.fileNaming === 'plural' ? plural : name}.ts` : '' %>"
3
+ skip_if: <%= !frontendEnabled || (generate.structure !== 'monolithic') %>
4
+ force: true
5
+ ---
6
+ /**
7
+ * <%= className %> - Generated Entity Module
8
+ *
9
+ * AUTO-GENERATED by entity codegen - do not edit directly.
10
+ * Source: entities/<%= name %>.yaml
11
+ *
12
+ * This file contains everything needed for the <%= className %> entity:
13
+ * - Types (base + resolved with relations)
14
+ * - Collection (Electric sync with optimistic mutations)
15
+ * - Hooks (useMany, useOne with auto-resolved relations)
16
+ * - Mutations (insert, update, delete)
17
+ * - Field metadata (for DataGrid, forms, admin)
18
+ */
19
+
20
+ <%
21
+ // Type import: depends on typeNaming config
22
+ // 'entity' = source exports OpportunityEntity, 'plain' = source exports Opportunity
23
+ const importedTypeName = generate.typeNaming === 'plain' ? className : className + 'Entity';
24
+ // Collection variable name depends on collectionNaming config
25
+ const collectionVar = generate.collectionNaming === 'plural' ? collectionVarNamePlural : collectionVarName;
26
+ // Hook return key depends on hookReturnStyle config
27
+ const returnKey = generate.hookReturnStyle === 'named' ? pluralCamelName : 'data';
28
+ const returnKeySingular = generate.hookReturnStyle === 'named' ? camelName : 'data';
29
+ -%>
30
+ <% if (generate.mutations && (exposeTrpc || exposeRepository)) { -%>
31
+ import { useState, useCallback } from 'react';
32
+ <% } -%>
33
+ <% if (frontend.sync.columnMapper) { -%>
34
+ import { <%= frontend.sync.columnMapper %> } from '@electric-sql/client';
35
+ <% } -%>
36
+ import { <%= camelName %>Schema, type <%= importedTypeName %> } from '<%= locations.dbEntities.import %><% if (!locations.dbEntities.barrelExport) { %>/<%= name %><% } %>';
37
+ <% if (exposeTrpc) { -%>
38
+ import { trpc } from '<%= locations.trpcClient.import %>';
39
+ <% } -%>
40
+ import { electricCollectionOptions } from '@tanstack/electric-db-collection';
41
+ import { createCollection<% if (generate.hookStyle === 'useLiveQuery') { %>, useLiveQuery, eq<% } %> } from '@tanstack/react-db';
42
+ <% if (generate.fieldMetadata) { -%>
43
+ import type { FieldMeta, FieldType, FieldImportance } from '<%= locations.frontendFieldMetaTypes.import %>/field-meta';
44
+ <% } -%>
45
+ <% if (frontend.auth.function) { -%>
46
+ import { <%= frontend.auth.function %> } from '<%= locations.frontendCollectionsAuth.import %>';
47
+ <% } -%>
48
+ <% if (frontend.sync.apiBaseUrlImport) { -%>
49
+ import { API_BASE_URL } from '<%= frontend.sync.apiBaseUrlImport %>';
50
+ <% } -%>
51
+ <%
52
+ // Collect unique belongs_to targets for imports (FK resolution)
53
+ // Only import if fkResolution is enabled (default: true)
54
+ const importedEntities = new Set();
55
+ if (generate.fkResolution !== false) {
56
+ existingBelongsTo.forEach((rel) => {
57
+ if (rel.target !== name) {
58
+ importedEntities.add(rel.target);
59
+ }
60
+ });
61
+ }
62
+ -%>
63
+ <% if (importedEntities.size > 0) { -%>
64
+
65
+ // Import related collections for FK resolution
66
+ <% importedEntities.forEach((target) => {
67
+ const targetCamel = target.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
68
+ // Simple pluralization matching prompt.js pluralize function
69
+ const targetPlural = target.endsWith('y') ? target.slice(0, -1) + 'ies' :
70
+ (target.endsWith('s') || target.endsWith('x') || target.endsWith('ch') || target.endsWith('sh')) ? target + 'es' : target + 's';
71
+ const targetFileName = generate.fileNaming === 'plural' ? targetPlural : target;
72
+ const targetCamelPlural = targetCamel.endsWith('y') ? targetCamel.slice(0, -1) + 'ies' : targetCamel + 's';
73
+ const targetCollectionVar = generate.collectionNaming === 'plural' ? targetCamelPlural : targetCamel;
74
+ -%>
75
+ import { <%= targetCollectionVar %>Collection } from './<%= targetFileName %>';
76
+ <% }); -%>
77
+ <% importedEntities.forEach((target) => {
78
+ const targetClass = target.charAt(0).toUpperCase() + target.slice(1).replace(/_([a-z])/g, (_, c) => c.toUpperCase());
79
+ -%>
80
+ import type { <%= generate.typeNaming === 'plain' ? targetClass : targetClass + 'Entity' %> } from '<%= locations.dbEntities.import %><% if (!locations.dbEntities.barrelExport) { %>/<%= target %><% } %>';
81
+ <% }); -%>
82
+ <% } -%>
83
+
84
+ // ============================================================================
85
+ // Types
86
+ // ============================================================================
87
+
88
+ /** Base entity from database */
89
+ <% if (generate.typeNaming === 'plain') { -%>
90
+ export type { <%= className %> };
91
+ <% } else { -%>
92
+ export type <%= className %> = <%= importedTypeName %>;
93
+ <% } -%>
94
+ <% if (existingBelongsTo.length > 0 && generate.fkResolution !== false) { -%>
95
+
96
+ /** Entity with resolved FK relations (only includes relations with existing targets) */
97
+ export interface <%= className %>Resolved extends <%= className %> {
98
+ <% existingBelongsTo.forEach((rel) => { -%>
99
+ <% // Use local type for self-referential, imported type for others -%>
100
+ <% const relTypeName = rel.target === name ? className : (generate.typeNaming === 'plain' ? rel.targetClass : rel.targetClass + 'Entity'); -%>
101
+ <%= rel.name %>?: <%= relTypeName %>;
102
+ <% }); -%>
103
+ }
104
+ <% } else { -%>
105
+
106
+ /** Entity type (no FK relations to resolve) */
107
+ export type <%= className %>Resolved = <%= className %>;
108
+ <% } -%>
109
+
110
+ // ============================================================================
111
+ // Collection (Electric sync with optimistic mutations)
112
+ // ============================================================================
113
+ <% if (hasSoftDelete) { -%>
114
+
115
+ // TODO: Backend Electric shape endpoint should filter soft-deleted records
116
+ // by including WHERE deleted_at IS NULL in the shape configuration.
117
+ // Without this filter, soft-deleted records will reappear after Electric sync.
118
+ <% } -%>
119
+
120
+ export const <%= collectionVar %> = createCollection(
121
+ electricCollectionOptions({
122
+ id: '<%= plural %>',
123
+ shapeOptions: {
124
+ <% if (frontend.sync.useTableParam) { -%>
125
+ <% if (frontend.sync.wrapInUrlConstructor !== false) { -%>
126
+ url: new URL(
127
+ '<%= frontend.sync.shapeUrl %>',
128
+ typeof window !== 'undefined'
129
+ ? window.location.origin
130
+ : 'http://localhost:5173',
131
+ ).toString(),
132
+ <% } else { -%>
133
+ url: '<%= frontend.sync.shapeUrl %>',
134
+ <% } -%>
135
+ params: {
136
+ table: '<%= plural %>',
137
+ },
138
+ <% } else { -%>
139
+ <% if (frontend.sync.wrapInUrlConstructor !== false) { -%>
140
+ url: new URL(
141
+ `<%= frontend.sync.shapeUrl %>/<%= plural %>`,
142
+ typeof window !== 'undefined'
143
+ ? window.location.origin
144
+ : 'http://localhost:5173',
145
+ ).toString(),
146
+ <% } else { -%>
147
+ url: `<%= frontend.sync.shapeUrl %>/<%= plural %>`,
148
+ <% } -%>
149
+ <% } -%>
150
+ <% if (frontend.auth.function) { -%>
151
+ headers: {
152
+ Authorization: <%= frontend.auth.function %>(),
153
+ },
154
+ <% } -%>
155
+ parser: {
156
+ <% Object.entries(frontend.parsers).forEach(([type, fn]) => { -%>
157
+ <%- type %>: <%- fn %>,
158
+ <% }); -%>
159
+ },
160
+ <% if (frontend.sync.columnMapper) { -%>
161
+ <% if (frontend.sync.columnMapperNeedsCall !== false) { -%>
162
+ columnMapper: <%= frontend.sync.columnMapper %>(),
163
+ <% } else { -%>
164
+ columnMapper: <%= frontend.sync.columnMapper %>,
165
+ <% } -%>
166
+ <% } -%>
167
+ },
168
+ schema: <%= camelName %>Schema,
169
+ getKey: (item) => item.id,
170
+ <% if (generate.mutations && (exposeTrpc || exposeRepository)) { -%>
171
+ <% if (exposeTrpc) { -%>
172
+ onInsert: async ({ transaction }) => {
173
+ const { modified } = transaction.mutations[0];
174
+ const result = await trpc.<%= plural %>.create.mutate(modified);
175
+ return { txid: result.txid };
176
+ },
177
+ onUpdate: async ({ transaction }) => {
178
+ const { modified } = transaction.mutations[0];
179
+ const result = await trpc.<%= plural %>.update.mutate({ id: modified.id, data: modified });
180
+ return { txid: result.txid };
181
+ },
182
+ onDelete: async ({ transaction }) => {
183
+ const { original } = transaction.mutations[0];
184
+ const result = await trpc.<%= plural %>.delete.mutate({ id: original.id });
185
+ return { txid: result.txid };
186
+ },
187
+ <% } -%>
188
+ <% } -%>
189
+ }),
190
+ );
191
+
192
+ // ============================================================================
193
+ // Resolution (FK lookup - internal use)
194
+ // ============================================================================
195
+ <% if (existingBelongsTo.length > 0 && generate.fkResolution !== false) { -%>
196
+
197
+ function resolveRelations(entity: <%= className %>): <%= className %>Resolved {
198
+ return {
199
+ ...entity,
200
+ <% existingBelongsTo.forEach((rel) => {
201
+ const targetCamel = rel.target.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
202
+ const targetCamelPlural = targetCamel.endsWith('y') ? targetCamel.slice(0, -1) + 'ies' : targetCamel + 's';
203
+ const targetCollectionVar = generate.collectionNaming === 'plural' ? targetCamelPlural : targetCamel;
204
+ -%>
205
+ <%= rel.name %>: entity.<%= rel.foreignKeyCamel %>
206
+ ? <%= targetCollectionVar %>Collection.state.get(entity.<%= rel.foreignKeyCamel %>)
207
+ : undefined,
208
+ <% }); -%>
209
+ };
210
+ }
211
+ <% } else { -%>
212
+
213
+ function resolveRelations(entity: <%= className %>): <%= className %>Resolved {
214
+ return entity;
215
+ }
216
+ <% } -%>
217
+
218
+ // ============================================================================
219
+ // Hooks (React hooks returning resolved entities)
220
+ // ============================================================================
221
+ <% if (generate.hookStyle === 'useLiveQuery') { -%>
222
+
223
+ /** Get all <%= plural %> with relations resolved */
224
+ export function use<%= classNamePlural %>() {
225
+ const result = useLiveQuery((q) => q.from({ <%= collectionVar %> }), []);
226
+ return {
227
+ <%= returnKey %>: result.data?.map(resolveRelations) ?? [],
228
+ isLoading: result.isLoading,
229
+ };
230
+ }
231
+
232
+ /** Get single <%= camelName %> by ID with relations resolved */
233
+ export function use<%= className %>(id: string | undefined) {
234
+ const result = useLiveQuery(
235
+ (q) => {
236
+ if (!id) return undefined;
237
+ return q
238
+ .from({ <%= collectionVar %> })
239
+ .where(({ <%= collectionVar %> }) => eq(<%= collectionVar %>.id, id));
240
+ },
241
+ [id],
242
+ );
243
+ const entity = result.data?.[0];
244
+ return {
245
+ <%= returnKeySingular %>: entity ? resolveRelations(entity) : undefined,
246
+ isLoading: result.isLoading,
247
+ };
248
+ }
249
+ <% } else { -%>
250
+
251
+ /** Get all <%= plural %> with relations resolved */
252
+ export function use<%= classNamePlural %>(): <%= className %>Resolved[] {
253
+ const raw = <%= collectionVar %>.useMany();
254
+ return raw.map(resolveRelations);
255
+ }
256
+
257
+ /** Get single <%= camelName %> by ID with relations resolved */
258
+ export function use<%= className %>(id: string | undefined): <%= className %>Resolved | undefined {
259
+ const raw = <%= collectionVar %>.useOne(id);
260
+ return raw ? resolveRelations(raw) : undefined;
261
+ }
262
+ <% } -%>
263
+
264
+ <% if (generate.mutations && (exposeTrpc || exposeRepository)) { -%>
265
+ // ============================================================================
266
+ // Mutations (Optimistic updates)
267
+ // ============================================================================
268
+
269
+ export function insert<%= className %>(data: Omit<<%= className %>, 'id'<% if (hasTimestamps) { %> | 'createdAt' | 'updatedAt'<% } %>>) {
270
+ return <%= collectionVar %>.insert({
271
+ id: crypto.randomUUID(),
272
+ <% if (hasTimestamps) { -%>
273
+ createdAt: new Date(),
274
+ updatedAt: new Date(),
275
+ <% } -%>
276
+ ...data,
277
+ } as <%= className %>);
278
+ }
279
+
280
+ export function update<%= className %>(id: string, fn: (draft: <%= className %>) => void) {
281
+ return <%= collectionVar %>.update(id, fn);
282
+ }
283
+
284
+ export function delete<%= className %>(id: string) {
285
+ return <%= collectionVar %>.delete(id);
286
+ }
287
+
288
+ // ============================================================================
289
+ // Mutation Hooks (Error tracking wrappers)
290
+ // ============================================================================
291
+
292
+ type MutationHookResult<TFn extends (...args: any[]) => any> = {
293
+ mutate: TFn;
294
+ error: Error | null;
295
+ clearError: () => void;
296
+ };
297
+
298
+ export function useCreate<%= className %>(): MutationHookResult<typeof insert<%= className %>> {
299
+ const [error, setError] = useState<Error | null>(null);
300
+
301
+ const mutate = useCallback<typeof insert<%= className %>>((data) => {
302
+ try {
303
+ insert<%= className %>(data);
304
+ setError(null);
305
+ } catch (err) {
306
+ const error = err instanceof Error ? err : new Error(String(err));
307
+ setError(error);
308
+ throw error;
309
+ }
310
+ }, []);
311
+
312
+ const clearError = useCallback(() => setError(null), []);
313
+ return { mutate, error, clearError };
314
+ }
315
+
316
+ export function useUpdate<%= className %>(): MutationHookResult<typeof update<%= className %>> {
317
+ const [error, setError] = useState<Error | null>(null);
318
+
319
+ const mutate = useCallback<typeof update<%= className %>>((id, fn) => {
320
+ try {
321
+ update<%= className %>(id, fn);
322
+ setError(null);
323
+ } catch (err) {
324
+ const error = err instanceof Error ? err : new Error(String(err));
325
+ setError(error);
326
+ throw error;
327
+ }
328
+ }, []);
329
+
330
+ const clearError = useCallback(() => setError(null), []);
331
+ return { mutate, error, clearError };
332
+ }
333
+
334
+ export function useDelete<%= className %>(): MutationHookResult<typeof delete<%= className %>> {
335
+ const [error, setError] = useState<Error | null>(null);
336
+
337
+ const mutate = useCallback<typeof delete<%= className %>>((id) => {
338
+ try {
339
+ delete<%= className %>(id);
340
+ setError(null);
341
+ } catch (err) {
342
+ const error = err instanceof Error ? err : new Error(String(err));
343
+ setError(error);
344
+ throw error;
345
+ }
346
+ }, []);
347
+
348
+ const clearError = useCallback(() => setError(null), []);
349
+ return { mutate, error, clearError };
350
+ }
351
+ <% } -%>
352
+ <% if (generate.fieldMetadata) { -%>
353
+
354
+ // ============================================================================
355
+ // Field Metadata (for DataGrid, forms, admin)
356
+ // ============================================================================
357
+
358
+ export const <%= camelName %>Fields: Record<string, FieldMeta<<%= className %>Resolved>> = {
359
+ <% fields.forEach((field) => { -%>
360
+ <% // Skip entity ref internal fields from metadata display
361
+ if (field.isEntityRefType || field.isEntityRefId) return;
362
+ -%>
363
+ <%= field.camelName %>: {
364
+ field: '<%= field.camelName %>',
365
+ label: '<%= field.ui_label %>',
366
+ type: '<%= field.ui_type %>' as FieldType,
367
+ importance: '<%= field.ui_importance %>' as FieldImportance,
368
+ <% if (field.ui_sortable) { -%>
369
+ sortable: true,
370
+ <% } -%>
371
+ <% if (field.ui_filterable) { -%>
372
+ filterable: true,
373
+ <% } -%>
374
+ <% if (field.ui_format) { -%>
375
+ format: <%- JSON.stringify(field.ui_format) %>,
376
+ <% } -%>
377
+ <% if (field.hasChoices) { -%>
378
+ choices: <%- JSON.stringify(field.choices) %>,
379
+ <% } -%>
380
+ <% if (field.foreignKey) { -%>
381
+ reference: '<%= field.foreignKey.split('.')[0] %>',
382
+ <% } -%>
383
+ },
384
+ <% }); -%>
385
+ <% // Add resolved relation fields to metadata
386
+ belongsToRelations.forEach((rel) => { -%>
387
+ <%= rel.name %>: {
388
+ field: '<%= rel.name %>',
389
+ label: '<%= rel.targetClass.replace(/([A-Z])/g, ' $1').trim() %>',
390
+ type: 'entity' as FieldType,
391
+ importance: 'secondary' as FieldImportance,
392
+ reference: '<%= rel.targetPlural %>',
393
+ },
394
+ <% }); -%>
395
+ <% if (hasTimestamps) { -%>
396
+ createdAt: {
397
+ field: 'createdAt',
398
+ label: 'Created',
399
+ type: 'datetime' as FieldType,
400
+ importance: 'tertiary' as FieldImportance,
401
+ format: { dateFormat: 'relative' },
402
+ },
403
+ updatedAt: {
404
+ field: 'updatedAt',
405
+ label: 'Updated',
406
+ type: 'datetime' as FieldType,
407
+ importance: 'tertiary' as FieldImportance,
408
+ format: { dateFormat: 'relative' },
409
+ },
410
+ <% } -%>
411
+ };
412
+
413
+ export const <%= camelName %>Metadata = {
414
+ name: '<%= name %>',
415
+ plural: '<%= plural %>',
416
+ displayName: '<%= className.replace(/([A-Z])/g, ' $1').trim() %>',
417
+ displayNamePlural: '<%= classNamePlural.replace(/([A-Z])/g, ' $1').trim() %>',
418
+
419
+ fields: <%= camelName %>Fields,
420
+
421
+ // Display configuration
422
+ primaryFields: [
423
+ <% fields.filter(f => f.ui_importance === 'primary').forEach(f => { -%>
424
+ '<%= f.camelName %>',
425
+ <% }); -%>
426
+ ],
427
+ searchFields: [
428
+ <% fields.filter(f => f.ui_filterable).forEach(f => { -%>
429
+ '<%= f.camelName %>',
430
+ <% }); -%>
431
+ ],
432
+ defaultSort: { field: '<% if (hasTimestamps) { %>createdAt<% } else { %>id<% } %>', direction: 'desc' as const },
433
+
434
+ // Capabilities
435
+ capabilities: {
436
+ create: <%= exposeRepository || exposeTrpc %>,
437
+ update: <%= exposeRepository || exposeTrpc %>,
438
+ delete: <%= exposeRepository || exposeTrpc %>,
439
+ list: true,
440
+ get: true,
441
+ },
442
+ } as const;
443
+ <% } -%>
444
+
445
+ // ============================================================================
446
+ // Export bundle for registry
447
+ // ============================================================================
448
+
449
+ export const <%= camelName %> = {
450
+ // Collection
451
+ collection: <%= collectionVar %>,
452
+
453
+ // Hooks
454
+ useMany: use<%= classNamePlural %>,
455
+ useOne: use<%= className %>,
456
+ <% if (generate.mutations && (exposeTrpc || exposeRepository)) { -%>
457
+
458
+ // Mutations
459
+ insert: insert<%= className %>,
460
+ update: update<%= className %>,
461
+ delete: delete<%= className %>,
462
+
463
+ // Mutation Hooks
464
+ useCreate: useCreate<%= className %>,
465
+ useUpdate: useUpdate<%= className %>,
466
+ useDelete: useDelete<%= className %>,
467
+ <% } -%>
468
+ <% if (generate.fieldMetadata) { -%>
469
+
470
+ // Metadata
471
+ fields: <%= camelName %>Fields,
472
+ metadata: <%= camelName %>Metadata,
473
+ <% } -%>
474
+ } as const;
@@ -0,0 +1,104 @@
1
+ ---
2
+ to: "<%= generate.structure === 'entity-first' ? `${locations.frontendGenerated.path}/${name}/fields.ts` : generate.structure === 'concern-first' ? `${locations.frontendGenerated.path}/fields/${name}.ts` : '' %>"
3
+ skip_if: <%= !frontendEnabled || (generate.structure === 'monolithic' || !generate.fieldMetadata) %>
4
+ force: true
5
+ ---
6
+ /**
7
+ * <%= className %> Field Metadata
8
+ * Generated by entity codegen - do not edit directly
9
+ *
10
+ * Field definitions for DataGrid, forms, and admin interfaces
11
+ */
12
+
13
+ import type { FieldMeta, FieldType, FieldImportance } from '<%= locations.frontendFieldMetaTypes.import %>/field-meta';
14
+ <% if (generate.structure === 'entity-first') { -%>
15
+ import type { <%= className %>Resolved } from './types';
16
+ <% } else if (generate.structure === 'concern-first') { -%>
17
+ import type { <%= className %>Resolved } from '../types/<%= name %>';
18
+ <% } -%>
19
+
20
+ export const <%= camelName %>Fields: Record<string, FieldMeta<<%= className %>Resolved>> = {
21
+ <% fields.forEach((field) => { -%>
22
+ <% // Skip entity ref internal fields from metadata display
23
+ if (field.isEntityRefType || field.isEntityRefId) return;
24
+ -%>
25
+ <%= field.camelName %>: {
26
+ field: '<%= field.camelName %>',
27
+ label: '<%= field.ui_label %>',
28
+ type: '<%= field.ui_type %>' as FieldType,
29
+ importance: '<%= field.ui_importance %>' as FieldImportance,
30
+ <% if (field.ui_sortable) { -%>
31
+ sortable: true,
32
+ <% } -%>
33
+ <% if (field.ui_filterable) { -%>
34
+ filterable: true,
35
+ <% } -%>
36
+ <% if (field.ui_format) { -%>
37
+ format: <%- JSON.stringify(field.ui_format) %>,
38
+ <% } -%>
39
+ <% if (field.hasChoices) { -%>
40
+ choices: <%- JSON.stringify(field.choices) %>,
41
+ <% } -%>
42
+ <% if (field.foreignKey) { -%>
43
+ reference: '<%= field.foreignKey.split('.')[0] %>',
44
+ <% } -%>
45
+ },
46
+ <% }); -%>
47
+ <% // Add resolved relation fields to metadata
48
+ belongsToRelations.forEach((rel) => { -%>
49
+ <%= rel.name %>: {
50
+ field: '<%= rel.name %>',
51
+ label: '<%= rel.targetClass.replace(/([A-Z])/g, ' $1').trim() %>',
52
+ type: 'entity' as FieldType,
53
+ importance: 'secondary' as FieldImportance,
54
+ reference: '<%= rel.targetPlural %>',
55
+ },
56
+ <% }); -%>
57
+ <% if (hasTimestamps) { -%>
58
+ createdAt: {
59
+ field: 'createdAt',
60
+ label: 'Created',
61
+ type: 'datetime' as FieldType,
62
+ importance: 'tertiary' as FieldImportance,
63
+ format: { dateFormat: 'relative' },
64
+ },
65
+ updatedAt: {
66
+ field: 'updatedAt',
67
+ label: 'Updated',
68
+ type: 'datetime' as FieldType,
69
+ importance: 'tertiary' as FieldImportance,
70
+ format: { dateFormat: 'relative' },
71
+ },
72
+ <% } -%>
73
+ };
74
+
75
+ export const <%= camelName %>Metadata = {
76
+ name: '<%= name %>',
77
+ plural: '<%= plural %>',
78
+ displayName: '<%= className.replace(/([A-Z])/g, ' $1').trim() %>',
79
+ displayNamePlural: '<%= classNamePlural.replace(/([A-Z])/g, ' $1').trim() %>',
80
+
81
+ fields: <%= camelName %>Fields,
82
+
83
+ // Display configuration
84
+ primaryFields: [
85
+ <% fields.filter(f => f.ui_importance === 'primary').forEach(f => { -%>
86
+ '<%= f.camelName %>',
87
+ <% }); -%>
88
+ ],
89
+ searchFields: [
90
+ <% fields.filter(f => f.ui_filterable).forEach(f => { -%>
91
+ '<%= f.camelName %>',
92
+ <% }); -%>
93
+ ],
94
+ defaultSort: { field: '<% if (hasTimestamps) { %>createdAt<% } else { %>id<% } %>', direction: 'desc' as const },
95
+
96
+ // Capabilities
97
+ capabilities: {
98
+ create: <%= exposeRepository || exposeTrpc %>,
99
+ update: <%= exposeRepository || exposeTrpc %>,
100
+ delete: <%= exposeRepository || exposeTrpc %>,
101
+ list: true,
102
+ get: true,
103
+ },
104
+ } as const;
@@ -0,0 +1,73 @@
1
+ ---
2
+ to: "<%= generate.structure === 'entity-first' ? `${locations.frontendGenerated.path}/${generate.fileNaming === 'plural' ? plural : name}/hooks.ts` : generate.structure === 'concern-first' ? `${locations.frontendGenerated.path}/hooks/${generate.fileNaming === 'plural' ? plural : name}.ts` : '' %>"
3
+ skip_if: <%= !frontendEnabled || (generate.structure === 'monolithic') %>
4
+ force: true
5
+ ---
6
+ /**
7
+ * <%= className %> Hooks
8
+ * Generated by entity codegen - do not edit directly
9
+ *
10
+ * React hooks returning resolved entities with relations
11
+ */
12
+
13
+ <%
14
+ // Collection variable name depends on collectionNaming config
15
+ const collectionVar = generate.collectionNaming === 'plural' ? collectionVarNamePlural : collectionVarName;
16
+ // File name for imports depends on fileNaming config
17
+ const fileName = generate.fileNaming === 'plural' ? plural : name;
18
+ // Hook return key depends on hookReturnStyle config
19
+ const returnKey = generate.hookReturnStyle === 'named' ? pluralCamelName : 'data';
20
+ const returnKeySingular = generate.hookReturnStyle === 'named' ? camelName : 'data';
21
+ -%>
22
+ <% if (generate.hookStyle === 'useLiveQuery') { -%>
23
+ import { useLiveQuery, eq } from '@tanstack/react-db';
24
+ <% } -%>
25
+ <% if (generate.structure === 'entity-first') { -%>
26
+ import { <%= collectionVar %>, resolveRelations } from './collection';
27
+ import type { <%= className %>Resolved } from './types';
28
+ <% } else if (generate.structure === 'concern-first') { -%>
29
+ import { <%= collectionVar %>, resolveRelations } from '../collections/<%= fileName %>';
30
+ import type { <%= className %>Resolved } from '../types/<%= fileName %>';
31
+ <% } -%>
32
+ <% if (generate.hookStyle === 'useLiveQuery') { -%>
33
+
34
+ /** Get all <%= plural %> with relations resolved */
35
+ export function use<%= classNamePlural %>() {
36
+ const result = useLiveQuery((q) => q.from({ <%= collectionVar %> }), []);
37
+ return {
38
+ <%= returnKey %>: result.data?.map(resolveRelations) ?? [],
39
+ isLoading: result.isLoading,
40
+ };
41
+ }
42
+
43
+ /** Get single <%= camelName %> by ID with relations resolved */
44
+ export function use<%= className %>(id: string | undefined) {
45
+ const result = useLiveQuery(
46
+ (q) => {
47
+ if (!id) return undefined;
48
+ return q
49
+ .from({ <%= collectionVar %> })
50
+ .where(({ <%= collectionVar %> }) => eq(<%= collectionVar %>.id, id));
51
+ },
52
+ [id],
53
+ );
54
+ const entity = result.data?.[0];
55
+ return {
56
+ <%= returnKeySingular %>: entity ? resolveRelations(entity) : undefined,
57
+ isLoading: result.isLoading,
58
+ };
59
+ }
60
+ <% } else { -%>
61
+
62
+ /** Get all <%= plural %> with relations resolved */
63
+ export function use<%= classNamePlural %>(): <%= className %>Resolved[] {
64
+ const raw = <%= collectionVar %>.useMany();
65
+ return raw.map(resolveRelations);
66
+ }
67
+
68
+ /** Get single <%= camelName %> by ID with relations resolved */
69
+ export function use<%= className %>(id: string | undefined): <%= className %>Resolved | undefined {
70
+ const raw = <%= collectionVar %>.useOne(id);
71
+ return raw ? resolveRelations(raw) : undefined;
72
+ }
73
+ <% } -%>
@@ -0,0 +1,21 @@
1
+ ---
2
+ to: "<%= generate.structure === 'entity-first' ? `${locations.frontendGenerated.path}/${name}/index.ts` : '' %>"
3
+ skip_if: <%= !frontendEnabled || (generate.structure !== 'entity-first') %>
4
+ force: true
5
+ ---
6
+ /**
7
+ * <%= className %> - Entity Module
8
+ * Generated by entity codegen - do not edit directly
9
+ *
10
+ * Barrel export for all <%= className %> components
11
+ */
12
+
13
+ export * from './types';
14
+ export * from './collection';
15
+ export * from './hooks';
16
+ <% if (generate.mutations && (exposeTrpc || exposeRepository)) { %>
17
+ export * from './mutations';
18
+ <% } %>
19
+ <% if (generate.fieldMetadata) { %>
20
+ export * from './fields';
21
+ <% } %>