@tailor-platform/erp-kit 0.1.1 → 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 (342) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +158 -62
  3. package/dist/cli.js +1010 -270
  4. package/package.json +11 -8
  5. package/schemas/module/command.yml +1 -0
  6. package/schemas/module/model.yml +14 -0
  7. package/schemas/module/query.yml +53 -0
  8. package/skills/{app-compose-1-requirement-analysis → erp-kit-app-1-requirements}/SKILL.md +2 -2
  9. package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/SKILL.md +3 -3
  10. package/skills/{app-compose-3-doc-review → erp-kit-app-3-doc-review}/SKILL.md +2 -2
  11. package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/SKILL.md +3 -3
  12. package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/SKILL.md +4 -4
  13. package/skills/{app-compose-6-implementation-spec → erp-kit-app-6-impl-spec}/SKILL.md +3 -3
  14. package/skills/{mock-scenario → erp-kit-mock-scenario}/SKILL.md +1 -1
  15. package/skills/{1-module-docs → erp-kit-module-1-docs}/SKILL.md +2 -2
  16. package/skills/{2-module-feature-breakdown → erp-kit-module-2-feature-breakdown}/SKILL.md +13 -9
  17. package/skills/erp-kit-module-2-feature-breakdown/references/naming.md +59 -0
  18. package/skills/{3-module-doc-review → erp-kit-module-3-doc-review}/SKILL.md +83 -25
  19. package/skills/erp-kit-module-4-tdd/SKILL.md +94 -0
  20. package/skills/erp-kit-module-4-tdd/references/cross-module-dependency.md +133 -0
  21. package/skills/{4-module-tdd-implementation → erp-kit-module-4-tdd}/references/db-relations.md +5 -1
  22. package/skills/{4-module-tdd-implementation → erp-kit-module-4-tdd}/references/exports.md +1 -1
  23. package/skills/erp-kit-module-4-tdd/references/generated-code.md +32 -0
  24. package/skills/{5-module-implementation-review → erp-kit-module-5-impl-review}/SKILL.md +46 -44
  25. package/skills/erp-kit-module-5-impl-review/references/commands.md +62 -0
  26. package/skills/erp-kit-module-5-impl-review/references/errors.md +10 -0
  27. package/skills/{5-module-implementation-review → erp-kit-module-5-impl-review}/references/testing.md +1 -1
  28. package/skills/erp-kit-module-shared/SKILL.md +16 -0
  29. package/skills/erp-kit-module-shared/references/commands.md +203 -0
  30. package/skills/erp-kit-module-shared/references/errors.md +35 -0
  31. package/skills/erp-kit-module-shared/references/queries.md +168 -0
  32. package/skills/erp-kit-module-shared/references/structure.md +36 -0
  33. package/skills/{3-module-doc-review → erp-kit-module-shared}/references/testing.md +4 -3
  34. package/skills/erp-kit-update/SKILL.md +64 -0
  35. package/src/cli.doc.test.ts +65 -0
  36. package/src/cli.ts +3 -117
  37. package/src/commands/app/index.ts +74 -0
  38. package/src/commands/check.test.ts +3 -2
  39. package/src/commands/check.ts +3 -2
  40. package/src/commands/index.ts +73 -0
  41. package/src/commands/init.test.ts +22 -5
  42. package/src/commands/init.ts +25 -16
  43. package/src/commands/license.ts +193 -0
  44. package/src/commands/mock/index.ts +2 -2
  45. package/src/commands/mock/start.ts +1 -1
  46. package/src/commands/mock/validate.test.ts +1 -1
  47. package/src/commands/module/generate.ts +35 -0
  48. package/src/commands/module/index.ts +87 -0
  49. package/src/commands/module/list.test.ts +57 -0
  50. package/src/commands/module/list.ts +64 -0
  51. package/src/commands/scaffold-templates.ts +65 -0
  52. package/src/commands/scaffold.test.ts +97 -2
  53. package/src/commands/scaffold.ts +24 -3
  54. package/src/commands/sync-check.test.ts +88 -1
  55. package/src/commands/sync-check.ts +41 -2
  56. package/src/generator/generate-code.test.ts +200 -0
  57. package/src/generator/generate-code.ts +260 -0
  58. package/src/generator/parse-command-doc.test.ts +159 -0
  59. package/src/generator/parse-command-doc.ts +116 -0
  60. package/src/integration.test.ts +6 -8
  61. package/src/module.ts +10 -9
  62. package/src/modules/item-management/README.md +38 -0
  63. package/src/modules/item-management/command/activateItem.generated.ts +6 -0
  64. package/src/modules/item-management/command/activateItem.test.ts +76 -0
  65. package/src/modules/item-management/command/activateItem.ts +42 -0
  66. package/src/modules/item-management/command/assignItemToTaxonomy.generated.ts +6 -0
  67. package/src/modules/item-management/command/assignItemToTaxonomy.test.ts +88 -0
  68. package/src/modules/item-management/command/assignItemToTaxonomy.ts +63 -0
  69. package/src/modules/item-management/command/createItem.generated.ts +6 -0
  70. package/src/modules/item-management/command/createItem.test.ts +152 -0
  71. package/src/modules/item-management/command/createItem.ts +72 -0
  72. package/src/modules/item-management/command/createTaxonomyNode.generated.ts +6 -0
  73. package/src/modules/item-management/command/createTaxonomyNode.test.ts +126 -0
  74. package/src/modules/item-management/command/createTaxonomyNode.ts +70 -0
  75. package/src/modules/item-management/command/deactivateItem.generated.ts +6 -0
  76. package/src/modules/item-management/command/deactivateItem.test.ts +76 -0
  77. package/src/modules/item-management/command/deactivateItem.ts +42 -0
  78. package/src/modules/item-management/command/deleteItem.generated.ts +6 -0
  79. package/src/modules/item-management/command/deleteItem.test.ts +61 -0
  80. package/src/modules/item-management/command/deleteItem.ts +38 -0
  81. package/src/modules/item-management/command/deleteTaxonomyNode.generated.ts +6 -0
  82. package/src/modules/item-management/command/deleteTaxonomyNode.test.ts +73 -0
  83. package/src/modules/item-management/command/deleteTaxonomyNode.ts +50 -0
  84. package/src/modules/item-management/command/moveTaxonomyNode.generated.ts +6 -0
  85. package/src/modules/item-management/command/moveTaxonomyNode.test.ts +136 -0
  86. package/src/modules/item-management/command/moveTaxonomyNode.ts +85 -0
  87. package/src/modules/item-management/command/reactivateItem.generated.ts +6 -0
  88. package/src/modules/item-management/command/reactivateItem.test.ts +76 -0
  89. package/src/modules/item-management/command/reactivateItem.ts +42 -0
  90. package/src/modules/item-management/command/removeItemFromTaxonomy.generated.ts +6 -0
  91. package/src/modules/item-management/command/removeItemFromTaxonomy.test.ts +43 -0
  92. package/src/modules/item-management/command/removeItemFromTaxonomy.ts +30 -0
  93. package/src/modules/item-management/command/updateItem.generated.ts +6 -0
  94. package/src/modules/item-management/command/updateItem.test.ts +178 -0
  95. package/src/modules/item-management/command/updateItem.ts +103 -0
  96. package/src/modules/item-management/command/updateTaxonomyNode.generated.ts +6 -0
  97. package/src/modules/item-management/command/updateTaxonomyNode.test.ts +88 -0
  98. package/src/modules/item-management/command/updateTaxonomyNode.ts +62 -0
  99. package/src/modules/item-management/db/item.ts +47 -0
  100. package/src/modules/item-management/db/itemTaxonomyAssignment.ts +49 -0
  101. package/src/modules/item-management/db/taxonomyNode.ts +34 -0
  102. package/src/modules/item-management/docs/commands/ActivateItem.md +32 -0
  103. package/src/modules/item-management/docs/commands/AssignItemToTaxonomy.md +38 -0
  104. package/src/modules/item-management/docs/commands/CreateItem.md +44 -0
  105. package/src/modules/item-management/docs/commands/CreateTaxonomyNode.md +44 -0
  106. package/src/modules/item-management/docs/commands/DeactivateItem.md +34 -0
  107. package/src/modules/item-management/docs/commands/DeleteItem.md +35 -0
  108. package/src/modules/item-management/docs/commands/DeleteTaxonomyNode.md +39 -0
  109. package/src/modules/item-management/docs/commands/MoveTaxonomyNode.md +45 -0
  110. package/src/modules/item-management/docs/commands/ReactivateItem.md +34 -0
  111. package/src/modules/item-management/docs/commands/RemoveItemFromTaxonomy.md +30 -0
  112. package/src/modules/item-management/docs/commands/UpdateItem.md +55 -0
  113. package/src/modules/item-management/docs/commands/UpdateTaxonomyNode.md +36 -0
  114. package/src/modules/item-management/docs/features/item-lifecycle.md +60 -0
  115. package/src/modules/item-management/docs/features/item-taxonomy.md +65 -0
  116. package/src/modules/item-management/docs/models/ItemTaxonomyAssignment.md +36 -0
  117. package/src/modules/item-management/docs/models/TaxonomyNode.md +47 -0
  118. package/src/modules/item-management/docs/models/item.md +59 -0
  119. package/src/modules/item-management/docs/queries/CalculateNodeDepth.md +36 -0
  120. package/src/modules/item-management/docs/queries/CalculateSubtreeDepth.md +40 -0
  121. package/src/modules/item-management/docs/queries/DetectCircularReference.md +41 -0
  122. package/src/modules/item-management/docs/queries/GetItem.md +38 -0
  123. package/src/modules/item-management/docs/queries/GetItemTaxonomyAssignment.md +29 -0
  124. package/src/modules/item-management/docs/queries/GetTaxonomyNode.md +35 -0
  125. package/src/modules/item-management/docs/queries/GetTaxonomyNodeAssignments.md +29 -0
  126. package/src/modules/item-management/docs/queries/GetTaxonomyNodeChildren.md +29 -0
  127. package/src/modules/item-management/generated/enums.ts +9 -0
  128. package/src/modules/item-management/generated/kysely-tailordb.ts +62 -0
  129. package/src/modules/item-management/index.ts +53 -0
  130. package/src/modules/item-management/lib/_db_deps.ts +13 -0
  131. package/src/modules/item-management/lib/errors.generated.ts +117 -0
  132. package/src/modules/item-management/lib/permissions.generated.ts +17 -0
  133. package/src/modules/item-management/lib/types.ts +19 -0
  134. package/src/modules/item-management/module.ts +97 -0
  135. package/src/modules/item-management/query/calculateNodeDepth.generated.ts +5 -0
  136. package/src/modules/item-management/query/calculateNodeDepth.test.ts +56 -0
  137. package/src/modules/item-management/query/calculateNodeDepth.ts +28 -0
  138. package/src/modules/item-management/query/calculateSubtreeDepth.generated.ts +5 -0
  139. package/src/modules/item-management/query/calculateSubtreeDepth.test.ts +75 -0
  140. package/src/modules/item-management/query/calculateSubtreeDepth.ts +29 -0
  141. package/src/modules/item-management/query/detectCircularReference.generated.ts +5 -0
  142. package/src/modules/item-management/query/detectCircularReference.test.ts +61 -0
  143. package/src/modules/item-management/query/detectCircularReference.ts +32 -0
  144. package/src/modules/item-management/query/getItem.generated.ts +5 -0
  145. package/src/modules/item-management/query/getItem.test.ts +67 -0
  146. package/src/modules/item-management/query/getItem.ts +20 -0
  147. package/src/modules/item-management/query/getItemTaxonomyAssignment.generated.ts +5 -0
  148. package/src/modules/item-management/query/getItemTaxonomyAssignment.test.ts +25 -0
  149. package/src/modules/item-management/query/getItemTaxonomyAssignment.ts +18 -0
  150. package/src/modules/item-management/query/getTaxonomyNode.generated.ts +5 -0
  151. package/src/modules/item-management/query/getTaxonomyNode.test.ts +47 -0
  152. package/src/modules/item-management/query/getTaxonomyNode.ts +18 -0
  153. package/src/modules/item-management/query/getTaxonomyNodeAssignments.generated.ts +5 -0
  154. package/src/modules/item-management/query/getTaxonomyNodeAssignments.test.ts +25 -0
  155. package/src/modules/item-management/query/getTaxonomyNodeAssignments.ts +16 -0
  156. package/src/modules/item-management/query/getTaxonomyNodeChildren.generated.ts +5 -0
  157. package/src/modules/item-management/query/getTaxonomyNodeChildren.test.ts +34 -0
  158. package/src/modules/item-management/query/getTaxonomyNodeChildren.ts +16 -0
  159. package/src/modules/item-management/tailor.config.ts +11 -0
  160. package/src/modules/item-management/testing/fixtures.ts +81 -0
  161. package/src/modules/primitives/command/activateCategory.generated.ts +6 -0
  162. package/src/modules/primitives/command/activateCategory.test.ts +11 -29
  163. package/src/modules/primitives/command/activateCategory.ts +27 -34
  164. package/src/modules/primitives/command/activateCurrency.generated.ts +6 -0
  165. package/src/modules/primitives/command/activateCurrency.test.ts +11 -29
  166. package/src/modules/primitives/command/activateCurrency.ts +27 -34
  167. package/src/modules/primitives/command/activateUnit.generated.ts +6 -0
  168. package/src/modules/primitives/command/activateUnit.test.ts +11 -15
  169. package/src/modules/primitives/command/activateUnit.ts +27 -34
  170. package/src/modules/primitives/command/createCategory.generated.ts +6 -0
  171. package/src/modules/primitives/command/createCategory.test.ts +27 -39
  172. package/src/modules/primitives/command/createCategory.ts +53 -62
  173. package/src/modules/primitives/command/createCurrency.generated.ts +6 -0
  174. package/src/modules/primitives/command/createCurrency.test.ts +78 -71
  175. package/src/modules/primitives/command/createCurrency.ts +43 -48
  176. package/src/modules/primitives/command/createExchangeRate.generated.ts +6 -0
  177. package/src/modules/primitives/command/createExchangeRate.test.ts +101 -100
  178. package/src/modules/primitives/command/createExchangeRate.ts +50 -59
  179. package/src/modules/primitives/command/createUnit.generated.ts +6 -0
  180. package/src/modules/primitives/command/createUnit.test.ts +92 -95
  181. package/src/modules/primitives/command/createUnit.ts +54 -57
  182. package/src/modules/primitives/command/deactivateCategory.generated.ts +6 -0
  183. package/src/modules/primitives/command/deactivateCategory.test.ts +27 -28
  184. package/src/modules/primitives/command/deactivateCategory.ts +43 -50
  185. package/src/modules/primitives/command/deactivateCurrency.generated.ts +6 -0
  186. package/src/modules/primitives/command/deactivateCurrency.test.ts +23 -38
  187. package/src/modules/primitives/command/deactivateCurrency.ts +31 -38
  188. package/src/modules/primitives/command/deactivateUnit.generated.ts +6 -0
  189. package/src/modules/primitives/command/deactivateUnit.test.ts +27 -23
  190. package/src/modules/primitives/command/deactivateUnit.ts +39 -49
  191. package/src/modules/primitives/command/setBaseCurrency.generated.ts +6 -0
  192. package/src/modules/primitives/command/setBaseCurrency.test.ts +40 -33
  193. package/src/modules/primitives/command/setBaseCurrency.ts +43 -50
  194. package/src/modules/primitives/command/setReferenceUnit.generated.ts +6 -0
  195. package/src/modules/primitives/command/setReferenceUnit.test.ts +39 -35
  196. package/src/modules/primitives/command/setReferenceUnit.ts +46 -59
  197. package/src/modules/primitives/db/unit.ts +13 -3
  198. package/src/modules/primitives/docs/commands/ActivateCategory.md +1 -2
  199. package/src/modules/primitives/docs/commands/ActivateCurrency.md +1 -2
  200. package/src/modules/primitives/docs/commands/ActivateUnit.md +1 -2
  201. package/src/modules/primitives/docs/commands/CreateCategory.md +1 -4
  202. package/src/modules/primitives/docs/commands/CreateCurrency.md +3 -4
  203. package/src/modules/primitives/docs/commands/CreateExchangeRate.md +4 -5
  204. package/src/modules/primitives/docs/commands/CreateUnit.md +5 -5
  205. package/src/modules/primitives/docs/commands/DeactivateCategory.md +2 -3
  206. package/src/modules/primitives/docs/commands/DeactivateCurrency.md +2 -3
  207. package/src/modules/primitives/docs/commands/DeactivateUnit.md +2 -3
  208. package/src/modules/primitives/docs/commands/SetBaseCurrency.md +2 -3
  209. package/src/modules/primitives/docs/commands/SetReferenceUnit.md +2 -3
  210. package/src/modules/primitives/docs/models/Currency.md +4 -0
  211. package/src/modules/primitives/docs/models/ExchangeRate.md +4 -1
  212. package/src/modules/primitives/docs/models/Unit.md +4 -1
  213. package/src/modules/primitives/docs/models/UoMCategory.md +2 -0
  214. package/src/modules/primitives/docs/{commands → queries}/ConvertAmount.md +3 -5
  215. package/src/modules/primitives/docs/{commands → queries}/ConvertQuantity.md +3 -5
  216. package/src/modules/primitives/docs/queries/GetBaseCurrency.md +32 -0
  217. package/src/modules/primitives/docs/queries/GetCurrency.md +36 -0
  218. package/src/modules/primitives/docs/queries/GetUnit.md +36 -0
  219. package/src/modules/primitives/docs/queries/GetUoMCategory.md +36 -0
  220. package/src/modules/primitives/docs/queries/ListUnitsByCategory.md +26 -0
  221. package/src/modules/primitives/generated/kysely-tailordb.ts +24 -45
  222. package/src/modules/primitives/index.ts +17 -6
  223. package/src/modules/primitives/lib/errors.generated.ts +112 -0
  224. package/src/modules/primitives/{permissions.ts → lib/permissions.generated.ts} +9 -10
  225. package/src/modules/primitives/module.ts +39 -27
  226. package/src/modules/primitives/query/convertAmount.generated.ts +5 -0
  227. package/src/modules/primitives/{command → query}/convertAmount.test.ts +4 -21
  228. package/src/modules/primitives/query/convertAmount.ts +121 -0
  229. package/src/modules/primitives/query/convertQuantity.generated.ts +5 -0
  230. package/src/modules/primitives/{command → query}/convertQuantity.test.ts +8 -15
  231. package/src/modules/primitives/query/convertQuantity.ts +63 -0
  232. package/src/modules/primitives/query/getBaseCurrency.generated.ts +5 -0
  233. package/src/modules/primitives/query/getBaseCurrency.test.ts +28 -0
  234. package/src/modules/primitives/query/getBaseCurrency.ts +16 -0
  235. package/src/modules/primitives/query/getCurrency.generated.ts +5 -0
  236. package/src/modules/primitives/query/getCurrency.test.ts +47 -0
  237. package/src/modules/primitives/query/getCurrency.ts +18 -0
  238. package/src/modules/primitives/query/getUnit.generated.ts +5 -0
  239. package/src/modules/primitives/query/getUnit.test.ts +47 -0
  240. package/src/modules/primitives/query/getUnit.ts +18 -0
  241. package/src/modules/primitives/query/getUoMCategory.generated.ts +5 -0
  242. package/src/modules/primitives/query/getUoMCategory.test.ts +47 -0
  243. package/src/modules/primitives/query/getUoMCategory.ts +18 -0
  244. package/src/modules/primitives/query/listUnitsByCategory.generated.ts +5 -0
  245. package/src/modules/primitives/query/listUnitsByCategory.ts +16 -0
  246. package/src/modules/primitives/tailor.config.ts +3 -3
  247. package/src/modules/shared/defineCommand.test.ts +23 -10
  248. package/src/modules/shared/defineCommand.ts +23 -10
  249. package/src/modules/shared/defineQuery.test.ts +28 -0
  250. package/src/modules/shared/defineQuery.ts +16 -0
  251. package/src/modules/shared/internal.ts +3 -1
  252. package/src/modules/shared/requirePermission.test.ts +22 -21
  253. package/src/modules/shared/requirePermission.ts +8 -2
  254. package/src/modules/shared/result.ts +12 -0
  255. package/src/modules/shared/types.ts +8 -0
  256. package/src/modules/testing/index.ts +36 -11
  257. package/src/modules/user-management/command/activateUser.generated.ts +6 -0
  258. package/src/modules/user-management/command/activateUser.test.ts +27 -27
  259. package/src/modules/user-management/command/activateUser.ts +40 -48
  260. package/src/modules/user-management/command/assignPermissionToRole.generated.ts +6 -0
  261. package/src/modules/user-management/command/assignPermissionToRole.test.ts +42 -43
  262. package/src/modules/user-management/command/assignPermissionToRole.ts +59 -62
  263. package/src/modules/user-management/command/assignRoleToUser.generated.ts +6 -0
  264. package/src/modules/user-management/command/assignRoleToUser.test.ts +70 -63
  265. package/src/modules/user-management/command/assignRoleToUser.ts +63 -66
  266. package/src/modules/user-management/command/createPermission.generated.ts +6 -0
  267. package/src/modules/user-management/command/createPermission.test.ts +45 -38
  268. package/src/modules/user-management/command/createPermission.ts +42 -46
  269. package/src/modules/user-management/command/createRole.generated.ts +6 -0
  270. package/src/modules/user-management/command/createRole.test.ts +30 -29
  271. package/src/modules/user-management/command/createRole.ts +33 -33
  272. package/src/modules/user-management/command/createUser.generated.ts +6 -0
  273. package/src/modules/user-management/command/createUser.test.ts +64 -42
  274. package/src/modules/user-management/command/createUser.ts +54 -56
  275. package/src/modules/user-management/command/deactivateUser.generated.ts +6 -0
  276. package/src/modules/user-management/command/deactivateUser.test.ts +27 -27
  277. package/src/modules/user-management/command/deactivateUser.ts +40 -48
  278. package/src/modules/user-management/command/logAuditEvent.generated.ts +6 -0
  279. package/src/modules/user-management/command/logAuditEvent.test.ts +50 -42
  280. package/src/modules/user-management/command/logAuditEvent.ts +25 -28
  281. package/src/modules/user-management/command/reactivateUser.generated.ts +6 -0
  282. package/src/modules/user-management/command/reactivateUser.test.ts +31 -27
  283. package/src/modules/user-management/command/reactivateUser.ts +40 -48
  284. package/src/modules/user-management/command/revokePermissionFromRole.generated.ts +6 -0
  285. package/src/modules/user-management/command/revokePermissionFromRole.test.ts +52 -51
  286. package/src/modules/user-management/command/revokePermissionFromRole.ts +60 -57
  287. package/src/modules/user-management/command/revokeRoleFromUser.generated.ts +6 -0
  288. package/src/modules/user-management/command/revokeRoleFromUser.test.ts +53 -48
  289. package/src/modules/user-management/command/revokeRoleFromUser.ts +58 -57
  290. package/src/modules/user-management/docs/commands/CreatePermission.md +2 -2
  291. package/src/modules/user-management/docs/commands/CreateRole.md +1 -1
  292. package/src/modules/user-management/docs/models/AuditEvent.md +2 -0
  293. package/src/modules/user-management/docs/models/Permission.md +2 -0
  294. package/src/modules/user-management/docs/models/Role.md +2 -0
  295. package/src/modules/user-management/docs/models/RolePermission.md +2 -0
  296. package/src/modules/user-management/docs/models/User.md +2 -0
  297. package/src/modules/user-management/docs/models/UserRole.md +2 -0
  298. package/src/modules/user-management/generated/enums.ts +11 -11
  299. package/src/modules/user-management/generated/kysely-tailordb.ts +27 -56
  300. package/src/modules/user-management/index.ts +2 -2
  301. package/src/modules/user-management/lib/errors.generated.ts +67 -0
  302. package/src/modules/user-management/{permissions.ts → lib/permissions.generated.ts} +8 -7
  303. package/src/modules/user-management/module.ts +22 -22
  304. package/src/modules/user-management/tailor.config.ts +3 -3
  305. package/src/schemas.ts +2 -1
  306. package/skills/1-module-docs/references/structure.md +0 -22
  307. package/skills/2-module-feature-breakdown/references/commands.md +0 -48
  308. package/skills/2-module-feature-breakdown/references/structure.md +0 -22
  309. package/skills/3-module-doc-review/references/commands.md +0 -54
  310. package/skills/3-module-doc-review/references/models.md +0 -29
  311. package/skills/4-module-tdd-implementation/SKILL.md +0 -74
  312. package/skills/4-module-tdd-implementation/references/commands.md +0 -45
  313. package/skills/4-module-tdd-implementation/references/errors.md +0 -7
  314. package/skills/4-module-tdd-implementation/references/models.md +0 -30
  315. package/skills/4-module-tdd-implementation/references/structure.md +0 -22
  316. package/skills/4-module-tdd-implementation/references/testing.md +0 -37
  317. package/skills/5-module-implementation-review/references/commands.md +0 -45
  318. package/skills/5-module-implementation-review/references/errors.md +0 -7
  319. package/skills/5-module-implementation-review/references/exports.md +0 -8
  320. package/skills/5-module-implementation-review/references/models.md +0 -30
  321. package/src/modules/primitives/command/convertAmount.ts +0 -126
  322. package/src/modules/primitives/command/convertQuantity.ts +0 -73
  323. package/src/modules/primitives/lib/errors.ts +0 -138
  324. package/src/modules/user-management/lib/errors.ts +0 -81
  325. /package/skills/{app-compose-1-requirement-analysis → erp-kit-app-1-requirements}/references/structure.md +0 -0
  326. /package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/references/screen-detailview.md +0 -0
  327. /package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/references/screen-form.md +0 -0
  328. /package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/references/screen-listview.md +0 -0
  329. /package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/references/structure.md +0 -0
  330. /package/skills/{app-compose-3-doc-review → erp-kit-app-3-doc-review}/references/structure.md +0 -0
  331. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/component.md +0 -0
  332. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/screen-detailview.md +0 -0
  333. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/screen-form.md +0 -0
  334. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/screen-listview.md +0 -0
  335. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/structure.md +0 -0
  336. /package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/references/component.md +0 -0
  337. /package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/references/screen-detailview.md +0 -0
  338. /package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/references/screen-form.md +0 -0
  339. /package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/references/screen-listview.md +0 -0
  340. /package/skills/{app-compose-6-implementation-spec → erp-kit-app-6-impl-spec}/references/auth.md +0 -0
  341. /package/skills/{app-compose-6-implementation-spec → erp-kit-app-6-impl-spec}/references/structure.md +0 -0
  342. /package/skills/{2-module-feature-breakdown → erp-kit-module-4-tdd}/references/models.md +0 -0
@@ -1,8 +1,8 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { InsufficientPermissionError, type CommandContext } from "../../shared/internal";
2
+ import { type CommandContext } from "../../shared/internal";
3
3
  import { createMockDb } from "../../testing/index";
4
4
  import { DB } from "../generated/kysely-tailordb";
5
- import { RoleNotFoundError, UserNotActiveError, UserNotFoundError } from "../lib/errors";
5
+ import { RoleNotFoundError, UserNotActiveError, UserNotFoundError } from "../lib/errors.generated";
6
6
  import {
7
7
  activeUser,
8
8
  baseAuditEvent,
@@ -11,7 +11,7 @@ import {
11
11
  inactiveUser,
12
12
  pendingUser,
13
13
  } from "../testing/fixtures";
14
- import { assignRoleToUser } from "./assignRoleToUser";
14
+ import { run } from "./assignRoleToUser";
15
15
 
16
16
  describe("assignRoleToUser", () => {
17
17
  const ctx: CommandContext = {
@@ -23,68 +23,76 @@ describe("assignRoleToUser", () => {
23
23
  const { db, spies } = createMockDb<DB>();
24
24
  spies.select.mockReturnValue(undefined);
25
25
 
26
- await expect(
27
- assignRoleToUser(
28
- db,
29
- {
30
- userId: "nonexistent-user",
31
- roleId: baseRole.id,
32
- actorId: "actor-1",
33
- },
34
- ctx,
35
- ),
36
- ).rejects.toBeInstanceOf(UserNotFoundError);
26
+ const result = await run(
27
+ db,
28
+ {
29
+ userId: "nonexistent-user",
30
+ roleId: baseRole.id,
31
+ actorId: "actor-1",
32
+ },
33
+ ctx,
34
+ );
35
+ expect(result.ok).toBe(false);
36
+ if (!result.ok) {
37
+ expect(result.error).toBeInstanceOf(UserNotFoundError);
38
+ }
37
39
  });
38
40
 
39
41
  it("throws when role does not exist", async () => {
40
42
  const { db, spies } = createMockDb<DB>();
41
43
  spies.select.mockReturnValueOnce(activeUser).mockReturnValueOnce(undefined);
42
44
 
43
- await expect(
44
- assignRoleToUser(
45
- db,
46
- {
47
- userId: activeUser.id,
48
- roleId: "nonexistent-role",
49
- actorId: "actor-1",
50
- },
51
- ctx,
52
- ),
53
- ).rejects.toBeInstanceOf(RoleNotFoundError);
45
+ const result = await run(
46
+ db,
47
+ {
48
+ userId: activeUser.id,
49
+ roleId: "nonexistent-role",
50
+ actorId: "actor-1",
51
+ },
52
+ ctx,
53
+ );
54
+ expect(result.ok).toBe(false);
55
+ if (!result.ok) {
56
+ expect(result.error).toBeInstanceOf(RoleNotFoundError);
57
+ }
54
58
  });
55
59
 
56
60
  it("throws when user is PENDING", async () => {
57
61
  const { db, spies } = createMockDb<DB>();
58
62
  spies.select.mockReturnValueOnce(pendingUser).mockReturnValueOnce(baseRole);
59
63
 
60
- await expect(
61
- assignRoleToUser(
62
- db,
63
- {
64
- userId: pendingUser.id,
65
- roleId: baseRole.id,
66
- actorId: "actor-1",
67
- },
68
- ctx,
69
- ),
70
- ).rejects.toBeInstanceOf(UserNotActiveError);
64
+ const result = await run(
65
+ db,
66
+ {
67
+ userId: pendingUser.id,
68
+ roleId: baseRole.id,
69
+ actorId: "actor-1",
70
+ },
71
+ ctx,
72
+ );
73
+ expect(result.ok).toBe(false);
74
+ if (!result.ok) {
75
+ expect(result.error).toBeInstanceOf(UserNotActiveError);
76
+ }
71
77
  });
72
78
 
73
79
  it("throws when user is INACTIVE", async () => {
74
80
  const { db, spies } = createMockDb<DB>();
75
81
  spies.select.mockReturnValueOnce(inactiveUser).mockReturnValueOnce(baseRole);
76
82
 
77
- await expect(
78
- assignRoleToUser(
79
- db,
80
- {
81
- userId: inactiveUser.id,
82
- roleId: baseRole.id,
83
- actorId: "actor-1",
84
- },
85
- ctx,
86
- ),
87
- ).rejects.toBeInstanceOf(UserNotActiveError);
83
+ const result = await run(
84
+ db,
85
+ {
86
+ userId: inactiveUser.id,
87
+ roleId: baseRole.id,
88
+ actorId: "actor-1",
89
+ },
90
+ ctx,
91
+ );
92
+ expect(result.ok).toBe(false);
93
+ if (!result.ok) {
94
+ expect(result.error).toBeInstanceOf(UserNotActiveError);
95
+ }
88
96
  });
89
97
 
90
98
  it("returns success when assignment already exists (idempotent)", async () => {
@@ -97,7 +105,7 @@ describe("assignRoleToUser", () => {
97
105
  .mockReturnValueOnce([{ key: "orders:read" }]); // Permission keys from recompute
98
106
  spies.update.mockReturnValueOnce(updatedUser);
99
107
 
100
- const result = await assignRoleToUser(
108
+ const result = await run(
101
109
  db,
102
110
  {
103
111
  userId: activeUser.id,
@@ -107,8 +115,11 @@ describe("assignRoleToUser", () => {
107
115
  ctx,
108
116
  );
109
117
 
110
- expect(result.userRole).toEqual(baseUserRole);
111
- expect(result.user.permissions).toEqual(["orders:read"]);
118
+ expect(result.ok).toBe(true);
119
+ if (result.ok) {
120
+ expect(result.value.userRole).toEqual(baseUserRole);
121
+ expect(result.value.user.permissions).toEqual(["orders:read"]);
122
+ }
112
123
  expect(spies.insert).not.toHaveBeenCalled();
113
124
  });
114
125
 
@@ -135,7 +146,7 @@ describe("assignRoleToUser", () => {
135
146
  spies.insert.mockReturnValueOnce(newUserRole).mockReturnValueOnce(createdAuditEvent);
136
147
  spies.update.mockReturnValueOnce(updatedUser);
137
148
 
138
- const result = await assignRoleToUser(
149
+ const result = await run(
139
150
  db,
140
151
  {
141
152
  userId: activeUser.id,
@@ -145,18 +156,14 @@ describe("assignRoleToUser", () => {
145
156
  ctx,
146
157
  );
147
158
 
148
- expect(result.userRole.userId).toBe(activeUser.id);
149
- expect(result.userRole.roleId).toBe(baseRole.id);
150
- expect(result.auditEvent?.eventType).toBe("ROLE_ASSIGNED");
151
- expect(result.user.permissions).toEqual(["orders:read"]);
159
+ expect(result.ok).toBe(true);
160
+ if (result.ok) {
161
+ expect(result.value.userRole.userId).toBe(activeUser.id);
162
+ expect(result.value.userRole.roleId).toBe(baseRole.id);
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
164
+ expect((result.value as any).auditEvent?.eventType).toBe("ROLE_ASSIGNED");
165
+ expect(result.value.user.permissions).toEqual(["orders:read"]);
166
+ }
152
167
  expect(spies.insert).toHaveBeenCalled();
153
168
  });
154
-
155
- it("throws when permission is missing", async () => {
156
- const { db } = createMockDb<DB>();
157
- const denied: CommandContext = { actorId: "test-actor", permissions: [] };
158
- await expect(
159
- assignRoleToUser(db, { userId: "user-1", roleId: "role-1", actorId: "actor-1" }, denied),
160
- ).rejects.toBeInstanceOf(InsufficientPermissionError);
161
- });
162
169
  });
@@ -1,8 +1,7 @@
1
- import { defineCommand } from "../../shared/internal";
1
+ import { ok, err, type CommandContext } from "../../shared/internal";
2
2
  import { DB } from "../generated/kysely-tailordb";
3
- import { RoleNotFoundError, UserNotActiveError, UserNotFoundError } from "../lib/errors";
3
+ import { RoleNotFoundError, UserNotActiveError, UserNotFoundError } from "../lib/errors.generated";
4
4
  import { recomputeUserPermissions } from "../lib/recomputeUserPermissions";
5
- import { permissions } from "../permissions";
6
5
 
7
6
  export interface AssignRoleToUserInput {
8
7
  userId: string;
@@ -17,77 +16,75 @@ export interface AssignRoleToUserInput {
17
16
  * Operation is idempotent - assigning the same role twice does not create
18
17
  * duplicate records or error.
19
18
  */
20
- export const assignRoleToUser = defineCommand(
21
- permissions.assignRoleToUser,
22
- async (db: DB, input: AssignRoleToUserInput) => {
23
- const user = await db
24
- .selectFrom("User")
25
- .selectAll()
26
- .where("id", "=", input.userId)
27
- .executeTakeFirst();
19
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
20
+ export async function run(db: DB, input: AssignRoleToUserInput, _ctx: CommandContext) {
21
+ const user = await db
22
+ .selectFrom("User")
23
+ .selectAll()
24
+ .where("id", "=", input.userId)
25
+ .executeTakeFirst();
28
26
 
29
- if (!user) {
30
- throw new UserNotFoundError(input.userId);
31
- }
27
+ if (!user) {
28
+ return err(new UserNotFoundError(input.userId));
29
+ }
32
30
 
33
- const role = await db
34
- .selectFrom("Role")
35
- .selectAll()
36
- .where("id", "=", input.roleId)
37
- .executeTakeFirst();
31
+ const role = await db
32
+ .selectFrom("Role")
33
+ .selectAll()
34
+ .where("id", "=", input.roleId)
35
+ .executeTakeFirst();
38
36
 
39
- if (!role) {
40
- throw new RoleNotFoundError(input.roleId);
41
- }
37
+ if (!role) {
38
+ return err(new RoleNotFoundError(input.roleId));
39
+ }
42
40
 
43
- if (user.status !== "ACTIVE") {
44
- throw new UserNotActiveError(input.userId, user.status);
45
- }
41
+ if (user.status !== "ACTIVE") {
42
+ return err(new UserNotActiveError(`${input.userId} (status: ${user.status})`));
43
+ }
46
44
 
47
- // Idempotent: return existing assignment, recompute permissions for consistency
48
- const existingAssignment = await db
49
- .selectFrom("UserRole")
50
- .selectAll()
51
- .where("userId", "=", input.userId)
52
- .where("roleId", "=", input.roleId)
53
- .executeTakeFirst();
45
+ // Idempotent: return existing assignment, recompute permissions for consistency
46
+ const existingAssignment = await db
47
+ .selectFrom("UserRole")
48
+ .selectAll()
49
+ .where("userId", "=", input.userId)
50
+ .where("roleId", "=", input.roleId)
51
+ .executeTakeFirst();
54
52
 
55
- if (existingAssignment) {
56
- const updatedUser = await recomputeUserPermissions(db, input.userId);
57
- return { userRole: existingAssignment, user: updatedUser };
58
- }
53
+ if (existingAssignment) {
54
+ const updatedUser = await recomputeUserPermissions(db, input.userId);
55
+ return ok({ userRole: existingAssignment, user: updatedUser });
56
+ }
57
+
58
+ const userRole = await db
59
+ .insertInto("UserRole")
60
+ .values({
61
+ userId: input.userId,
62
+ roleId: input.roleId,
63
+ createdAt: new Date(),
64
+ updatedAt: null,
65
+ })
66
+ .returningAll()
67
+ .executeTakeFirst();
59
68
 
60
- const userRole = await db
61
- .insertInto("UserRole")
62
- .values({
69
+ const auditEvent = await db
70
+ .insertInto("AuditEvent")
71
+ .values({
72
+ eventType: "ROLE_ASSIGNED",
73
+ actorId: input.actorId,
74
+ targetId: input.userId,
75
+ targetType: "User",
76
+ payload: JSON.stringify({
63
77
  userId: input.userId,
64
78
  roleId: input.roleId,
65
- createdAt: new Date(),
66
- updatedAt: null,
67
- })
68
- .returningAll()
69
- .executeTakeFirst();
79
+ roleName: role.name,
80
+ }),
81
+ createdAt: new Date(),
82
+ updatedAt: null,
83
+ })
84
+ .returningAll()
85
+ .executeTakeFirst();
70
86
 
71
- const auditEvent = await db
72
- .insertInto("AuditEvent")
73
- .values({
74
- eventType: "ROLE_ASSIGNED",
75
- actorId: input.actorId,
76
- targetId: input.userId,
77
- targetType: "User",
78
- payload: JSON.stringify({
79
- userId: input.userId,
80
- roleId: input.roleId,
81
- roleName: role.name,
82
- }),
83
- createdAt: new Date(),
84
- updatedAt: null,
85
- })
86
- .returningAll()
87
- .executeTakeFirst();
87
+ const updatedUser = await recomputeUserPermissions(db, input.userId);
88
88
 
89
- const updatedUser = await recomputeUserPermissions(db, input.userId);
90
-
91
- return { userRole: userRole!, user: updatedUser, auditEvent: auditEvent! };
92
- },
93
- );
89
+ return ok({ userRole: userRole!, user: updatedUser, auditEvent: auditEvent! });
90
+ }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { defineCommand } from "../../shared/internal";
3
+ import { permissions } from "../lib/permissions.generated";
4
+ import { run } from "./createPermission";
5
+
6
+ export const createPermission = defineCommand(permissions.createPermission, run);
@@ -1,16 +1,14 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { InsufficientPermissionError, type CommandContext } from "../../shared/internal";
2
+ import { type CommandContext } from "../../shared/internal";
3
3
  import { createMockDb } from "../../testing/index";
4
4
  import { DB } from "../generated/kysely-tailordb";
5
5
  import {
6
6
  DuplicatePermissionKeyError,
7
7
  InvalidPermissionKeyFormatError,
8
8
  MissingRequiredFieldError,
9
- } from "../lib/errors";
9
+ } from "../lib/errors.generated";
10
10
  import { basePermission } from "../testing/fixtures";
11
- import { makeCreatePermission } from "./createPermission";
12
-
13
- const createPermission = makeCreatePermission();
11
+ import { run } from "./createPermission";
14
12
 
15
13
  describe("createPermission", () => {
16
14
  const ctx: CommandContext = {
@@ -22,50 +20,62 @@ describe("createPermission", () => {
22
20
  it("throws when key is empty", async () => {
23
21
  const { db } = createMockDb<DB>();
24
22
 
25
- await expect(createPermission(db, { key: "" }, ctx)).rejects.toBeInstanceOf(
26
- MissingRequiredFieldError,
27
- );
23
+ const result = await run(db, { key: "" }, ctx);
24
+ expect(result.ok).toBe(false);
25
+ if (!result.ok) {
26
+ expect(result.error).toBeInstanceOf(MissingRequiredFieldError);
27
+ }
28
28
  });
29
29
 
30
30
  it("throws when key format is invalid (no colon)", async () => {
31
31
  const { db } = createMockDb<DB>();
32
32
 
33
- await expect(createPermission(db, { key: "invalidkey" }, ctx)).rejects.toBeInstanceOf(
34
- InvalidPermissionKeyFormatError,
35
- );
33
+ const result = await run(db, { key: "invalidkey" }, ctx);
34
+ expect(result.ok).toBe(false);
35
+ if (!result.ok) {
36
+ expect(result.error).toBeInstanceOf(InvalidPermissionKeyFormatError);
37
+ }
36
38
  });
37
39
 
38
40
  it("throws when key format is invalid (multiple colons)", async () => {
39
41
  const { db } = createMockDb<DB>();
40
42
 
41
- await expect(
42
- createPermission(db, { key: "resource:action:extra" }, ctx),
43
- ).rejects.toBeInstanceOf(InvalidPermissionKeyFormatError);
43
+ const result = await run(db, { key: "resource:action:extra" }, ctx);
44
+ expect(result.ok).toBe(false);
45
+ if (!result.ok) {
46
+ expect(result.error).toBeInstanceOf(InvalidPermissionKeyFormatError);
47
+ }
44
48
  });
45
49
 
46
50
  it("throws when key format is invalid (empty resource)", async () => {
47
51
  const { db } = createMockDb<DB>();
48
52
 
49
- await expect(createPermission(db, { key: ":action" }, ctx)).rejects.toBeInstanceOf(
50
- InvalidPermissionKeyFormatError,
51
- );
53
+ const result = await run(db, { key: ":action" }, ctx);
54
+ expect(result.ok).toBe(false);
55
+ if (!result.ok) {
56
+ expect(result.error).toBeInstanceOf(InvalidPermissionKeyFormatError);
57
+ }
52
58
  });
53
59
 
54
60
  it("throws when key format is invalid (empty action)", async () => {
55
61
  const { db } = createMockDb<DB>();
56
62
 
57
- await expect(createPermission(db, { key: "resource:" }, ctx)).rejects.toBeInstanceOf(
58
- InvalidPermissionKeyFormatError,
59
- );
63
+ const result = await run(db, { key: "resource:" }, ctx);
64
+ expect(result.ok).toBe(false);
65
+ if (!result.ok) {
66
+ expect(result.error).toBeInstanceOf(InvalidPermissionKeyFormatError);
67
+ }
60
68
  });
61
69
 
62
70
  it("throws when permission key already exists", async () => {
63
71
  const { db, spies } = createMockDb<DB>();
64
72
  spies.select.mockReturnValue(basePermission);
65
73
 
66
- await expect(createPermission(db, { key: basePermission.key }, ctx)).rejects.toBeInstanceOf(
67
- DuplicatePermissionKeyError,
68
- );
74
+ const result = await run(db, { key: basePermission.key }, ctx);
75
+ expect(result.ok).toBe(false);
76
+ if (!result.ok) {
77
+ expect(result.error).toBeInstanceOf(DuplicatePermissionKeyError);
78
+ }
69
79
  });
70
80
 
71
81
  // Success cases
@@ -81,9 +91,12 @@ describe("createPermission", () => {
81
91
  spies.select.mockReturnValue(undefined); // No existing permission
82
92
  spies.insert.mockReturnValue(createdPermission);
83
93
 
84
- const result = await createPermission(db, { key: "users:read" }, ctx);
94
+ const result = await run(db, { key: "users:read" }, ctx);
85
95
 
86
- expect(result.permission.key).toBe("users:read");
96
+ expect(result.ok).toBe(true);
97
+ if (result.ok) {
98
+ expect(result.value.permission.key).toBe("users:read");
99
+ }
87
100
  expect(spies.insert).toHaveBeenCalled();
88
101
  });
89
102
 
@@ -99,7 +112,7 @@ describe("createPermission", () => {
99
112
  spies.select.mockReturnValue(undefined);
100
113
  spies.insert.mockReturnValue(createdPermission);
101
114
 
102
- const result = await createPermission(
115
+ const result = await run(
103
116
  db,
104
117
  {
105
118
  key: "users:write",
@@ -108,20 +121,14 @@ describe("createPermission", () => {
108
121
  ctx,
109
122
  );
110
123
 
111
- expect(result.permission.key).toBe("users:write");
112
- expect(result.permission.description).toBe("Permission to write users");
113
- });
114
-
115
- it("throws when permission is missing", async () => {
116
- const { db } = createMockDb<DB>();
117
- const denied: CommandContext = { actorId: "test-actor", permissions: [] };
118
- await expect(createPermission(db, { key: "users:read" }, denied)).rejects.toBeInstanceOf(
119
- InsufficientPermissionError,
120
- );
124
+ expect(result.ok).toBe(true);
125
+ if (result.ok) {
126
+ expect(result.value.permission.key).toBe("users:write");
127
+ expect(result.value.permission.description).toBe("Permission to write users");
128
+ }
121
129
  });
122
130
 
123
131
  it("passes custom fields through to insert", async () => {
124
- const createPermissionWithFields = makeCreatePermission<{ module: string }>();
125
132
  const { db, spies } = createMockDb<DB>();
126
133
  const createdPermission = {
127
134
  ...basePermission,
@@ -133,7 +140,7 @@ describe("createPermission", () => {
133
140
  spies.select.mockReturnValue(undefined);
134
141
  spies.insert.mockReturnValue(createdPermission);
135
142
 
136
- await createPermissionWithFields(db, { key: "users:read", module: "user-management" }, ctx);
143
+ await run(db, { key: "users:read", module: "user-management" }, ctx);
137
144
 
138
145
  expect(spies.values).toHaveBeenNthCalledWith(
139
146
  1,
@@ -1,11 +1,10 @@
1
- import { defineCommand } from "../../shared/internal";
1
+ import { ok, err, type CommandContext } from "../../shared/internal";
2
2
  import { DB } from "../generated/kysely-tailordb";
3
3
  import {
4
4
  DuplicatePermissionKeyError,
5
5
  InvalidPermissionKeyFormatError,
6
6
  MissingRequiredFieldError,
7
- } from "../lib/errors";
8
- import { permissions } from "../permissions";
7
+ } from "../lib/errors.generated";
9
8
 
10
9
  interface CreatePermissionInput {
11
10
  key: string;
@@ -20,47 +19,44 @@ const PERMISSION_KEY_PATTERN = /^[a-zA-Z0-9_-]+:[a-zA-Z0-9_-]+$/;
20
19
  * Creates a new permission with the specified key in resource:action format.
21
20
  * Validates that the key follows the correct format and is unique.
22
21
  */
23
- export function makeCreatePermission<CF extends Record<string, unknown>>() {
24
- return defineCommand(
25
- permissions.createPermission,
26
- async (db: DB, input: CreatePermissionInput & CF) => {
27
- const { key, description, ...customFields } = input;
28
-
29
- // 1. Validate key is provided
30
- if (!key || key.trim() === "") {
31
- throw new MissingRequiredFieldError("key");
32
- }
33
-
34
- // 2. Validate key format (resource:action)
35
- if (!PERMISSION_KEY_PATTERN.test(key)) {
36
- throw new InvalidPermissionKeyFormatError(key);
37
- }
38
-
39
- // 3. Check if permission key already exists
40
- const existingPermission = await db
41
- .selectFrom("Permission")
42
- .selectAll()
43
- .where("key", "=", key)
44
- .executeTakeFirst();
45
-
46
- if (existingPermission) {
47
- throw new DuplicatePermissionKeyError(key);
48
- }
49
-
50
- // 4. Create permission
51
- const permission = await db
52
- .insertInto("Permission")
53
- .values({
54
- ...(customFields as Record<string, unknown>),
55
- key,
56
- description: description ?? null,
57
- createdAt: new Date(),
58
- updatedAt: null,
59
- })
60
- .returningAll()
61
- .executeTakeFirst();
62
-
63
- return { permission: permission! };
64
- },
65
- );
22
+ export async function run<CF extends Record<string, unknown>>(
23
+ db: DB,
24
+ input: CreatePermissionInput & CF,
25
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
26
+ _ctx: CommandContext,
27
+ ) {
28
+ const { key, description, ...customFields } = input;
29
+
30
+ if (!key || key.trim() === "") {
31
+ return err(new MissingRequiredFieldError("key"));
32
+ }
33
+
34
+ if (!PERMISSION_KEY_PATTERN.test(key)) {
35
+ return err(new InvalidPermissionKeyFormatError(key));
36
+ }
37
+
38
+ const existingPermission = await db
39
+ .selectFrom("Permission")
40
+ .selectAll()
41
+ .where("key", "=", key)
42
+ .executeTakeFirst();
43
+
44
+ if (existingPermission) {
45
+ return err(new DuplicatePermissionKeyError(key));
46
+ }
47
+
48
+ // 4. Create permission
49
+ const permission = await db
50
+ .insertInto("Permission")
51
+ .values({
52
+ ...(customFields as Record<string, unknown>),
53
+ key,
54
+ description: description ?? null,
55
+ createdAt: new Date(),
56
+ updatedAt: null,
57
+ })
58
+ .returningAll()
59
+ .executeTakeFirst();
60
+
61
+ return ok({ permission: permission! });
66
62
  }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { defineCommand } from "../../shared/internal";
3
+ import { permissions } from "../lib/permissions.generated";
4
+ import { run } from "./createRole";
5
+
6
+ export const createRole = defineCommand(permissions.createRole, run);