@powerhousedao/codegen 6.0.0-dev.13 → 6.0.0-dev.131

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 (656) hide show
  1. package/{dist/src/templates/boilerplate/LICENSE.js → LICENSE} +1 -4
  2. package/dist/file-builders-DTtl0nnu.mjs +1661 -0
  3. package/dist/file-builders-DTtl0nnu.mjs.map +1 -0
  4. package/dist/index-CJZGVSYg.d.mts +65 -0
  5. package/dist/index-CJZGVSYg.d.mts.map +1 -0
  6. package/dist/index-bxxFsCxV.d.mts +202 -0
  7. package/dist/index-bxxFsCxV.d.mts.map +1 -0
  8. package/dist/index.d.mts +301 -0
  9. package/dist/index.d.mts.map +1 -0
  10. package/dist/index.mjs +809 -0
  11. package/dist/index.mjs.map +1 -0
  12. package/dist/src/file-builders/index.d.mts +3 -0
  13. package/dist/src/file-builders/index.mjs +3 -0
  14. package/dist/src/name-builders/index.d.mts +2 -0
  15. package/dist/src/name-builders/index.mjs +146 -0
  16. package/dist/src/name-builders/index.mjs.map +1 -0
  17. package/dist/src/templates/index.d.mts +416 -0
  18. package/dist/src/templates/index.d.mts.map +1 -0
  19. package/dist/src/templates/index.mjs +2 -0
  20. package/dist/src/utils/index.d.mts +127 -0
  21. package/dist/src/utils/index.d.mts.map +1 -0
  22. package/dist/src/utils/index.mjs +380 -0
  23. package/dist/src/utils/index.mjs.map +1 -0
  24. package/dist/templates-CKdxigVj.mjs +4611 -0
  25. package/dist/templates-CKdxigVj.mjs.map +1 -0
  26. package/dist/types-BcTGclWR.d.mts +89 -0
  27. package/dist/types-BcTGclWR.d.mts.map +1 -0
  28. package/dist/validation-Bpg_44mW.d.mts +43 -0
  29. package/dist/validation-Bpg_44mW.d.mts.map +1 -0
  30. package/package.json +30 -59
  31. package/dist/index.d.ts +0 -8
  32. package/dist/index.d.ts.map +0 -1
  33. package/dist/index.js +0 -7
  34. package/dist/index.js.map +0 -1
  35. package/dist/src/codegen/.hygen/package.json +0 -6
  36. package/dist/src/codegen/.hygen/templates/powerhouse/generate-custom-subgraph/index.js +0 -10
  37. package/dist/src/codegen/.hygen/templates/powerhouse/generate-custom-subgraph/resolvers.esm.t +0 -17
  38. package/dist/src/codegen/.hygen/templates/powerhouse/generate-custom-subgraph/schema.esm.t +0 -16
  39. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/actions.esm.t +0 -16
  40. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/creators.esm.t +0 -9
  41. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/customUtils.esm.t +0 -5
  42. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/document-schema.esm.t +0 -56
  43. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/document-type.esm.t +0 -6
  44. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/documentModel.esm.t +0 -7
  45. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/documentModelTest.esm.t +0 -121
  46. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/hooks.esm.t +0 -49
  47. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/index.esm.t +0 -23
  48. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/index.js +0 -127
  49. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/module.esm.t +0 -22
  50. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/ph-factories.esm.t +0 -93
  51. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/reducer.esm.t +0 -46
  52. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/root-utils.esm.t +0 -11
  53. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/rootActions.esm.t +0 -13
  54. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/rootIndex.esm.t +0 -14
  55. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/schema.esm.t +0 -6
  56. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/src-index.esm.t +0 -5
  57. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/types.esm.t +0 -31
  58. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model/utils.esm.t +0 -77
  59. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-module/actions.esm.t +0 -22
  60. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-module/creators.esm.t +0 -37
  61. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-module/customTest.esm.t +0 -44
  62. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-module/error.esm.t +0 -36
  63. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-module/index.js +0 -71
  64. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-module/operations.esm.t +0 -17
  65. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-subgraph/index.js +0 -118
  66. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-subgraph/resolvers.esm.t +0 -130
  67. package/dist/src/codegen/.hygen/templates/powerhouse/generate-document-model-subgraph/schema.esm.t +0 -44
  68. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/CreateDocument.esm.t +0 -58
  69. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/DriveContents.esm.t +0 -23
  70. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/DriveExplorer.esm.t +0 -32
  71. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/EmptyState.esm.t +0 -19
  72. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/Files.esm.t +0 -29
  73. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/FolderTree.esm.t +0 -108
  74. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/Folders.esm.t +0 -28
  75. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/components/NavigationBreadcrumbs.esm.t +0 -14
  76. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/config.esm.t +0 -11
  77. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/editor.esm.t +0 -18
  78. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/index.js +0 -25
  79. package/dist/src/codegen/.hygen/templates/powerhouse/generate-drive-editor/module.esm.t +0 -15
  80. package/dist/src/codegen/.hygen/templates/powerhouse/generate-editor/editor.esm.t +0 -80
  81. package/dist/src/codegen/.hygen/templates/powerhouse/generate-editor/index.js +0 -90
  82. package/dist/src/codegen/.hygen/templates/powerhouse/generate-editor/module.esm.t +0 -16
  83. package/dist/src/codegen/.hygen/templates/powerhouse/generate-import-script/index.esm.t +0 -59
  84. package/dist/src/codegen/.hygen/templates/powerhouse/generate-import-script/index.js +0 -9
  85. package/dist/src/codegen/.hygen/templates/powerhouse/generate-import-script/utils.esm.t +0 -100
  86. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/factory.esm.t +0 -22
  87. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/index.esm.t +0 -62
  88. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/index.js +0 -12
  89. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/index.root.esm.t +0 -10
  90. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/index.root.inject.esm.t +0 -12
  91. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/lib.esm.t +0 -34
  92. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/lib.inject_call.esm.t +0 -7
  93. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/lib.inject_export.esm.t +0 -7
  94. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-analytics/lib.inject_import.esm.t +0 -7
  95. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/factory.esm.t +0 -40
  96. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/index.esm.t +0 -47
  97. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/index.js +0 -12
  98. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/index.root.esm.t +0 -10
  99. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/index.root.inject.esm.t +0 -12
  100. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/lib.esm.t +0 -34
  101. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/lib.inject_call.esm.t +0 -7
  102. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/lib.inject_export.esm.t +0 -9
  103. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/lib.inject_import.esm.t +0 -7
  104. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/migrations.esm.t +0 -23
  105. package/dist/src/codegen/.hygen/templates/powerhouse/generate-processor-relationalDb/schema.esm.t +0 -13
  106. package/dist/src/codegen/.hygen/templates/powerhouse/generate-subgraph/index.esm.t +0 -17
  107. package/dist/src/codegen/.hygen/templates/powerhouse/generate-subgraph/index.js +0 -10
  108. package/dist/src/codegen/.hygen/templates/powerhouse/generate-subgraph/lib.esm.t +0 -9
  109. package/dist/src/codegen/__tests__/config.d.ts +0 -3
  110. package/dist/src/codegen/__tests__/config.d.ts.map +0 -1
  111. package/dist/src/codegen/__tests__/config.js +0 -3
  112. package/dist/src/codegen/__tests__/config.js.map +0 -1
  113. package/dist/src/codegen/__tests__/constants.d.ts +0 -16
  114. package/dist/src/codegen/__tests__/constants.d.ts.map +0 -1
  115. package/dist/src/codegen/__tests__/constants.js +0 -16
  116. package/dist/src/codegen/__tests__/constants.js.map +0 -1
  117. package/dist/src/codegen/__tests__/fixtures/expected-reducer-content-v3.d.ts +0 -2
  118. package/dist/src/codegen/__tests__/fixtures/expected-reducer-content-v3.d.ts.map +0 -1
  119. package/dist/src/codegen/__tests__/fixtures/expected-reducer-content-v3.js +0 -9
  120. package/dist/src/codegen/__tests__/fixtures/expected-reducer-content-v3.js.map +0 -1
  121. package/dist/src/codegen/__tests__/fixtures/expected-reducer-content.d.ts +0 -3
  122. package/dist/src/codegen/__tests__/fixtures/expected-reducer-content.d.ts.map +0 -1
  123. package/dist/src/codegen/__tests__/fixtures/expected-reducer-content.js +0 -33
  124. package/dist/src/codegen/__tests__/fixtures/expected-reducer-content.js.map +0 -1
  125. package/dist/src/codegen/__tests__/fixtures/run-generated-tests.d.ts +0 -2
  126. package/dist/src/codegen/__tests__/fixtures/run-generated-tests.d.ts.map +0 -1
  127. package/dist/src/codegen/__tests__/fixtures/run-generated-tests.js +0 -23
  128. package/dist/src/codegen/__tests__/fixtures/run-generated-tests.js.map +0 -1
  129. package/dist/src/codegen/__tests__/fixtures/typecheck.d.ts +0 -2
  130. package/dist/src/codegen/__tests__/fixtures/typecheck.d.ts.map +0 -1
  131. package/dist/src/codegen/__tests__/fixtures/typecheck.js +0 -23
  132. package/dist/src/codegen/__tests__/fixtures/typecheck.js.map +0 -1
  133. package/dist/src/codegen/__tests__/generate-doc-model.test.d.ts +0 -2
  134. package/dist/src/codegen/__tests__/generate-doc-model.test.d.ts.map +0 -1
  135. package/dist/src/codegen/__tests__/generate-doc-model.test.js +0 -233
  136. package/dist/src/codegen/__tests__/generate-doc-model.test.js.map +0 -1
  137. package/dist/src/codegen/__tests__/generate-drive-editor.test.d.ts +0 -2
  138. package/dist/src/codegen/__tests__/generate-drive-editor.test.d.ts.map +0 -1
  139. package/dist/src/codegen/__tests__/generate-drive-editor.test.js +0 -156
  140. package/dist/src/codegen/__tests__/generate-drive-editor.test.js.map +0 -1
  141. package/dist/src/codegen/__tests__/generate-editor.test.d.ts +0 -2
  142. package/dist/src/codegen/__tests__/generate-editor.test.d.ts.map +0 -1
  143. package/dist/src/codegen/__tests__/generate-editor.test.js +0 -115
  144. package/dist/src/codegen/__tests__/generate-editor.test.js.map +0 -1
  145. package/dist/src/codegen/__tests__/generate-manifest.test.d.ts +0 -2
  146. package/dist/src/codegen/__tests__/generate-manifest.test.d.ts.map +0 -1
  147. package/dist/src/codegen/__tests__/generate-manifest.test.js +0 -192
  148. package/dist/src/codegen/__tests__/generate-manifest.test.js.map +0 -1
  149. package/dist/src/codegen/__tests__/generate-versioned-document-model.test.d.ts +0 -2
  150. package/dist/src/codegen/__tests__/generate-versioned-document-model.test.d.ts.map +0 -1
  151. package/dist/src/codegen/__tests__/generate-versioned-document-model.test.js +0 -159
  152. package/dist/src/codegen/__tests__/generate-versioned-document-model.test.js.map +0 -1
  153. package/dist/src/codegen/__tests__/global-setup.d.ts +0 -2
  154. package/dist/src/codegen/__tests__/global-setup.d.ts.map +0 -1
  155. package/dist/src/codegen/__tests__/global-setup.js +0 -21
  156. package/dist/src/codegen/__tests__/global-setup.js.map +0 -1
  157. package/dist/src/codegen/__tests__/ts-morph-generator.test.d.ts +0 -2
  158. package/dist/src/codegen/__tests__/ts-morph-generator.test.d.ts.map +0 -1
  159. package/dist/src/codegen/__tests__/ts-morph-generator.test.js +0 -73
  160. package/dist/src/codegen/__tests__/ts-morph-generator.test.js.map +0 -1
  161. package/dist/src/codegen/__tests__/utils.d.ts +0 -7
  162. package/dist/src/codegen/__tests__/utils.d.ts.map +0 -1
  163. package/dist/src/codegen/__tests__/utils.js +0 -52
  164. package/dist/src/codegen/__tests__/utils.js.map +0 -1
  165. package/dist/src/codegen/generate.d.ts +0 -79
  166. package/dist/src/codegen/generate.d.ts.map +0 -1
  167. package/dist/src/codegen/generate.js +0 -334
  168. package/dist/src/codegen/generate.js.map +0 -1
  169. package/dist/src/codegen/graphql.d.ts +0 -36
  170. package/dist/src/codegen/graphql.d.ts.map +0 -1
  171. package/dist/src/codegen/graphql.js +0 -146
  172. package/dist/src/codegen/graphql.js.map +0 -1
  173. package/dist/src/codegen/hygen.d.ts +0 -47
  174. package/dist/src/codegen/hygen.d.ts.map +0 -1
  175. package/dist/src/codegen/hygen.js +0 -230
  176. package/dist/src/codegen/hygen.js.map +0 -1
  177. package/dist/src/codegen/index.d.ts +0 -7
  178. package/dist/src/codegen/index.d.ts.map +0 -1
  179. package/dist/src/codegen/index.js +0 -7
  180. package/dist/src/codegen/index.js.map +0 -1
  181. package/dist/src/codegen/kysely.d.ts +0 -6
  182. package/dist/src/codegen/kysely.d.ts.map +0 -1
  183. package/dist/src/codegen/kysely.js +0 -51
  184. package/dist/src/codegen/kysely.js.map +0 -1
  185. package/dist/src/codegen/types.d.ts +0 -9
  186. package/dist/src/codegen/types.d.ts.map +0 -1
  187. package/dist/src/codegen/types.js +0 -2
  188. package/dist/src/codegen/types.js.map +0 -1
  189. package/dist/src/codegen/utils.d.ts +0 -7
  190. package/dist/src/codegen/utils.d.ts.map +0 -1
  191. package/dist/src/codegen/utils.js +0 -79
  192. package/dist/src/codegen/utils.js.map +0 -1
  193. package/dist/src/create-lib/checkout-project.d.ts +0 -13
  194. package/dist/src/create-lib/checkout-project.d.ts.map +0 -1
  195. package/dist/src/create-lib/checkout-project.js +0 -47
  196. package/dist/src/create-lib/checkout-project.js.map +0 -1
  197. package/dist/src/create-lib/create-project.d.ts +0 -10
  198. package/dist/src/create-lib/create-project.d.ts.map +0 -1
  199. package/dist/src/create-lib/create-project.js +0 -98
  200. package/dist/src/create-lib/create-project.js.map +0 -1
  201. package/dist/src/create-lib/feature-flags.d.ts +0 -4
  202. package/dist/src/create-lib/feature-flags.d.ts.map +0 -1
  203. package/dist/src/create-lib/feature-flags.js +0 -4
  204. package/dist/src/create-lib/feature-flags.js.map +0 -1
  205. package/dist/src/create-lib/index.d.ts +0 -3
  206. package/dist/src/create-lib/index.d.ts.map +0 -1
  207. package/dist/src/create-lib/index.js +0 -3
  208. package/dist/src/create-lib/index.js.map +0 -1
  209. package/dist/src/create-lib/utils.d.ts +0 -8
  210. package/dist/src/create-lib/utils.d.ts.map +0 -1
  211. package/dist/src/create-lib/utils.js +0 -34
  212. package/dist/src/create-lib/utils.js.map +0 -1
  213. package/dist/src/file-builders/boilerplate/build-package-json.test.d.ts +0 -2
  214. package/dist/src/file-builders/boilerplate/build-package-json.test.d.ts.map +0 -1
  215. package/dist/src/file-builders/boilerplate/build-package-json.test.js +0 -28
  216. package/dist/src/file-builders/boilerplate/build-package-json.test.js.map +0 -1
  217. package/dist/src/file-builders/boilerplate/package-json-versions.test.d.ts +0 -2
  218. package/dist/src/file-builders/boilerplate/package-json-versions.test.d.ts.map +0 -1
  219. package/dist/src/file-builders/boilerplate/package-json-versions.test.js +0 -34
  220. package/dist/src/file-builders/boilerplate/package-json-versions.test.js.map +0 -1
  221. package/dist/src/file-builders/boilerplate/package.json.d.ts +0 -6
  222. package/dist/src/file-builders/boilerplate/package.json.d.ts.map +0 -1
  223. package/dist/src/file-builders/boilerplate/package.json.js +0 -18
  224. package/dist/src/file-builders/boilerplate/package.json.js.map +0 -1
  225. package/dist/src/file-builders/document-editor.d.ts +0 -8
  226. package/dist/src/file-builders/document-editor.d.ts.map +0 -1
  227. package/dist/src/file-builders/document-editor.js +0 -57
  228. package/dist/src/file-builders/document-editor.js.map +0 -1
  229. package/dist/src/file-builders/document-model/document-model.d.ts +0 -8
  230. package/dist/src/file-builders/document-model/document-model.d.ts.map +0 -1
  231. package/dist/src/file-builders/document-model/document-model.js +0 -246
  232. package/dist/src/file-builders/document-model/document-model.js.map +0 -1
  233. package/dist/src/file-builders/document-model/gen-dir.d.ts +0 -3
  234. package/dist/src/file-builders/document-model/gen-dir.d.ts.map +0 -1
  235. package/dist/src/file-builders/document-model/gen-dir.js +0 -201
  236. package/dist/src/file-builders/document-model/gen-dir.js.map +0 -1
  237. package/dist/src/file-builders/document-model/root-dir.d.ts +0 -3
  238. package/dist/src/file-builders/document-model/root-dir.d.ts.map +0 -1
  239. package/dist/src/file-builders/document-model/root-dir.js +0 -51
  240. package/dist/src/file-builders/document-model/root-dir.js.map +0 -1
  241. package/dist/src/file-builders/document-model/src-dir.d.ts +0 -3
  242. package/dist/src/file-builders/document-model/src-dir.d.ts.map +0 -1
  243. package/dist/src/file-builders/document-model/src-dir.js +0 -118
  244. package/dist/src/file-builders/document-model/src-dir.js.map +0 -1
  245. package/dist/src/file-builders/document-model/tests-dir.d.ts +0 -3
  246. package/dist/src/file-builders/document-model/tests-dir.d.ts.map +0 -1
  247. package/dist/src/file-builders/document-model/tests-dir.js +0 -127
  248. package/dist/src/file-builders/document-model/tests-dir.js.map +0 -1
  249. package/dist/src/file-builders/document-model/upgrades-dir.d.ts +0 -31
  250. package/dist/src/file-builders/document-model/upgrades-dir.d.ts.map +0 -1
  251. package/dist/src/file-builders/document-model/upgrades-dir.js +0 -135
  252. package/dist/src/file-builders/document-model/upgrades-dir.js.map +0 -1
  253. package/dist/src/file-builders/drive-editor.d.ts +0 -9
  254. package/dist/src/file-builders/drive-editor.d.ts.map +0 -1
  255. package/dist/src/file-builders/drive-editor.js +0 -164
  256. package/dist/src/file-builders/drive-editor.js.map +0 -1
  257. package/dist/src/file-builders/editor-common.d.ts +0 -13
  258. package/dist/src/file-builders/editor-common.d.ts.map +0 -1
  259. package/dist/src/file-builders/editor-common.js +0 -26
  260. package/dist/src/file-builders/editor-common.js.map +0 -1
  261. package/dist/src/file-builders/index-files.d.ts +0 -18
  262. package/dist/src/file-builders/index-files.d.ts.map +0 -1
  263. package/dist/src/file-builders/index-files.js +0 -25
  264. package/dist/src/file-builders/index-files.js.map +0 -1
  265. package/dist/src/file-builders/index.d.ts +0 -10
  266. package/dist/src/file-builders/index.d.ts.map +0 -1
  267. package/dist/src/file-builders/index.js +0 -9
  268. package/dist/src/file-builders/index.js.map +0 -1
  269. package/dist/src/file-builders/module-files.d.ts +0 -52
  270. package/dist/src/file-builders/module-files.d.ts.map +0 -1
  271. package/dist/src/file-builders/module-files.js +0 -230
  272. package/dist/src/file-builders/module-files.js.map +0 -1
  273. package/dist/src/file-builders/subgraphs.d.ts +0 -6
  274. package/dist/src/file-builders/subgraphs.d.ts.map +0 -1
  275. package/dist/src/file-builders/subgraphs.js +0 -53
  276. package/dist/src/file-builders/subgraphs.js.map +0 -1
  277. package/dist/src/file-builders/types.d.ts +0 -66
  278. package/dist/src/file-builders/types.d.ts.map +0 -1
  279. package/dist/src/file-builders/types.js +0 -2
  280. package/dist/src/file-builders/types.js.map +0 -1
  281. package/dist/src/index.d.ts +0 -5
  282. package/dist/src/index.d.ts.map +0 -1
  283. package/dist/src/index.js +0 -5
  284. package/dist/src/index.js.map +0 -1
  285. package/dist/src/name-builders/get-action-names.d.ts +0 -6
  286. package/dist/src/name-builders/get-action-names.d.ts.map +0 -1
  287. package/dist/src/name-builders/get-action-names.js +0 -16
  288. package/dist/src/name-builders/get-action-names.js.map +0 -1
  289. package/dist/src/name-builders/get-variable-names.d.ts +0 -48
  290. package/dist/src/name-builders/get-variable-names.d.ts.map +0 -1
  291. package/dist/src/name-builders/get-variable-names.js +0 -147
  292. package/dist/src/name-builders/get-variable-names.js.map +0 -1
  293. package/dist/src/name-builders/index.d.ts +0 -3
  294. package/dist/src/name-builders/index.d.ts.map +0 -1
  295. package/dist/src/name-builders/index.js +0 -3
  296. package/dist/src/name-builders/index.js.map +0 -1
  297. package/dist/src/templates/boilerplate/AGENTS.md.d.ts +0 -2
  298. package/dist/src/templates/boilerplate/AGENTS.md.d.ts.map +0 -1
  299. package/dist/src/templates/boilerplate/AGENTS.md.js +0 -408
  300. package/dist/src/templates/boilerplate/AGENTS.md.js.map +0 -1
  301. package/dist/src/templates/boilerplate/CLAUDE.md.d.ts +0 -2
  302. package/dist/src/templates/boilerplate/CLAUDE.md.d.ts.map +0 -1
  303. package/dist/src/templates/boilerplate/CLAUDE.md.js +0 -408
  304. package/dist/src/templates/boilerplate/CLAUDE.md.js.map +0 -1
  305. package/dist/src/templates/boilerplate/LICENSE.d.ts +0 -2
  306. package/dist/src/templates/boilerplate/LICENSE.d.ts.map +0 -1
  307. package/dist/src/templates/boilerplate/LICENSE.js.map +0 -1
  308. package/dist/src/templates/boilerplate/README.md.d.ts +0 -2
  309. package/dist/src/templates/boilerplate/README.md.d.ts.map +0 -1
  310. package/dist/src/templates/boilerplate/README.md.js +0 -194
  311. package/dist/src/templates/boilerplate/README.md.js.map +0 -1
  312. package/dist/src/templates/boilerplate/claude/settings.local.json.d.ts +0 -2
  313. package/dist/src/templates/boilerplate/claude/settings.local.json.d.ts.map +0 -1
  314. package/dist/src/templates/boilerplate/claude/settings.local.json.js +0 -18
  315. package/dist/src/templates/boilerplate/claude/settings.local.json.js.map +0 -1
  316. package/dist/src/templates/boilerplate/cursor/mcp.json.d.ts +0 -2
  317. package/dist/src/templates/boilerplate/cursor/mcp.json.d.ts.map +0 -1
  318. package/dist/src/templates/boilerplate/cursor/mcp.json.js +0 -12
  319. package/dist/src/templates/boilerplate/cursor/mcp.json.js.map +0 -1
  320. package/dist/src/templates/boilerplate/document-models/document-models.d.ts +0 -2
  321. package/dist/src/templates/boilerplate/document-models/document-models.d.ts.map +0 -1
  322. package/dist/src/templates/boilerplate/document-models/document-models.js +0 -7
  323. package/dist/src/templates/boilerplate/document-models/document-models.js.map +0 -1
  324. package/dist/src/templates/boilerplate/document-models/index.d.ts +0 -2
  325. package/dist/src/templates/boilerplate/document-models/index.d.ts.map +0 -1
  326. package/dist/src/templates/boilerplate/document-models/index.js +0 -2
  327. package/dist/src/templates/boilerplate/document-models/index.js.map +0 -1
  328. package/dist/src/templates/boilerplate/editors/editors.d.ts +0 -2
  329. package/dist/src/templates/boilerplate/editors/editors.d.ts.map +0 -1
  330. package/dist/src/templates/boilerplate/editors/editors.js +0 -7
  331. package/dist/src/templates/boilerplate/editors/editors.js.map +0 -1
  332. package/dist/src/templates/boilerplate/editors/index.d.ts +0 -2
  333. package/dist/src/templates/boilerplate/editors/index.d.ts.map +0 -1
  334. package/dist/src/templates/boilerplate/editors/index.js +0 -2
  335. package/dist/src/templates/boilerplate/editors/index.js.map +0 -1
  336. package/dist/src/templates/boilerplate/eslint.config.js.d.ts +0 -2
  337. package/dist/src/templates/boilerplate/eslint.config.js.d.ts.map +0 -1
  338. package/dist/src/templates/boilerplate/eslint.config.js.js +0 -140
  339. package/dist/src/templates/boilerplate/eslint.config.js.js.map +0 -1
  340. package/dist/src/templates/boilerplate/gemini/settings.json.d.ts +0 -2
  341. package/dist/src/templates/boilerplate/gemini/settings.json.d.ts.map +0 -1
  342. package/dist/src/templates/boilerplate/gemini/settings.json.js +0 -12
  343. package/dist/src/templates/boilerplate/gemini/settings.json.js.map +0 -1
  344. package/dist/src/templates/boilerplate/gitignore.d.ts +0 -2
  345. package/dist/src/templates/boilerplate/gitignore.d.ts.map +0 -1
  346. package/dist/src/templates/boilerplate/gitignore.js +0 -11
  347. package/dist/src/templates/boilerplate/gitignore.js.map +0 -1
  348. package/dist/src/templates/boilerplate/index.d.ts +0 -2
  349. package/dist/src/templates/boilerplate/index.d.ts.map +0 -1
  350. package/dist/src/templates/boilerplate/index.html.d.ts +0 -2
  351. package/dist/src/templates/boilerplate/index.html.d.ts.map +0 -1
  352. package/dist/src/templates/boilerplate/index.html.js +0 -31
  353. package/dist/src/templates/boilerplate/index.html.js.map +0 -1
  354. package/dist/src/templates/boilerplate/index.html.legacy.d.ts +0 -2
  355. package/dist/src/templates/boilerplate/index.html.legacy.d.ts.map +0 -1
  356. package/dist/src/templates/boilerplate/index.html.legacy.js +0 -36
  357. package/dist/src/templates/boilerplate/index.html.legacy.js.map +0 -1
  358. package/dist/src/templates/boilerplate/index.js +0 -8
  359. package/dist/src/templates/boilerplate/index.js.map +0 -1
  360. package/dist/src/templates/boilerplate/mcp.json.d.ts +0 -2
  361. package/dist/src/templates/boilerplate/mcp.json.d.ts.map +0 -1
  362. package/dist/src/templates/boilerplate/mcp.json.js +0 -12
  363. package/dist/src/templates/boilerplate/mcp.json.js.map +0 -1
  364. package/dist/src/templates/boilerplate/npmrc.d.ts +0 -2
  365. package/dist/src/templates/boilerplate/npmrc.d.ts.map +0 -1
  366. package/dist/src/templates/boilerplate/npmrc.js +0 -2
  367. package/dist/src/templates/boilerplate/npmrc.js.map +0 -1
  368. package/dist/src/templates/boilerplate/package.json.d.ts +0 -2
  369. package/dist/src/templates/boilerplate/package.json.d.ts.map +0 -1
  370. package/dist/src/templates/boilerplate/package.json.js +0 -115
  371. package/dist/src/templates/boilerplate/package.json.js.map +0 -1
  372. package/dist/src/templates/boilerplate/package.json.legacy.d.ts +0 -55
  373. package/dist/src/templates/boilerplate/package.json.legacy.d.ts.map +0 -1
  374. package/dist/src/templates/boilerplate/package.json.legacy.js +0 -55
  375. package/dist/src/templates/boilerplate/package.json.legacy.js.map +0 -1
  376. package/dist/src/templates/boilerplate/powerhouse.config.json.d.ts +0 -6
  377. package/dist/src/templates/boilerplate/powerhouse.config.json.d.ts.map +0 -1
  378. package/dist/src/templates/boilerplate/powerhouse.config.json.js +0 -46
  379. package/dist/src/templates/boilerplate/powerhouse.config.json.js.map +0 -1
  380. package/dist/src/templates/boilerplate/powerhouse.manifest.json.d.ts +0 -2
  381. package/dist/src/templates/boilerplate/powerhouse.manifest.json.d.ts.map +0 -1
  382. package/dist/src/templates/boilerplate/powerhouse.manifest.json.js +0 -19
  383. package/dist/src/templates/boilerplate/powerhouse.manifest.json.js.map +0 -1
  384. package/dist/src/templates/boilerplate/processors/index.d.ts +0 -2
  385. package/dist/src/templates/boilerplate/processors/index.d.ts.map +0 -1
  386. package/dist/src/templates/boilerplate/processors/index.js +0 -2
  387. package/dist/src/templates/boilerplate/processors/index.js.map +0 -1
  388. package/dist/src/templates/boilerplate/style.css.d.ts +0 -2
  389. package/dist/src/templates/boilerplate/style.css.d.ts.map +0 -1
  390. package/dist/src/templates/boilerplate/style.css.js +0 -17
  391. package/dist/src/templates/boilerplate/style.css.js.map +0 -1
  392. package/dist/src/templates/boilerplate/subgraphs/index.d.ts +0 -2
  393. package/dist/src/templates/boilerplate/subgraphs/index.d.ts.map +0 -1
  394. package/dist/src/templates/boilerplate/subgraphs/index.js +0 -2
  395. package/dist/src/templates/boilerplate/subgraphs/index.js.map +0 -1
  396. package/dist/src/templates/boilerplate/tsconfig.json.d.ts +0 -2
  397. package/dist/src/templates/boilerplate/tsconfig.json.d.ts.map +0 -1
  398. package/dist/src/templates/boilerplate/tsconfig.json.js +0 -46
  399. package/dist/src/templates/boilerplate/tsconfig.json.js.map +0 -1
  400. package/dist/src/templates/boilerplate/vite.config.ts.d.ts +0 -2
  401. package/dist/src/templates/boilerplate/vite.config.ts.d.ts.map +0 -1
  402. package/dist/src/templates/boilerplate/vite.config.ts.js +0 -21
  403. package/dist/src/templates/boilerplate/vite.config.ts.js.map +0 -1
  404. package/dist/src/templates/boilerplate/vitest.config.ts.d.ts +0 -2
  405. package/dist/src/templates/boilerplate/vitest.config.ts.d.ts.map +0 -1
  406. package/dist/src/templates/boilerplate/vitest.config.ts.js +0 -21
  407. package/dist/src/templates/boilerplate/vitest.config.ts.js.map +0 -1
  408. package/dist/src/templates/document-editor/editor.d.ts +0 -5
  409. package/dist/src/templates/document-editor/editor.d.ts.map +0 -1
  410. package/dist/src/templates/document-editor/editor.js +0 -85
  411. package/dist/src/templates/document-editor/editor.js.map +0 -1
  412. package/dist/src/templates/document-editor/module.d.ts +0 -7
  413. package/dist/src/templates/document-editor/module.d.ts.map +0 -1
  414. package/dist/src/templates/document-editor/module.js +0 -16
  415. package/dist/src/templates/document-editor/module.js.map +0 -1
  416. package/dist/src/templates/document-model/actions.d.ts +0 -3
  417. package/dist/src/templates/document-model/actions.d.ts.map +0 -1
  418. package/dist/src/templates/document-model/actions.js +0 -28
  419. package/dist/src/templates/document-model/actions.js.map +0 -1
  420. package/dist/src/templates/document-model/gen/actions.d.ts +0 -3
  421. package/dist/src/templates/document-model/gen/actions.d.ts.map +0 -1
  422. package/dist/src/templates/document-model/gen/actions.js +0 -40
  423. package/dist/src/templates/document-model/gen/actions.js.map +0 -1
  424. package/dist/src/templates/document-model/gen/creators.d.ts +0 -3
  425. package/dist/src/templates/document-model/gen/creators.d.ts.map +0 -1
  426. package/dist/src/templates/document-model/gen/creators.js +0 -16
  427. package/dist/src/templates/document-model/gen/creators.js.map +0 -1
  428. package/dist/src/templates/document-model/gen/document-schema.d.ts +0 -3
  429. package/dist/src/templates/document-model/gen/document-schema.d.ts.map +0 -1
  430. package/dist/src/templates/document-model/gen/document-schema.js +0 -56
  431. package/dist/src/templates/document-model/gen/document-schema.js.map +0 -1
  432. package/dist/src/templates/document-model/gen/document-type.d.ts +0 -3
  433. package/dist/src/templates/document-model/gen/document-type.d.ts.map +0 -1
  434. package/dist/src/templates/document-model/gen/document-type.js +0 -5
  435. package/dist/src/templates/document-model/gen/document-type.js.map +0 -1
  436. package/dist/src/templates/document-model/gen/index.d.ts +0 -3
  437. package/dist/src/templates/document-model/gen/index.d.ts.map +0 -1
  438. package/dist/src/templates/document-model/gen/index.js +0 -29
  439. package/dist/src/templates/document-model/gen/index.js.map +0 -1
  440. package/dist/src/templates/document-model/gen/modules/actions.d.ts +0 -8
  441. package/dist/src/templates/document-model/gen/modules/actions.d.ts.map +0 -1
  442. package/dist/src/templates/document-model/gen/modules/actions.js +0 -39
  443. package/dist/src/templates/document-model/gen/modules/actions.js.map +0 -1
  444. package/dist/src/templates/document-model/gen/modules/creators.d.ts +0 -3
  445. package/dist/src/templates/document-model/gen/modules/creators.d.ts.map +0 -1
  446. package/dist/src/templates/document-model/gen/modules/creators.js +0 -97
  447. package/dist/src/templates/document-model/gen/modules/creators.js.map +0 -1
  448. package/dist/src/templates/document-model/gen/modules/error.d.ts +0 -3
  449. package/dist/src/templates/document-model/gen/modules/error.d.ts.map +0 -1
  450. package/dist/src/templates/document-model/gen/modules/error.js +0 -73
  451. package/dist/src/templates/document-model/gen/modules/error.js.map +0 -1
  452. package/dist/src/templates/document-model/gen/modules/operations.d.ts +0 -3
  453. package/dist/src/templates/document-model/gen/modules/operations.d.ts.map +0 -1
  454. package/dist/src/templates/document-model/gen/modules/operations.js +0 -61
  455. package/dist/src/templates/document-model/gen/modules/operations.js.map +0 -1
  456. package/dist/src/templates/document-model/gen/ph-factories.d.ts +0 -3
  457. package/dist/src/templates/document-model/gen/ph-factories.d.ts.map +0 -1
  458. package/dist/src/templates/document-model/gen/ph-factories.js +0 -93
  459. package/dist/src/templates/document-model/gen/ph-factories.js.map +0 -1
  460. package/dist/src/templates/document-model/gen/reducer.d.ts +0 -3
  461. package/dist/src/templates/document-model/gen/reducer.d.ts.map +0 -1
  462. package/dist/src/templates/document-model/gen/reducer.js +0 -106
  463. package/dist/src/templates/document-model/gen/reducer.js.map +0 -1
  464. package/dist/src/templates/document-model/gen/schema/index.d.ts +0 -2
  465. package/dist/src/templates/document-model/gen/schema/index.d.ts.map +0 -1
  466. package/dist/src/templates/document-model/gen/schema/index.js +0 -6
  467. package/dist/src/templates/document-model/gen/schema/index.js.map +0 -1
  468. package/dist/src/templates/document-model/gen/types.d.ts +0 -3
  469. package/dist/src/templates/document-model/gen/types.d.ts.map +0 -1
  470. package/dist/src/templates/document-model/gen/types.js +0 -38
  471. package/dist/src/templates/document-model/gen/types.js.map +0 -1
  472. package/dist/src/templates/document-model/gen/utils.d.ts +0 -3
  473. package/dist/src/templates/document-model/gen/utils.d.ts.map +0 -1
  474. package/dist/src/templates/document-model/gen/utils.js +0 -77
  475. package/dist/src/templates/document-model/gen/utils.js.map +0 -1
  476. package/dist/src/templates/document-model/hooks.d.ts +0 -3
  477. package/dist/src/templates/document-model/hooks.d.ts.map +0 -1
  478. package/dist/src/templates/document-model/hooks.js +0 -52
  479. package/dist/src/templates/document-model/hooks.js.map +0 -1
  480. package/dist/src/templates/document-model/index.d.ts +0 -2
  481. package/dist/src/templates/document-model/index.d.ts.map +0 -1
  482. package/dist/src/templates/document-model/index.js +0 -9
  483. package/dist/src/templates/document-model/index.js.map +0 -1
  484. package/dist/src/templates/document-model/module.d.ts +0 -9
  485. package/dist/src/templates/document-model/module.d.ts.map +0 -1
  486. package/dist/src/templates/document-model/module.js +0 -26
  487. package/dist/src/templates/document-model/module.js.map +0 -1
  488. package/dist/src/templates/document-model/src/index.d.ts +0 -2
  489. package/dist/src/templates/document-model/src/index.d.ts.map +0 -1
  490. package/dist/src/templates/document-model/src/index.js +0 -5
  491. package/dist/src/templates/document-model/src/index.js.map +0 -1
  492. package/dist/src/templates/document-model/src/tests/document-model.test.d.ts +0 -3
  493. package/dist/src/templates/document-model/src/tests/document-model.test.d.ts.map +0 -1
  494. package/dist/src/templates/document-model/src/tests/document-model.test.js +0 -121
  495. package/dist/src/templates/document-model/src/tests/document-model.test.js.map +0 -1
  496. package/dist/src/templates/document-model/src/tests/module.test.d.ts +0 -6
  497. package/dist/src/templates/document-model/src/tests/module.test.d.ts.map +0 -1
  498. package/dist/src/templates/document-model/src/tests/module.test.js +0 -87
  499. package/dist/src/templates/document-model/src/tests/module.test.js.map +0 -1
  500. package/dist/src/templates/document-model/src/utils.d.ts +0 -2
  501. package/dist/src/templates/document-model/src/utils.d.ts.map +0 -1
  502. package/dist/src/templates/document-model/src/utils.js +0 -5
  503. package/dist/src/templates/document-model/src/utils.js.map +0 -1
  504. package/dist/src/templates/document-model/upgrades/upgrade-transition.d.ts +0 -7
  505. package/dist/src/templates/document-model/upgrades/upgrade-transition.d.ts.map +0 -1
  506. package/dist/src/templates/document-model/upgrades/upgrade-transition.js +0 -22
  507. package/dist/src/templates/document-model/upgrades/upgrade-transition.js.map +0 -1
  508. package/dist/src/templates/document-model/utils.d.ts +0 -3
  509. package/dist/src/templates/document-model/utils.d.ts.map +0 -1
  510. package/dist/src/templates/document-model/utils.js +0 -11
  511. package/dist/src/templates/document-model/utils.js.map +0 -1
  512. package/dist/src/templates/drive-editor/components/CreateDocument.d.ts +0 -2
  513. package/dist/src/templates/drive-editor/components/CreateDocument.d.ts.map +0 -1
  514. package/dist/src/templates/drive-editor/components/CreateDocument.js +0 -58
  515. package/dist/src/templates/drive-editor/components/CreateDocument.js.map +0 -1
  516. package/dist/src/templates/drive-editor/components/DriveContents.d.ts +0 -2
  517. package/dist/src/templates/drive-editor/components/DriveContents.d.ts.map +0 -1
  518. package/dist/src/templates/drive-editor/components/DriveContents.js +0 -24
  519. package/dist/src/templates/drive-editor/components/DriveContents.js.map +0 -1
  520. package/dist/src/templates/drive-editor/components/DriveExplorer.d.ts +0 -2
  521. package/dist/src/templates/drive-editor/components/DriveExplorer.d.ts.map +0 -1
  522. package/dist/src/templates/drive-editor/components/DriveExplorer.js +0 -32
  523. package/dist/src/templates/drive-editor/components/DriveExplorer.js.map +0 -1
  524. package/dist/src/templates/drive-editor/components/EmptyState.d.ts +0 -2
  525. package/dist/src/templates/drive-editor/components/EmptyState.d.ts.map +0 -1
  526. package/dist/src/templates/drive-editor/components/EmptyState.js +0 -19
  527. package/dist/src/templates/drive-editor/components/EmptyState.js.map +0 -1
  528. package/dist/src/templates/drive-editor/components/Files.d.ts +0 -2
  529. package/dist/src/templates/drive-editor/components/Files.d.ts.map +0 -1
  530. package/dist/src/templates/drive-editor/components/Files.js +0 -30
  531. package/dist/src/templates/drive-editor/components/Files.js.map +0 -1
  532. package/dist/src/templates/drive-editor/components/FolderTree.d.ts +0 -2
  533. package/dist/src/templates/drive-editor/components/FolderTree.d.ts.map +0 -1
  534. package/dist/src/templates/drive-editor/components/FolderTree.js +0 -108
  535. package/dist/src/templates/drive-editor/components/FolderTree.js.map +0 -1
  536. package/dist/src/templates/drive-editor/components/Folders.d.ts +0 -2
  537. package/dist/src/templates/drive-editor/components/Folders.d.ts.map +0 -1
  538. package/dist/src/templates/drive-editor/components/Folders.js +0 -28
  539. package/dist/src/templates/drive-editor/components/Folders.js.map +0 -1
  540. package/dist/src/templates/drive-editor/components/NavigationBreadcrumbs.d.ts +0 -2
  541. package/dist/src/templates/drive-editor/components/NavigationBreadcrumbs.d.ts.map +0 -1
  542. package/dist/src/templates/drive-editor/components/NavigationBreadcrumbs.js +0 -14
  543. package/dist/src/templates/drive-editor/components/NavigationBreadcrumbs.js.map +0 -1
  544. package/dist/src/templates/drive-editor/config.d.ts +0 -5
  545. package/dist/src/templates/drive-editor/config.d.ts.map +0 -1
  546. package/dist/src/templates/drive-editor/config.js +0 -11
  547. package/dist/src/templates/drive-editor/config.js.map +0 -1
  548. package/dist/src/templates/drive-editor/editor.d.ts +0 -2
  549. package/dist/src/templates/drive-editor/editor.d.ts.map +0 -1
  550. package/dist/src/templates/drive-editor/editor.js +0 -18
  551. package/dist/src/templates/drive-editor/editor.js.map +0 -1
  552. package/dist/src/templates/index.d.ts +0 -65
  553. package/dist/src/templates/index.d.ts.map +0 -1
  554. package/dist/src/templates/index.js +0 -65
  555. package/dist/src/templates/index.js.map +0 -1
  556. package/dist/src/ts-morph-generator/__tests__/ReducerGenerator.test.d.ts +0 -2
  557. package/dist/src/ts-morph-generator/__tests__/ReducerGenerator.test.d.ts.map +0 -1
  558. package/dist/src/ts-morph-generator/__tests__/ReducerGenerator.test.js +0 -491
  559. package/dist/src/ts-morph-generator/__tests__/ReducerGenerator.test.js.map +0 -1
  560. package/dist/src/ts-morph-generator/core/FileGenerator.d.ts +0 -11
  561. package/dist/src/ts-morph-generator/core/FileGenerator.d.ts.map +0 -1
  562. package/dist/src/ts-morph-generator/core/FileGenerator.js +0 -11
  563. package/dist/src/ts-morph-generator/core/FileGenerator.js.map +0 -1
  564. package/dist/src/ts-morph-generator/core/GenerationContext.d.ts +0 -39
  565. package/dist/src/ts-morph-generator/core/GenerationContext.d.ts.map +0 -1
  566. package/dist/src/ts-morph-generator/core/GenerationContext.js +0 -2
  567. package/dist/src/ts-morph-generator/core/GenerationContext.js.map +0 -1
  568. package/dist/src/ts-morph-generator/core/ReducerGenerator.d.ts +0 -12
  569. package/dist/src/ts-morph-generator/core/ReducerGenerator.d.ts.map +0 -1
  570. package/dist/src/ts-morph-generator/core/ReducerGenerator.js +0 -147
  571. package/dist/src/ts-morph-generator/core/ReducerGenerator.js.map +0 -1
  572. package/dist/src/ts-morph-generator/core/TSMorphCodeGenerator.d.ts +0 -20
  573. package/dist/src/ts-morph-generator/core/TSMorphCodeGenerator.d.ts.map +0 -1
  574. package/dist/src/ts-morph-generator/core/TSMorphCodeGenerator.js +0 -120
  575. package/dist/src/ts-morph-generator/core/TSMorphCodeGenerator.js.map +0 -1
  576. package/dist/src/ts-morph-generator/index.d.ts +0 -4
  577. package/dist/src/ts-morph-generator/index.d.ts.map +0 -1
  578. package/dist/src/ts-morph-generator/index.js +0 -4
  579. package/dist/src/ts-morph-generator/index.js.map +0 -1
  580. package/dist/src/ts-morph-generator/utilities/DeclarationManager.d.ts +0 -5
  581. package/dist/src/ts-morph-generator/utilities/DeclarationManager.d.ts.map +0 -1
  582. package/dist/src/ts-morph-generator/utilities/DeclarationManager.js +0 -10
  583. package/dist/src/ts-morph-generator/utilities/DeclarationManager.js.map +0 -1
  584. package/dist/src/ts-morph-generator/utilities/DirectoryManager.d.ts +0 -13
  585. package/dist/src/ts-morph-generator/utilities/DirectoryManager.d.ts.map +0 -1
  586. package/dist/src/ts-morph-generator/utilities/DirectoryManager.js +0 -45
  587. package/dist/src/ts-morph-generator/utilities/DirectoryManager.js.map +0 -1
  588. package/dist/src/ts-morph-generator/utilities/ImportManager.d.ts +0 -15
  589. package/dist/src/ts-morph-generator/utilities/ImportManager.d.ts.map +0 -1
  590. package/dist/src/ts-morph-generator/utilities/ImportManager.js +0 -50
  591. package/dist/src/ts-morph-generator/utilities/ImportManager.js.map +0 -1
  592. package/dist/src/ts-morph-generator/utilities/index.d.ts +0 -4
  593. package/dist/src/ts-morph-generator/utilities/index.d.ts.map +0 -1
  594. package/dist/src/ts-morph-generator/utilities/index.js +0 -4
  595. package/dist/src/ts-morph-generator/utilities/index.js.map +0 -1
  596. package/dist/src/utils/cli.d.ts +0 -26
  597. package/dist/src/utils/cli.d.ts.map +0 -1
  598. package/dist/src/utils/cli.js +0 -57
  599. package/dist/src/utils/cli.js.map +0 -1
  600. package/dist/src/utils/constants.d.ts +0 -13
  601. package/dist/src/utils/constants.d.ts.map +0 -1
  602. package/dist/src/utils/constants.js +0 -29
  603. package/dist/src/utils/constants.js.map +0 -1
  604. package/dist/src/utils/dependencies.d.ts +0 -12
  605. package/dist/src/utils/dependencies.d.ts.map +0 -1
  606. package/dist/src/utils/dependencies.js +0 -34
  607. package/dist/src/utils/dependencies.js.map +0 -1
  608. package/dist/src/utils/document-type-metadata.d.ts +0 -15
  609. package/dist/src/utils/document-type-metadata.d.ts.map +0 -1
  610. package/dist/src/utils/document-type-metadata.js +0 -67
  611. package/dist/src/utils/document-type-metadata.js.map +0 -1
  612. package/dist/src/utils/format-with-prettier.d.ts +0 -5
  613. package/dist/src/utils/format-with-prettier.d.ts.map +0 -1
  614. package/dist/src/utils/format-with-prettier.js +0 -20
  615. package/dist/src/utils/format-with-prettier.js.map +0 -1
  616. package/dist/src/utils/index.d.ts +0 -14
  617. package/dist/src/utils/index.d.ts.map +0 -1
  618. package/dist/src/utils/index.js +0 -14
  619. package/dist/src/utils/index.js.map +0 -1
  620. package/dist/src/utils/mock.d.ts +0 -3
  621. package/dist/src/utils/mock.d.ts.map +0 -1
  622. package/dist/src/utils/mock.js +0 -5
  623. package/dist/src/utils/mock.js.map +0 -1
  624. package/dist/src/utils/source-files.d.ts +0 -18
  625. package/dist/src/utils/source-files.d.ts.map +0 -1
  626. package/dist/src/utils/source-files.js +0 -39
  627. package/dist/src/utils/source-files.js.map +0 -1
  628. package/dist/src/utils/spawn-async.d.ts +0 -5
  629. package/dist/src/utils/spawn-async.d.ts.map +0 -1
  630. package/dist/src/utils/spawn-async.js +0 -29
  631. package/dist/src/utils/spawn-async.js.map +0 -1
  632. package/dist/src/utils/syntax-builders.d.ts +0 -8
  633. package/dist/src/utils/syntax-builders.d.ts.map +0 -1
  634. package/dist/src/utils/syntax-builders.js +0 -72
  635. package/dist/src/utils/syntax-builders.js.map +0 -1
  636. package/dist/src/utils/syntax-getters.d.ts +0 -9
  637. package/dist/src/utils/syntax-getters.d.ts.map +0 -1
  638. package/dist/src/utils/syntax-getters.js +0 -20
  639. package/dist/src/utils/syntax-getters.js.map +0 -1
  640. package/dist/src/utils/ts-morph-project.d.ts +0 -15
  641. package/dist/src/utils/ts-morph-project.d.ts.map +0 -1
  642. package/dist/src/utils/ts-morph-project.js +0 -28
  643. package/dist/src/utils/ts-morph-project.js.map +0 -1
  644. package/dist/src/utils/unsafe-utils.d.ts +0 -8
  645. package/dist/src/utils/unsafe-utils.d.ts.map +0 -1
  646. package/dist/src/utils/unsafe-utils.js +0 -23
  647. package/dist/src/utils/unsafe-utils.js.map +0 -1
  648. package/dist/src/utils/validation.d.ts +0 -18
  649. package/dist/src/utils/validation.d.ts.map +0 -1
  650. package/dist/src/utils/validation.js +0 -138
  651. package/dist/src/utils/validation.js.map +0 -1
  652. package/dist/tsconfig.tsbuildinfo +0 -1
  653. package/dist/vitest.config.d.ts +0 -3
  654. package/dist/vitest.config.d.ts.map +0 -1
  655. package/dist/vitest.config.js +0 -19
  656. package/dist/vitest.config.js.map +0 -1
@@ -0,0 +1,4611 @@
1
+ import { getActionInputName, getActionInputTypeNames, getActionType, getActionTypeName } from "./src/name-builders/index.mjs";
2
+ import { camelCase, capitalCase, constantCase, kebabCase, pascalCase } from "change-case";
3
+ import { css, html, js, json, md, ts, tsx, yaml } from "@tmpl/core";
4
+ //#region src/templates/boilerplate/AGENTS.md.ts
5
+ const agentsTemplate = md`
6
+ # Powerhouse Document Models Assistant
7
+
8
+ This project creates document models, editors, processors and subgraphs for the Powerhouse ecosystem. Your role is to help users create these modules based on their needs.
9
+
10
+ ## Core Concepts
11
+
12
+ - **Document Model**: A template for creating documents. Defines schema and allowed operations for a document type.
13
+ - **Document**: An instance of a document model containing actual data that follows the model's structure and can be modified using operations.
14
+ - **Drive**: A document of type "powerhouse/document-drive" representing a collection of documents and folders. Add documents using "addActions" with "ADD_FILE" action.
15
+ - **Action**: A proposed change to a document (JSON object with action name and input). Dispatch using "addActions" tool.
16
+ - **Operation**: A completed change to a document containing the action plus metadata (index, timestamp, hash, errors). Actions become operations after dispatch.
17
+
18
+ ## Technology Primer
19
+
20
+ - **Reactor**: The core Powerhouse engine. It is modular and storage-agnostic, loads document models at runtime, and synchronizes documents across nodes via drives.
21
+ - **Reactor Package**: A deployable bundle that extends the Reactor. It contains one or more document models, editors, processors, and subgraphs. A Vetra project generates a Reactor Package.
22
+ - **Connect**: The Powerhouse web application for document management. End users open Connect to browse drives, create documents, and interact with editors.
23
+ - **Switchboard**: The Powerhouse API service. It exposes GraphQL and MCP endpoints so external tools can read/write documents programmatically.
24
+ - **Vetra**: The local development environment for building Reactor Packages. It includes Vetra Studio (a local Connect instance) and Vetra Switchboard (a local Switchboard with reactor-mcp). Start it with \`ph vetra\`.
25
+
26
+ ## CRITICAL: MCP Tool Usage Rules
27
+
28
+ **MANDATORY**: The \`reactor-mcp\` MUST BE USED when handling documents or document-models for the Powerhouse/Vetra ecosystem.
29
+ If the \`reactor-mcp\` server is unavailable, ask the user to run \`ph vetra\` on a separate terminal to start the server and try to reconnect to the MCP server, DO NOT run it yourself.
30
+
31
+ ### Key Requirements:
32
+
33
+ - Never set document IDs manually - they're auto-generated by 'createDocument'
34
+ - Minimize "addActions" calls by batching multiple actions together
35
+ - Add new document model documents to "vetra-{hash}" drive unless specified otherwise
36
+ - Always check document model schema before calling addActions
37
+ - Use MCP tools for ALL document and document-model operations
38
+
39
+ ## Document Model Creation Workflow
40
+
41
+ ### 1. Planning Phase
42
+
43
+ **MANDATORY**: Present your proposal to the user and ask for confirmation before implementing ANY document model.
44
+
45
+ - **ALWAYS** describe the proposed document model structure (state schema, operations, modules) before creating
46
+ - **NEVER** proceed with implementation without explicit user approval of your proposal
47
+ - When in doubt, ask for clarification
48
+ - Break complex models into logical modules and operations
49
+
50
+ #### Document Type ID Format
51
+
52
+ - **Type ID**: \`{organization}/{document-type-name}\` (e.g., \`pizza-plaza/order\`, \`acme/invoice\`)
53
+ - **File extension**: 2-4 characters with leading dot (e.g., \`.ordr\`, \`.inv\`)
54
+ - **Name**: Must match \`/[a-zA-Z][a-zA-Z0-9 ]*/\` — human-readable, capitalized (e.g., \`"Order"\`, \`"Invoice"\`)
55
+
56
+ ### 2. Pre-Implementation Requirements
57
+
58
+ **MANDATORY**: Check document model schema before making any MCP tool calls.
59
+
60
+ - **ALWAYS** use \`mcp__reactor-mcp__getDocumentModelSchema\` with \`type: "powerhouse/document-model"\` first
61
+ - Review input schema requirements for operations like \`ADD_MODULE\`, \`ADD_OPERATION\`, etc.
62
+ - Ensure all required parameters (like \`id\` or \`scope\` fields) are included in action inputs
63
+ - This prevents failed tool calls and reduces iteration
64
+
65
+ ### 3. Implementation Requirements
66
+
67
+ - Document model reducers must be **pure synchronous functions**
68
+ - Reducers receive current state and operation, always returning the same result
69
+ - Values like dates/IDs must come from operation input, not generated in reducer
70
+ - Reducer code goes into SET_OPERATION_REDUCER action (no function header needed)
71
+ - Reducers are wrapped with Mutative - you can mutate the state object directly
72
+ - External imports go at the beginning of the actual reducer file in \`src/\`
73
+ - Ensure that the reducer code of each operation in the document model schema is applied in \`document-models/<document-model-name>/src/reducers/<module-name>.ts\`
74
+
75
+ ### 4. Quality assurance
76
+
77
+ After doing changes to the code, or after creating a new document model or a new editor, _YOU MUST RUN_ the following commands to check for errors in your implementation:
78
+
79
+ - **TypeScript Check**: Run \`npm run tsc\` to validate type safety
80
+ - **ESLint Check**: Run \`npm run lint:fix\` to check for errors with ESLint
81
+
82
+ ## Document editor creation flow
83
+
84
+ **CRITICAL**: Creating a document editor is a **two-phase** process. You must NEVER skip Phase 1 or try to manually create editor files from scratch. The codegen system generates the boilerplate — your job is only to implement the UI inside it.
85
+
86
+ ### Phase 1: Create the editor document via MCP (MANDATORY FIRST STEP)
87
+
88
+ **NEVER** start by writing editor code, creating component files, or looking at how to scaffold an editor manually. The **only** way to create a new editor is through the MCP tools:
89
+
90
+ 1. Check if the document editor already exists. If it does, ask the user if a new one should be created or if the existing one should be reimplemented
91
+ 2. If it's a new editor, get the document editor schema using \`mcp__reactor-mcp__getDocumentModelSchema\` with \`type: "powerhouse/document-editor"\`
92
+ 3. Create a new editor document on the \`vetra-{hash}\` drive of type \`powerhouse/document-editor\` using \`mcp__reactor-mcp__addActions\` with the \`ADD_FILE\` action
93
+ 4. Configure the editor document with the required actions (set the editor name, target document model, etc.) according to the schema
94
+
95
+ ⚠️ **The editor document MUST be confirmed/published — if it is left as draft state, the codegen will NOT run and no editor files will be generated.** Make sure the document state is not "DRAFT" after creation.
96
+
97
+ 5. Once the editor document is confirmed on the drive, the codegen automatically runs and generates boilerplate files in the \`editors/\` folder, including hooks, type definitions, and the editor component shell
98
+
99
+ ### Phase 2: Implement the editor UI
100
+
101
+ Only **after** the codegen has produced the boilerplate files, proceed with the UI implementation:
102
+
103
+ - Inspect the generated files in the \`editors/\` folder — do NOT create new files for the main editor component; edit the generated one
104
+ - Inspect the hooks in \`editors/hooks\` as they should be useful
105
+ - Read the schema of the document model that the editor is for to know how to interact with it
106
+ - Every editor **MUST** include \`<DocumentToolbar />\` imported from \`@powerhousedao/design-system/connect/index\`. Place it at the top of the editor component — do not put anything next to it.
107
+ - Style the editor using tailwind classes or a style tag. If using a style tag, make sure to make the selectors specific to only apply to the editor component.
108
+ - Create modular components for the UI elements and place them on separate files to make it easier to maintain and update
109
+ - Consider using the React Components exported by \`@powerhousedao/design-system\` and \`@powerhousedao/document-engineering\`
110
+ - Separate business logic from presentation logic
111
+ - Use TypeScript for type safety, avoid using any and type casting
112
+ - Always check for type and lint errors after creating or modifying the editor
113
+ - **CRITICAL**: After creating a new editor, verify that \`editors/editors.ts\` includes the new editor module. The codegen should update this file automatically, but if it doesn't, manually add the import and include the editor in the \`editors\` array. Without this registration, Connect won't find an editor for the document type. Example:
114
+
115
+ ~~~typescript
116
+ import type { EditorModule } from "document-model";
117
+ import { TodoListEditor } from "./todo-list-editor/module.js";
118
+
119
+ export const editors: EditorModule[] = [TodoListEditor];
120
+ ~~~
121
+
122
+ ### Document Editor Implementation Pattern
123
+
124
+ **CRITICAL**: When implementing document editors, use the modern React hooks pattern from \`@powerhousedao/reactor-browser\`.
125
+
126
+ The following section is valid for editors that edit a single document type.
127
+
128
+ #### Required Imports and Setup
129
+
130
+ Using a "Todo" document model as example:
131
+
132
+ ~~~typescript
133
+ import { generateId } from "document-model";
134
+ import { useSelectedTodoDocument } from "../hooks/useTodoDocument.js";
135
+ import {
136
+ addTodo,
137
+ } from "../../document-models/todo/gen/creators.js";
138
+
139
+ export default function Editor() {
140
+ const [document, dispatch] = useSelectedTodoDocument();
141
+
142
+ function handleAddTodo(values: { title: string }) {
143
+ if (values.title) {
144
+ dispatch(addTodo({ id: generateId(), title: values.title }));
145
+ }
146
+ };
147
+
148
+ // Note: The \`useSelectedTodoDocument\` hook is auto-generated. Check the \`editors/hooks\` folder for the exact hook name.
149
+ // Action creators like \`addTodo\` are exported from the document model's \`gen/creators.js\` file.
150
+ ~~~
151
+
152
+ The \`useSelectedTodoDocument\` gets generated automatically so you don't need to implement it yourself.
153
+
154
+ ## ⚠️ CRITICAL: Generated Files & Modification Rules
155
+
156
+ ### Generated Files Rule
157
+
158
+ **NEVER edit files in \`gen/\` folders** - they are auto-generated and will be overwritten.
159
+
160
+ ### Document Model Modification Process
161
+
162
+ For ANY document model changes, follow this **mandatory** two-step process:
163
+
164
+ #### Step 1: Update Document Model via MCP
165
+
166
+ Use \`mcp__reactor-mcp__addActions\` with operations like:
167
+
168
+ - \`SET_OPERATION_SCHEMA\` - update input/output schemas
169
+ - \`SET_OPERATION_REDUCER\` - update reducer code
170
+ - \`SET_STATE_SCHEMA\` - update state definitions
171
+
172
+ #### Step 2: Update Existing Source Files
173
+
174
+ **ALSO manually update existing reducer files in \`src/\` folder** - these are NOT auto-generated.
175
+ Make sure to check if the operation reducer code needs to be updated after changing the state schema.
176
+
177
+ ### ⚠️ Critical Reminder
178
+
179
+ **ALWAYS do BOTH steps when fixing reducer issues:**
180
+
181
+ 1. ✅ Fix existing reducer files in \`src/\` manually
182
+ 2. ✅ Update document model via MCP with same fixes
183
+
184
+ **Forgetting step 2 means future code generations will still contain the bugs!**
185
+
186
+ ## Reducer Implementation Guidelines
187
+
188
+ ### ❌ Forbidden in Reducers (Non-Deterministic)
189
+
190
+ - \`crypto.randomUUID()\`, \`Math.random()\`, \`Date.now()\`, \`new Date()\`
191
+ - External API calls or side effects
192
+ - Asynchronous functions
193
+ - Any non-deterministic functions
194
+
195
+ ### ❌ Forbidden Patterns
196
+
197
+ ~~~typescript
198
+ // NEVER use fallback values with non-deterministic functions
199
+ id: action.input.id || crypto.randomUUID(); // ❌ FORBIDDEN
200
+ timestamp: action.input.timestamp || new Date(); // ❌ FORBIDDEN
201
+ ~~~
202
+
203
+ ### ✅ Required Pattern
204
+
205
+ All dynamic values must come from action input:
206
+
207
+ - **IDs**: Include \`id: OID!\` in input schema, use \`action.input.id\` in reducer
208
+ - **Timestamps**: Include \`timestamp: DateTime!\` in input schema
209
+ - **Computed values**: Calculate before dispatching action
210
+
211
+ ### Example
212
+
213
+ ~~~typescript
214
+ // ❌ BAD - impure reducer
215
+ const newItem = {
216
+ id: crypto.randomUUID(), // Non-deterministic
217
+ createdAt: new Date(), // Non-deterministic
218
+ };
219
+
220
+ // ✅ GOOD - pure reducer
221
+ const newItem = {
222
+ id: action.input.id, // From action input
223
+ createdAt: action.input.createdAt, // From action input
224
+ };
225
+ ~~~
226
+
227
+ ### Handling Nullable Input Types
228
+
229
+ **CRITICAL**: Be careful when handling optional input types:
230
+
231
+ - Optional input types use \`InputMaybe<T>\` allowing \`null | undefined | T\`.
232
+ - Optional state types use \`Maybe<T>\` = \`T | null\`.
233
+ - If there is no applicable default value then use \`|| null\`.
234
+
235
+ ~~~typescript
236
+ // ❌ BAD - Type error with Maybe<string>
237
+ amount: action.input.amount,
238
+ notes: action.input.notes,
239
+
240
+ // ✅ GOOD - Matches Maybe<T> = T | null
241
+ amount: action.input.amount || null,
242
+ notes: action.input.notes || [],
243
+ ~~~
244
+
245
+ Use truthy checks when conditionally assigning optional values from input to state:
246
+
247
+ ~~~typescript
248
+ // ❌ BAD - Type 'string | null' is not assignable to type 'string'.
249
+ if (action.input.field !== undefined) entry.field = action.input.field;
250
+
251
+ // ✅ GOOD - use truthy checks
252
+ if (action.input.field) state.field = action.input.field;
253
+
254
+ // ✅ GOOD - For booleans use explicit null/undefined checks
255
+ if (action.input.field !== undefined && action.input.field !== null)
256
+ state.field = action.input.field;
257
+ ~~~
258
+
259
+ ### Error Handling in Operations
260
+
261
+ **MANDATORY**: Define specific error types for each operation to handle invalid inputs and edge cases properly.
262
+ Action inputs are validated so they are guaranteed to respect the input schema.
263
+ Errors referenced in the reducer code will be imported automatically.
264
+
265
+ #### Error Definition Requirements
266
+
267
+ 1. **Add error definitions** to operations using \`ADD_OPERATION_ERROR\`:
268
+ - \`errorCode\`: Uppercase snake_case (e.g., \`"MISSING_ID"\`, \`"ENTRY_NOT_FOUND"\`)
269
+ - \`errorName\`: PascalCase ending with "Error" (e.g., \`"MissingIdError"\`, \`"EntryNotFoundError"\`)
270
+ - \`errorDescription\`: Human-readable description of the error condition
271
+
272
+ 2. **Error names must end with "Error"** for consistency and code generation
273
+
274
+ 3. **Use specific error types** rather than generic validation
275
+
276
+ 4. **Must use unique error names and ids**
277
+
278
+ #### Error Usage in Reducers
279
+
280
+ ~~~typescript
281
+ // ✅ GOOD - Throw specific errors by name
282
+ if (!action.input.id) {
283
+ throw new MissingIdError("ID is required for operation");
284
+ }
285
+
286
+ if (entryIndex === -1) {
287
+ throw new EntryNotFoundError(\`Entry not found\`);
288
+ }
289
+
290
+ // ❌ BAD - Generic Error
291
+ throw new Error("Something went wrong");
292
+
293
+ // ❌ BAD - Nested error access
294
+ throw new errors.ModuleName.MissingIdError("message");
295
+
296
+ // ❌ BAD - Do not import error classes in the reducer code,
297
+ import { MissingIdError } from "../../gen/module-name/error.js";
298
+
299
+ // ✅ GOOD - Simply reference the error and it will be imported automatically
300
+ throw new MissingIdError("message");
301
+ ~~~
302
+
303
+ #### Common Error Patterns
304
+
305
+ - **EntityNotFoundError**: Referenced entity doesn't exist
306
+ - **DuplicateIdError**: ID already exists when creating new entries
307
+ - **InvalidInputError**: Business logic violations
308
+ - **PermissionDeniedError**: Access control violations
309
+
310
+ #### Testing Reducer Errors
311
+
312
+ **CRITICAL**: When a reducer throws an error, the operation is **still added** to the document but with an \`.error\` property containing the error message as a string.
313
+
314
+ **DO NOT** use \`.toThrow()\` or \`expect(() => ...).toThrow()\` patterns when testing reducer errors.
315
+
316
+ ##### How Errors Work in Operations
317
+
318
+ 1. The reducer throws an error (e.g., \`throw new InvalidNameError("message")\`)
319
+ 2. The operation is still recorded in \`document.operations.global\` (or \`.local\`)
320
+ 3. The error message is stored in \`operation.error\` as a string
321
+ 4. **The state is NOT mutated** - it remains unchanged from before the operation
322
+
323
+ ##### Accessing the Correct Operation Index
324
+
325
+ **CRITICAL**: You must access the correct operation index. The index corresponds to how many operations were dispatched before it.
326
+
327
+ - If this is the **first** operation dispatched, access \`[0]\`
328
+ - If 3 operations were dispatched **before** the failing one, access \`[3]\`
329
+
330
+ ##### Example
331
+
332
+ ~~~typescript
333
+ it("should return error and not mutate state", () => {
334
+ const document = utils.createDocument();
335
+ const initialState = document.state.global.name;
336
+
337
+ const updatedDocument = reducer(document, setName({ name: "invalid" }));
338
+
339
+ // Access the correct operation index (0 = first operation)
340
+ expect(updatedDocument.operations.global[0].error).toBe(
341
+ "Name is not allowed",
342
+ );
343
+ // State remains unchanged
344
+ expect(updatedDocument.state.global.name).toBe(initialState);
345
+ });
346
+
347
+ // ❌ WRONG - Never use toThrow()
348
+ expect(() => reducer(document, setName({ name: "invalid" }))).toThrow();
349
+ ~~~
350
+
351
+ ## Document Model Structure
352
+
353
+ ### Core Components
354
+
355
+ - **Basic Metadata**: \`id\`, \`name\`, \`extension\`, \`description\`, \`author\` (name + website)
356
+ - **Specifications**: Versioned specs with \`version\`, \`changeLog\`, \`state\` (global/local with schema, initialValue, examples)
357
+ - **Modules**: Operational modules containing their operations
358
+
359
+ ## Available Document Model Operations (37 total)
360
+
361
+ | Category | Operations | Count |
362
+ | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
363
+ | **Header Management** | \`SET_MODEL_NAME\`, \`SET_MODEL_ID\`, \`SET_MODEL_EXTENSION\`, \`SET_MODEL_DESCRIPTION\`, \`SET_AUTHOR_NAME\`, \`SET_AUTHOR_WEBSITE\` | 6 |
364
+ | **Versioning** | ⚠️ **DO NOT USE** - Not implemented | 0 |
365
+ | **Module Management** | \`ADD_MODULE\`, \`SET_MODULE_NAME\`, \`SET_MODULE_DESCRIPTION\`, \`DELETE_MODULE\`, \`REORDER_MODULES\` | 5 |
366
+ | **Operation Management** | \`ADD_OPERATION\`, \`SET_OPERATION_NAME\`, \`SET_OPERATION_SCHEMA\`, \`SET_OPERATION_DESCRIPTION\`, \`SET_OPERATION_TEMPLATE\`, \`SET_OPERATION_REDUCER\`, \`MOVE_OPERATION\`, \`DELETE_OPERATION\`, \`REORDER_MODULE_OPERATIONS\` | 9 |
367
+ | **Operation Error Management** | \`ADD_OPERATION_ERROR\`, \`SET_OPERATION_ERROR_CODE\`, \`SET_OPERATION_ERROR_NAME\`, \`SET_OPERATION_ERROR_DESCRIPTION\`, \`SET_OPERATION_ERROR_TEMPLATE\`, \`DELETE_OPERATION_ERROR\`, \`REORDER_OPERATION_ERRORS\` | 7 |
368
+ | **Operation Example Management** | \`ADD_OPERATION_EXAMPLE\`, \`UPDATE_OPERATION_EXAMPLE\`, \`DELETE_OPERATION_EXAMPLE\`, \`REORDER_OPERATION_EXAMPLES\` | 4 |
369
+ | **State Management** | \`SET_STATE_SCHEMA\`, \`SET_INITIAL_STATE\`, \`ADD_STATE_EXAMPLE\`, \`UPDATE_STATE_EXAMPLE\`, \`DELETE_STATE_EXAMPLE\`, \`REORDER_STATE_EXAMPLES\` | 6 |
370
+
371
+ ## Best Practices & Design Principles
372
+
373
+ ### Scope Selection
374
+
375
+ - **\`scope: "global"\`**: State shared among all users with document access
376
+ - **\`scope: "local"\`**: State private to each individual user
377
+
378
+ ### Operation Design
379
+
380
+ - Use descriptive operation names (e.g., \`ADD_LINE_ITEM\`, \`UPDATE_RECIPIENT\`)
381
+ - One operation per user intent (separate concerns)
382
+ - Include comprehensive examples and error definitions
383
+ - Organize related operations into logical modules
384
+
385
+ ## GraphQL Schema Guidelines
386
+
387
+ ### Document State Schema
388
+
389
+ - **Most fields optional** to support creating empty documents
390
+ - Use required fields \`!\` only when absolutely necessary
391
+ - Defaults handled by operations, not schema
392
+
393
+ #### Mandatory vs Optional Field Rules
394
+
395
+ A user must always be able to create an **empty document** without providing any information. This drives the following rules:
396
+
397
+ - **Root type properties** can only be mandatory (\`!\`) if they have a logical default value (e.g., empty array, enum initial status)
398
+ - **Collections** should always use \`[Type!]!\` — inner \`!\` means no nulls in the array, outer \`!\` means the array itself defaults to empty
399
+ - **Child object fields** can be mandatory only if all their required properties also have logical defaults
400
+ - Use \`enum\` types for workflow statuses (e.g., \`status: OrderStatus!\` where the enum has an initial value like \`DRAFT\`)
401
+
402
+ ### ⚠️ CRITICAL: State Type Naming Convention
403
+
404
+ **MANDATORY**: The global state type name MUST follow this exact pattern:
405
+
406
+ ~~~graphql
407
+ type <DocumentModelName>State {
408
+ # your fields here
409
+ }
410
+ ~~~
411
+
412
+ **DO NOT** append "Global" to the state type name, even when defining global state:
413
+
414
+ ~~~graphql
415
+ // ❌ WRONG - Do not use "GlobalState" suffix
416
+ type TodoListGlobalState {
417
+ todos: [Todo!]!
418
+ }
419
+
420
+ // ✅ CORRECT - Use only "State" suffix
421
+ type TodoListState {
422
+ todos: [Todo!]!
423
+ }
424
+
425
+ // ✅ CORRECT - Use "LocalState" suffix for Local scope
426
+ type TodoListLocalState {
427
+ localTodos: [Todo!]!
428
+ }
429
+ ~~~
430
+
431
+ **Why this matters:**
432
+
433
+ - The code generator expects the type to be named \`<DocumentModelName>State\`
434
+ - Using \`GlobalState\` or \`LocalState\` suffix will cause TypeScript compilation errors
435
+ - This applies when using \`SET_STATE_SCHEMA\` with \`scope: "global"\`
436
+
437
+ **Rule**: For global state, the type should be \`<DocumentModelName>State\`. For local state (if needed), the type name should be \`<DocumentModelName>LocalState\`.
438
+
439
+ ### Available Scalar Types
440
+
441
+ | Standard | Custom Identity | Custom Amounts | Custom Specialized |
442
+ | --------- | ---------------------- | ------------------- | ------------------ |
443
+ | \`String\` | \`OID\` (Object ID) | \`Amount\` | \`EthereumAddress\` |
444
+ | \`Int\` | \`PHID\` (Powerhouse ID) | \`Amount_Tokens\` | \`EmailAddress\` |
445
+ | \`Float\` | \`OLabel\` | \`Amount_Money\` | \`Date\` |
446
+ | \`Boolean\` | | \`Amount_Fiat\` | \`DateTime\` |
447
+ | | | \`Amount_Currency\` | \`URL\` |
448
+ | | | \`Amount_Crypto\` | \`Currency\` |
449
+ | | | \`Amount_Percentage\` | |
450
+
451
+ ### Arrays and Objects
452
+
453
+ - **Arrays**: Must be mandatory \`[ObjectType!]!\`
454
+ - **Objects in arrays**: Must include \`OID!\` field for unique identification
455
+ - Include \`OLabel\` for metadata when relevant
456
+
457
+ #### OID vs PHID Usage
458
+
459
+ - \`OID\` is used as **primary key** (\`id: OID!\`) and **foreign key** (\`otherObjectId: OID!\`) within a document
460
+ - \`PHID\` is **only** for referencing **external documents** (other documents in the drive), typically alongside cached properties (like a link preview — title/snippet may become stale)
461
+ - **NEVER** use the \`ID\` type — it is a common GraphQL convention but is not used in Powerhouse document models
462
+
463
+ #### Collection Sorting & Trees
464
+
465
+ - **No need for \`position\` or \`weight\` properties** — maintain order via array index; operations like \`MOVE_X\` reorder the array directly
466
+ - **Trees**: Always define as a flat list with \`parentId: OID\` (root nodes have \`parentId = null\`); do NOT use recursive/nested types
467
+
468
+ ### Input Types
469
+
470
+ - Reflect user intent with descriptive names
471
+ - Simple, specific fields over complex nested types
472
+ - System auto-generates \`OID\` for new objects (users don't provide manually)
473
+
474
+ #### Input Type Naming Convention
475
+
476
+ - Root input type **MUST** be named \`<OperationName>Input\` (PascalCase of the operation name)
477
+ - Example: operation \`SET_CATEGORY_LABEL\` → input type \`SetCategoryLabelInput\`
478
+ - **Failing to follow this convention breaks the code generator**
479
+
480
+ #### Input Types Cannot Reference State Types
481
+
482
+ - In operation input schemas, **ONLY** \`enum\` types and scalar types from the state schema can be referenced directly
483
+ - All other state types must be **mirrored** with unique input types (e.g., state type \`MenuItem\` → input type \`NewMenuItemInput\` for the ADD operation)
484
+ - State \`enum\` types **MUST NOT** be redefined in input schemas — reference them directly
485
+ - Each operation should have its **own** input types; do not share mirror types across operations
486
+
487
+ #### Empty Input Workaround
488
+
489
+ - Input types with **zero fields** are not supported by the code generator
490
+ - Workaround: add \`_: Boolean\` as a dummy optional parameter
491
+
492
+ ~~~graphql
493
+ # ❌ BAD - empty input type breaks codegen
494
+ input ClearAllInput {}
495
+
496
+ # ✅ GOOD - dummy field workaround
497
+ input ClearAllInput {
498
+ _: Boolean
499
+ }
500
+ ~~~
501
+
502
+ ## Working with Drives
503
+
504
+ **MANDATORY**: Check the document-drive schema before performing drive operations.
505
+
506
+ ### Drive Types
507
+
508
+ There might be two drives available with a special use case:
509
+
510
+ 1. **Vetra Drive** (\`vetra-{hash}\`):
511
+ - Contains **source documents**: document models and document editors
512
+ - Used for development
513
+ - Add document model and editor definitions here
514
+
515
+ 2. **Preview Drive** (\`preview-{hash}\`, named "Vetra Preview"):
516
+ - Contains **demo and preview documents** (document instances)
517
+ - Used for showcasing and testing document models
518
+ - Add actual document instances here
519
+
520
+ ### Drive Operations
521
+
522
+ When working with drives (adding/removing documents, creating folders, etc.):
523
+
524
+ 1. **Always get the drive schema first**:
525
+
526
+ ~~~typescript
527
+ mcp__reactor -
528
+ mcp__getDocumentModelSchema({ type: "powerhouse/document-drive" });
529
+ ~~~
530
+
531
+ 2. **Review available operations** in the schema, such as:
532
+ - \`ADD_FILE\` - Add a document to the drive
533
+ - \`ADD_FOLDER\` - Create a new folder
534
+ - \`DELETE_NODE\` - Remove a file or folder (use this, NOT "DELETE_FILE")
535
+ - \`UPDATE_NODE\` - Update node properties
536
+ - \`MOVE_NODE\` - Move a node to different location
537
+
538
+ 3. **Check input schemas** for each operation to ensure you're passing correct parameters
539
+ `.raw;
540
+ //#endregion
541
+ //#region src/templates/boilerplate/claude/settings.local.json.ts
542
+ const claudeSettingsLocalTemplate = json`
543
+ {
544
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
545
+ "permissions": {
546
+ "allow": ["Bash(npm run tsc:*)", "Bash(npm run lint:*)"],
547
+ "deny": [
548
+ "Write(./document-models/*/gen/**)",
549
+ "Write(./.ph/**)",
550
+ "Edit(./document-models/*/gen/**)",
551
+ "Edit(./.ph/**)"
552
+ ]
553
+ },
554
+ "enableAllProjectMcpServers": true,
555
+ "enabledMcpjsonServers": ["reactor-mcp"]
556
+ }
557
+ `.raw;
558
+ //#endregion
559
+ //#region src/templates/boilerplate/cursor/mcp.json.ts
560
+ const cursorMcpTemplate = json`
561
+ {
562
+ "mcpServers": {
563
+ "reactor-mcp": {
564
+ "type": "http",
565
+ "url": "http://localhost:4001/mcp"
566
+ }
567
+ }
568
+ }
569
+ `.raw;
570
+ //#endregion
571
+ //#region src/templates/boilerplate/docker/connect-entrypoint.sh.ts
572
+ const connectEntrypointTemplate = `#!/bin/sh
573
+ set -e
574
+
575
+ # Substitute environment variables in nginx configuration
576
+ envsubst '\${PORT},\${PH_CONNECT_BASE_PATH}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
577
+
578
+ echo "Testing nginx configuration..."
579
+ nginx -t
580
+
581
+ if [ $? -eq 0 ]; then
582
+ echo "Connect available at: http://localhost:\${PORT}\${PH_CONNECT_BASE_PATH}"
583
+ exec nginx -g "daemon off;"
584
+ else
585
+ echo "Nginx configuration test failed"
586
+ exit 1
587
+ fi
588
+ `;
589
+ //#endregion
590
+ //#region src/templates/boilerplate/docker/Dockerfile.ts
591
+ const dockerfileTemplate = `# =============================================================================
592
+ # Multi-stage Dockerfile for Powerhouse Document Model Packages
593
+ # Produces two images: connect (frontend) and switchboard (backend)
594
+ #
595
+ # Build commands:
596
+ # docker build --target connect -t <registry>/<project>/connect:<tag> .
597
+ # docker build --target switchboard -t <registry>/<project>/switchboard:<tag> .
598
+ # =============================================================================
599
+
600
+ # -----------------------------------------------------------------------------
601
+ # Base stage: Common setup for building
602
+ # -----------------------------------------------------------------------------
603
+ FROM node:24-alpine AS base
604
+
605
+ WORKDIR /app
606
+
607
+ # Install build dependencies
608
+ RUN apk add --no-cache python3 make g++ git bash \\
609
+ && ln -sf /usr/bin/python3 /usr/bin/python
610
+
611
+ # Setup pnpm
612
+ ENV PNPM_HOME="/pnpm"
613
+ ENV PATH="$PNPM_HOME:$PATH"
614
+ RUN corepack enable && corepack prepare pnpm@latest --activate
615
+
616
+ # Configure JSR registry
617
+ RUN pnpm config set @jsr:registry https://npm.jsr.io
618
+
619
+ # Build arguments
620
+ ARG TAG=latest
621
+ ARG PH_CONNECT_BASE_PATH="/"
622
+
623
+ # Install ph-cmd, prisma, and prettier globally
624
+ RUN pnpm add -g ph-cmd@$TAG prisma@5.17.0 prettier
625
+
626
+ # Initialize project based on tag (dev/staging/latest)
627
+ RUN case "$TAG" in \\
628
+ *dev*) ph init project --dev --package-manager pnpm ;; \\
629
+ *staging*) ph init project --staging --package-manager pnpm ;; \\
630
+ *) ph init project --package-manager pnpm ;; \\
631
+ esac
632
+
633
+ WORKDIR /app/project
634
+
635
+ # Copy package files for the current package
636
+ COPY package.json pnpm-lock.yaml ./
637
+
638
+ # Install the current package (this package)
639
+ ARG PACKAGE_NAME
640
+ RUN if [ -n "$PACKAGE_NAME" ]; then \\
641
+ echo "Installing package: $PACKAGE_NAME"; \\
642
+ ph install "$PACKAGE_NAME"; \\
643
+ else \\
644
+ echo "Warning: PACKAGE_NAME not provided, using local build"; \\
645
+ pnpm install; \\
646
+ fi
647
+
648
+ # Regenerate Prisma client for Alpine Linux
649
+ RUN prisma generate --schema node_modules/document-drive/dist/prisma/schema.prisma || true
650
+
651
+ # -----------------------------------------------------------------------------
652
+ # Connect build stage
653
+ # -----------------------------------------------------------------------------
654
+ FROM base AS connect-builder
655
+
656
+ ARG PH_CONNECT_BASE_PATH="/"
657
+
658
+ # Build connect
659
+ RUN ph connect build --base \${PH_CONNECT_BASE_PATH}
660
+
661
+ # -----------------------------------------------------------------------------
662
+ # Connect final stage - nginx
663
+ # -----------------------------------------------------------------------------
664
+ FROM nginx:alpine AS connect
665
+
666
+ # Install envsubst for config templating
667
+ RUN apk add --no-cache gettext
668
+
669
+ # Copy nginx config template
670
+ COPY docker/nginx.conf /etc/nginx/nginx.conf.template
671
+
672
+ # Copy built static files from build stage
673
+ COPY --from=connect-builder /app/project/.ph/connect-build/dist /var/www/html/project
674
+
675
+ # Environment variables for nginx config
676
+ ENV PORT=3001
677
+ ENV PH_CONNECT_BASE_PATH="/"
678
+
679
+ # Copy and setup entrypoint
680
+ COPY docker/connect-entrypoint.sh /docker-entrypoint.sh
681
+ RUN chmod +x /docker-entrypoint.sh
682
+
683
+ EXPOSE \${PORT}
684
+
685
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \\
686
+ CMD wget -q --spider http://localhost:\${PORT}/health || exit 1
687
+
688
+ ENTRYPOINT ["/docker-entrypoint.sh"]
689
+
690
+ # -----------------------------------------------------------------------------
691
+ # Switchboard final stage - node runtime
692
+ # -----------------------------------------------------------------------------
693
+ FROM node:24-alpine AS switchboard
694
+
695
+ WORKDIR /app
696
+
697
+ # Install runtime dependencies
698
+ RUN apk add --no-cache curl openssl
699
+
700
+ # Setup pnpm
701
+ ENV PNPM_HOME="/pnpm"
702
+ ENV PATH="$PNPM_HOME:$PATH"
703
+ RUN corepack enable && corepack prepare pnpm@latest --activate
704
+
705
+ # Configure JSR registry
706
+ RUN pnpm config set @jsr:registry https://npm.jsr.io
707
+
708
+ # Install ph-cmd and prisma globally (needed at runtime)
709
+ ARG TAG=latest
710
+ RUN pnpm add -g ph-cmd@$TAG prisma@5.17.0
711
+
712
+ # Copy built project from build stage
713
+ COPY --from=base /app/project /app/project
714
+
715
+ WORKDIR /app/project
716
+
717
+ # Copy entrypoint
718
+ COPY docker/switchboard-entrypoint.sh /app/entrypoint.sh
719
+ RUN chmod +x /app/entrypoint.sh
720
+
721
+ # Environment variables
722
+ ENV NODE_ENV=production
723
+ ENV PORT=3000
724
+ ENV DATABASE_URL=""
725
+ ENV SKIP_DB_MIGRATIONS="false"
726
+
727
+ EXPOSE \${PORT}
728
+
729
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=30s --retries=3 \\
730
+ CMD curl -f http://localhost:\${PORT}/health || exit 1
731
+
732
+ ENTRYPOINT ["/app/entrypoint.sh"]
733
+ `;
734
+ //#endregion
735
+ //#region src/templates/boilerplate/docker/nginx.conf.ts
736
+ const nginxConfTemplate = `user nginx;
737
+ worker_processes auto;
738
+ error_log /var/log/nginx/error.log warn;
739
+ pid /var/run/nginx.pid;
740
+
741
+ events {
742
+ worker_connections 1024;
743
+ }
744
+
745
+ http {
746
+ include /etc/nginx/mime.types;
747
+ default_type application/octet-stream;
748
+
749
+ # Gzip compression
750
+ gzip on;
751
+ gzip_vary on;
752
+ gzip_proxied any;
753
+ gzip_comp_level 6;
754
+ gzip_buffers 16 8k;
755
+ gzip_http_version 1.1;
756
+ gzip_types text/plain text/css application/javascript application/json image/svg+xml application/xml+rss image/avif;
757
+
758
+ server {
759
+ listen 0.0.0.0:\${PORT};
760
+ server_name _;
761
+ root /var/www/html/project;
762
+
763
+ # Health check endpoint
764
+ location /health {
765
+ access_log off;
766
+ add_header Content-Type text/plain;
767
+ return 200 'OK';
768
+ }
769
+
770
+ location \${PH_CONNECT_BASE_PATH}/assets/ {
771
+ alias /var/www/html/project/assets/;
772
+ access_log off;
773
+ log_not_found off;
774
+ etag off;
775
+ expires max;
776
+ add_header Cache-Control "public, max-age=31536000, immutable";
777
+ }
778
+
779
+ location \${PH_CONNECT_BASE_PATH}/fonts/ {
780
+ alias /var/www/html/project/fonts/;
781
+ access_log off;
782
+ log_not_found off;
783
+ expires max;
784
+ add_header Cache-Control "public, max-age=31536000, immutable";
785
+ }
786
+
787
+ location = \${PH_CONNECT_BASE_PATH}/service-worker.js {
788
+ alias /var/www/html/project/service-worker.js;
789
+
790
+ access_log off;
791
+ log_not_found off;
792
+ etag off;
793
+
794
+ add_header Cache-Control "no-cache, no-store, must-revalidate";
795
+ add_header Pragma "no-cache";
796
+ add_header Expires "0";
797
+ }
798
+
799
+ # match any file in the root folder, except index.html
800
+ location ~ \${PH_CONNECT_BASE_PATH}/(?!index\\.html$)([^/]+\\.[a-zA-Z0-9]+)$ {
801
+ alias /var/www/html/project/$1;
802
+ access_log off;
803
+ log_not_found off;
804
+ etag on;
805
+ add_header Cache-Control "public, must-revalidate";
806
+ }
807
+
808
+ location \${PH_CONNECT_BASE_PATH} {
809
+ try_files $uri $uri/ /index.html;
810
+ }
811
+ }
812
+ }
813
+ `;
814
+ //#endregion
815
+ //#region src/templates/boilerplate/docker/switchboard-entrypoint.sh.ts
816
+ const switchboardEntrypointTemplate = `#!/bin/sh
817
+ set -e
818
+
819
+ # Regenerate Prisma client for current platform (fixes darwin-arm64 vs linux-musl-openssl mismatch)
820
+ echo "[entrypoint] Regenerating Prisma client for current platform..."
821
+ prisma generate --schema node_modules/document-drive/dist/prisma/schema.prisma
822
+
823
+ # Run migrations if DATABASE_URL is postgres and migrations not skipped
824
+ if [ -n "$DATABASE_URL" ] && echo "$DATABASE_URL" | grep -q "^postgres" && [ "$SKIP_DB_MIGRATIONS" != "true" ]; then
825
+ echo "[entrypoint] Running Prisma db push..."
826
+ prisma db push --schema node_modules/document-drive/dist/prisma/schema.prisma --skip-generate
827
+ echo "[entrypoint] Running migrations..."
828
+ ph switchboard --migrate
829
+ fi
830
+
831
+ echo "[entrypoint] Starting switchboard on port \${PORT:-3000}..."
832
+ exec ph switchboard --port \${PORT:-3000}
833
+ `;
834
+ //#endregion
835
+ //#region src/templates/boilerplate/document-models/document-models.ts
836
+ const documentModelsTemplate = ts`
837
+ import type { DocumentModelModule } from "document-model";
838
+
839
+ export const documentModels: DocumentModelModule[] = [];
840
+ `.raw;
841
+ //#endregion
842
+ //#region src/templates/boilerplate/document-models/index.ts
843
+ const documentModelsIndexTemplate = "";
844
+ //#endregion
845
+ //#region src/templates/boilerplate/editors/editors.ts
846
+ const editorsTemplate = ts`
847
+ import type { EditorModule } from "document-model";
848
+
849
+ export const editors: EditorModule[] = [];
850
+ `.raw;
851
+ //#endregion
852
+ //#region src/templates/boilerplate/editors/index.ts
853
+ const editorsIndexTemplate = "";
854
+ //#endregion
855
+ //#region src/templates/boilerplate/eslint.config.js.ts
856
+ const eslintConfigTemplate = js`
857
+ // @ts-check
858
+ import { default as eslint } from "@eslint/js";
859
+ import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
860
+ import reactPlugin from "eslint-plugin-react";
861
+ import reactHooksPlugin from "eslint-plugin-react-hooks";
862
+ import { defineConfig, globalIgnores } from "eslint/config";
863
+ import globals from "globals";
864
+ import tseslint from "typescript-eslint";
865
+
866
+ /** These files are typically ignored by eslint by default, so there is no need to investigate why they are ignored. */
867
+ const ignoredFiles = [
868
+ "**/node_modules/",
869
+ "**/dist/",
870
+ "**/.ph/",
871
+ "**/storybook-static/",
872
+ "**/.vite/",
873
+ ];
874
+
875
+ /** Global configs for eslint ignores */
876
+ const ignored = globalIgnores(ignoredFiles);
877
+
878
+ /** Typescript (\`.ts\`) files */
879
+ const typescriptFiles = ["**/*.ts"];
880
+
881
+ /** Typescript React (\`.tsx\`) files */
882
+ const typescriptReactFiles = ["**/*.tsx"];
883
+
884
+ /** Javascript (\`.js\`, \`.cjs\`, \`.mjs\`) files */
885
+ const javascriptFiles = ["**/*.js", "**/*.cjs", "**/*.mjs"];
886
+
887
+ /** Typescript rules that we have chosen to opt out of in general */
888
+ /** @type {import("eslint").Linter.RulesRecord} */
889
+ const typescriptRules = {
890
+ "@typescript-eslint/consistent-type-imports": [
891
+ "error",
892
+ {
893
+ prefer: "type-imports",
894
+ disallowTypeAnnotations: true,
895
+ fixStyle: "separate-type-imports",
896
+ },
897
+ ],
898
+ "@typescript-eslint/no-explicit-any": "off",
899
+ "@typescript-eslint/no-unused-vars": [
900
+ "warn",
901
+ {
902
+ argsIgnorePattern: "^_",
903
+ varsIgnorePattern: "^_",
904
+ caughtErrorsIgnorePattern: "^_",
905
+ },
906
+ ],
907
+ "@typescript-eslint/no-unnecessary-condition": "warn",
908
+ "@typescript-eslint/require-await": "warn",
909
+ "@typescript-eslint/no-misused-promises": "warn",
910
+ "@typescript-eslint/no-floating-promises": "warn",
911
+ "@typescript-eslint/no-empty-object-type": "warn",
912
+ "@typescript-eslint/no-duplicate-type-constituents": "warn",
913
+ "@typescript-eslint/restrict-template-expressions": [
914
+ "warn",
915
+ {
916
+ allowNumber: true,
917
+ },
918
+ ],
919
+ };
920
+
921
+ /** Language options for typescript files
922
+ @type {import("eslint").Linter.LanguageOptions} */
923
+ const typescriptLanguageOptions = {
924
+ sourceType: "module",
925
+ ecmaVersion: "latest",
926
+ globals: {
927
+ ...globals.browser,
928
+ ...globals.node,
929
+ },
930
+ parserOptions: {
931
+ projectService: {
932
+ allowDefaultProject: ["eslint.config.js", "vitest.config.ts"],
933
+ },
934
+ tsconfigRootDir: import.meta.dirname,
935
+ ecmaFeatures: {
936
+ jsx: true,
937
+ },
938
+ },
939
+ };
940
+
941
+ /** React plugins */
942
+ const reactPlugins = {
943
+ react: reactPlugin,
944
+ "react-hooks": reactHooksPlugin,
945
+ };
946
+
947
+ /** React settings */
948
+ const reactSettings = {
949
+ react: {
950
+ version: "detect",
951
+ },
952
+ };
953
+
954
+ /** Typescript config for both \`.ts\` and \`.tsx\` files */
955
+ const typescriptConfig = {
956
+ files: [...typescriptFiles, ...typescriptReactFiles],
957
+ languageOptions: typescriptLanguageOptions,
958
+ rules: typescriptRules,
959
+ };
960
+
961
+ /** React config for \`.tsx\` files */
962
+ const reactConfig = {
963
+ files: typescriptReactFiles,
964
+ settings: reactSettings,
965
+ plugins: reactPlugins,
966
+ };
967
+
968
+ /** Config for javascript files */
969
+ const javascriptConfig = {
970
+ // disable type aware linting for js files
971
+ files: javascriptFiles,
972
+ extends: [tseslint.configs.disableTypeChecked],
973
+ };
974
+
975
+ /** Recommended config from eslint */
976
+ const eslintRecommendedConfig = eslint.configs.recommended;
977
+
978
+ /** Recommended config from typescript-eslint */
979
+ const typescriptEsLintRecommendedConfig = [
980
+ ...tseslint.configs.recommendedTypeChecked,
981
+ ];
982
+
983
+ /** Main config */
984
+ export default defineConfig(
985
+ ignored,
986
+ eslintRecommendedConfig,
987
+ typescriptEsLintRecommendedConfig,
988
+ typescriptConfig,
989
+ reactConfig,
990
+ javascriptConfig,
991
+ eslintPluginPrettierRecommended,
992
+ );
993
+ `.raw;
994
+ //#endregion
995
+ //#region src/templates/boilerplate/gemini/settings.json.ts
996
+ const geminiSettingsTemplate = json`
997
+ {
998
+ "mcpServers": {
999
+ "reactor-mcp": {
1000
+ "type": "http",
1001
+ "url": "http://localhost:4001/mcp"
1002
+ }
1003
+ }
1004
+ }
1005
+ `.raw;
1006
+ //#endregion
1007
+ //#region src/templates/boilerplate/github/sync-and-publish.yml.ts
1008
+ const syncAndPublishWorkflowTemplate = yaml`
1009
+ name: Sync and Publish
1010
+
1011
+ on:
1012
+ # Triggered by powerhouse monorepo after release
1013
+ repository_dispatch:
1014
+ types: [powerhouse-release]
1015
+
1016
+ # Manual trigger
1017
+ workflow_dispatch:
1018
+ inputs:
1019
+ channel:
1020
+ description: 'Release channel'
1021
+ required: true
1022
+ type: choice
1023
+ options:
1024
+ - dev
1025
+ - staging
1026
+ - latest
1027
+ default: 'staging'
1028
+ version:
1029
+ description: 'Powerhouse version (e.g., 5.3.0-staging.6)'
1030
+ required: false
1031
+ type: string
1032
+ dry-run:
1033
+ description: 'Dry run (skip publishing)'
1034
+ required: false
1035
+ type: boolean
1036
+ default: false
1037
+ skip-docker:
1038
+ description: 'Skip Docker build and push'
1039
+ required: false
1040
+ type: boolean
1041
+ default: false
1042
+
1043
+ env:
1044
+ NODE_VERSION: '24'
1045
+ PNPM_VERSION: '10'
1046
+ DOCKER_REGISTRY: cr.vetra.io
1047
+ GHCR_REGISTRY: ghcr.io
1048
+
1049
+ jobs:
1050
+ # ==========================================================================
1051
+ # Determine release parameters
1052
+ # ==========================================================================
1053
+ prepare:
1054
+ name: Prepare Release
1055
+ runs-on: ubuntu-latest
1056
+ outputs:
1057
+ channel: \${{ steps.params.outputs.channel }}
1058
+ version: \${{ steps.params.outputs.version }}
1059
+ branch: \${{ steps.params.outputs.branch }}
1060
+ project_name: \${{ steps.params.outputs.project_name }}
1061
+ dry_run: \${{ steps.params.outputs.dry_run }}
1062
+ skip_docker: \${{ steps.params.outputs.skip_docker }}
1063
+ steps:
1064
+ - name: Determine parameters
1065
+ id: params
1066
+ run: |
1067
+ # Get channel from dispatch payload or input
1068
+ if [ "\${{ github.event_name }}" = "repository_dispatch" ]; then
1069
+ CHANNEL="\${{ github.event.client_payload.channel }}"
1070
+ VERSION="\${{ github.event.client_payload.version }}"
1071
+ DRY_RUN="false"
1072
+ SKIP_DOCKER="false"
1073
+ else
1074
+ CHANNEL="\${{ inputs.channel }}"
1075
+ VERSION="\${{ inputs.version }}"
1076
+ DRY_RUN="\${{ inputs.dry-run }}"
1077
+ SKIP_DOCKER="\${{ inputs.skip-docker }}"
1078
+ fi
1079
+
1080
+ # Default channel to staging if not set
1081
+ CHANNEL="\${CHANNEL:-staging}"
1082
+
1083
+ # Determine branch from channel
1084
+ case "\$CHANNEL" in
1085
+ dev) BRANCH="dev" ;;
1086
+ staging) BRANCH="staging" ;;
1087
+ latest|main) BRANCH="main" ;;
1088
+ *) BRANCH="staging" ;;
1089
+ esac
1090
+
1091
+ # Use DOCKER_PROJECT secret if set, otherwise extract from repository name
1092
+ if [ -n "\${{ secrets.DOCKER_PROJECT }}" ]; then
1093
+ PROJECT_NAME="\${{ secrets.DOCKER_PROJECT }}"
1094
+ else
1095
+ PROJECT_NAME="\${GITHUB_REPOSITORY#*/}"
1096
+ fi
1097
+
1098
+ echo "channel=\$CHANNEL" >> \$GITHUB_OUTPUT
1099
+ echo "version=\$VERSION" >> \$GITHUB_OUTPUT
1100
+ echo "branch=\$BRANCH" >> \$GITHUB_OUTPUT
1101
+ echo "project_name=\$PROJECT_NAME" >> \$GITHUB_OUTPUT
1102
+ echo "dry_run=\$DRY_RUN" >> \$GITHUB_OUTPUT
1103
+ echo "skip_docker=\$SKIP_DOCKER" >> \$GITHUB_OUTPUT
1104
+
1105
+ echo "Channel: \$CHANNEL"
1106
+ echo "Version: \$VERSION"
1107
+ echo "Branch: \$BRANCH"
1108
+ echo "Project: \$PROJECT_NAME"
1109
+ echo "Dry Run: \$DRY_RUN"
1110
+ echo "Skip Docker: \$SKIP_DOCKER"
1111
+
1112
+ # ==========================================================================
1113
+ # Update dependencies and publish to npm
1114
+ # ==========================================================================
1115
+ update-and-publish:
1116
+ name: Update & Publish NPM
1117
+ needs: prepare
1118
+ runs-on: ubuntu-latest
1119
+ permissions:
1120
+ contents: write
1121
+ id-token: write
1122
+ outputs:
1123
+ new_version: \${{ steps.version.outputs.new_version }}
1124
+ steps:
1125
+ - name: Checkout repository
1126
+ uses: actions/checkout@v4
1127
+ with:
1128
+ ref: \${{ needs.prepare.outputs.branch }}
1129
+ fetch-depth: 0
1130
+ token: \${{ secrets.GITHUB_TOKEN }}
1131
+
1132
+ - name: Install pnpm
1133
+ uses: pnpm/action-setup@v4
1134
+ with:
1135
+ version: \${{ env.PNPM_VERSION }}
1136
+
1137
+ - name: Install Node.js
1138
+ uses: actions/setup-node@v4
1139
+ with:
1140
+ node-version: \${{ env.NODE_VERSION }}
1141
+ cache: 'pnpm'
1142
+
1143
+ - name: Configure git
1144
+ run: |
1145
+ git config user.name "github-actions[bot]"
1146
+ git config user.email "github-actions[bot]@users.noreply.github.com"
1147
+
1148
+ - name: Install ph-cli
1149
+ run: |
1150
+ CHANNEL="\${{ needs.prepare.outputs.channel }}"
1151
+ case "\$CHANNEL" in
1152
+ dev) pnpm add -g @powerhousedao/ph-cli@dev ;;
1153
+ staging) pnpm add -g @powerhousedao/ph-cli@staging ;;
1154
+ *) pnpm add -g @powerhousedao/ph-cli@latest ;;
1155
+ esac
1156
+
1157
+ - name: Update Powerhouse dependencies
1158
+ run: ph update
1159
+
1160
+ - name: Install dependencies
1161
+ run: pnpm install
1162
+
1163
+ - name: Build package
1164
+ run: pnpm build
1165
+
1166
+ - name: Run tests
1167
+ run: pnpm test || true
1168
+ continue-on-error: true
1169
+
1170
+ - name: Bump version
1171
+ id: version
1172
+ run: |
1173
+ CHANNEL="\${{ needs.prepare.outputs.channel }}"
1174
+ CURRENT_VERSION=\$(node -p "require('./package.json').version")
1175
+
1176
+ # Determine new version
1177
+ if [ "\$CHANNEL" = "latest" ] || [ "\$CHANNEL" = "main" ]; then
1178
+ # For production, use patch bump
1179
+ npm version patch --no-git-tag-version
1180
+ else
1181
+ # For dev/staging, use prerelease
1182
+ npm version prerelease --preid=\$CHANNEL --no-git-tag-version
1183
+ fi
1184
+
1185
+ NEW_VERSION=\$(node -p "require('./package.json').version")
1186
+ echo "new_version=\$NEW_VERSION" >> \$GITHUB_OUTPUT
1187
+ echo "Bumped version: \$CURRENT_VERSION -> \$NEW_VERSION"
1188
+
1189
+ - name: Commit changes
1190
+ run: |
1191
+ git add package.json pnpm-lock.yaml
1192
+ git commit -m "chore: sync powerhouse dependencies to \${{ needs.prepare.outputs.version }}
1193
+
1194
+ - Updated to powerhouse \${{ needs.prepare.outputs.version }}
1195
+ - Bumped version to \${{ steps.version.outputs.new_version }}" || echo "No changes to commit"
1196
+
1197
+ - name: Push changes
1198
+ if: needs.prepare.outputs.dry_run != 'true'
1199
+ run: git push
1200
+
1201
+ - name: Setup npm for publishing
1202
+ if: needs.prepare.outputs.dry_run != 'true' && secrets.NPM_ACCESS_TOKEN != ''
1203
+ uses: actions/setup-node@v4
1204
+ with:
1205
+ node-version: \${{ env.NODE_VERSION }}
1206
+ registry-url: 'https://registry.npmjs.org'
1207
+
1208
+ - name: Publish to npm with provenance
1209
+ if: needs.prepare.outputs.dry_run != 'true' && secrets.NPM_ACCESS_TOKEN != ''
1210
+ env:
1211
+ NODE_AUTH_TOKEN: \${{ secrets.NPM_ACCESS_TOKEN }}
1212
+ NPM_CONFIG_PROVENANCE: true
1213
+ run: |
1214
+ CHANNEL="\${{ needs.prepare.outputs.channel }}"
1215
+ if [ "\$CHANNEL" = "latest" ] || [ "\$CHANNEL" = "main" ]; then
1216
+ pnpm publish --access public --tag latest --no-git-checks
1217
+ else
1218
+ pnpm publish --access public --tag \$CHANNEL --no-git-checks
1219
+ fi
1220
+
1221
+ - name: Create git tag
1222
+ if: needs.prepare.outputs.dry_run != 'true'
1223
+ run: |
1224
+ git tag "v\${{ steps.version.outputs.new_version }}"
1225
+ git push origin "v\${{ steps.version.outputs.new_version }}"
1226
+
1227
+ # ==========================================================================
1228
+ # Build and push Docker images
1229
+ # ==========================================================================
1230
+ build-docker:
1231
+ name: Build Docker Images
1232
+ needs: [prepare, update-and-publish]
1233
+ if: |
1234
+ needs.prepare.outputs.skip_docker != 'true' &&
1235
+ needs.prepare.outputs.dry_run != 'true' &&
1236
+ secrets.DOCKER_USERNAME != '' &&
1237
+ secrets.DOCKER_PASSWORD != ''
1238
+ runs-on: ubuntu-latest
1239
+ permissions:
1240
+ contents: read
1241
+ packages: write
1242
+ strategy:
1243
+ matrix:
1244
+ target: [connect, switchboard]
1245
+ steps:
1246
+ - name: Checkout repository
1247
+ uses: actions/checkout@v4
1248
+ with:
1249
+ ref: \${{ needs.prepare.outputs.branch }}
1250
+
1251
+ - name: Pull latest changes
1252
+ run: git pull origin \${{ needs.prepare.outputs.branch }}
1253
+
1254
+ - name: Set up Docker Buildx
1255
+ uses: docker/setup-buildx-action@v3
1256
+
1257
+ - name: Ensure Docker project exists
1258
+ run: |
1259
+ PROJECT_NAME="\${{ needs.prepare.outputs.project_name }}"
1260
+
1261
+ # Check if project exists, create if not
1262
+ STATUS=\$(curl -s -o /dev/null -w "%{http_code}" \\
1263
+ -u "\${{ secrets.DOCKER_USERNAME }}:\${{ secrets.DOCKER_PASSWORD }}" \\
1264
+ "https://\${{ env.DOCKER_REGISTRY }}/api/v2.0/projects?name=\${PROJECT_NAME}")
1265
+
1266
+ if [ "\$STATUS" = "200" ]; then
1267
+ # Check if the project is in the response
1268
+ EXISTS=\$(curl -s \\
1269
+ -u "\${{ secrets.DOCKER_USERNAME }}:\${{ secrets.DOCKER_PASSWORD }}" \\
1270
+ "https://\${{ env.DOCKER_REGISTRY }}/api/v2.0/projects?name=\${PROJECT_NAME}" | \\
1271
+ jq -r ".[] | select(.name==\\"\${PROJECT_NAME}\\") | .name")
1272
+
1273
+ if [ "\$EXISTS" = "\$PROJECT_NAME" ]; then
1274
+ echo "Project \${PROJECT_NAME} already exists"
1275
+ else
1276
+ echo "Creating project \${PROJECT_NAME}..."
1277
+ curl -X POST \\
1278
+ -u "\${{ secrets.DOCKER_USERNAME }}:\${{ secrets.DOCKER_PASSWORD }}" \\
1279
+ -H "Content-Type: application/json" \\
1280
+ -d "{\\"project_name\\": \\"\${PROJECT_NAME}\\", \\"public\\": false}" \\
1281
+ "https://\${{ env.DOCKER_REGISTRY }}/api/v2.0/projects"
1282
+ fi
1283
+ else
1284
+ echo "Creating project \${PROJECT_NAME}..."
1285
+ curl -X POST \\
1286
+ -u "\${{ secrets.DOCKER_USERNAME }}:\${{ secrets.DOCKER_PASSWORD }}" \\
1287
+ -H "Content-Type: application/json" \\
1288
+ -d "{\\"project_name\\": \\"\${PROJECT_NAME}\\", \\"public\\": false}" \\
1289
+ "https://\${{ env.DOCKER_REGISTRY }}/api/v2.0/projects"
1290
+ fi
1291
+
1292
+ - name: Login to GitHub Container Registry
1293
+ uses: docker/login-action@v3
1294
+ with:
1295
+ registry: \${{ env.GHCR_REGISTRY }}
1296
+ username: \${{ github.actor }}
1297
+ password: \${{ secrets.GITHUB_TOKEN }}
1298
+
1299
+ - name: Login to Docker Registry
1300
+ uses: docker/login-action@v3
1301
+ with:
1302
+ registry: \${{ env.DOCKER_REGISTRY }}
1303
+ username: \${{ secrets.DOCKER_USERNAME }}
1304
+ password: \${{ secrets.DOCKER_PASSWORD }}
1305
+
1306
+ - name: Extract package name
1307
+ id: package
1308
+ run: |
1309
+ PACKAGE_NAME=\$(node -p "require('./package.json').name")
1310
+ echo "name=\$PACKAGE_NAME" >> \$GITHUB_OUTPUT
1311
+
1312
+ - name: Determine image tags
1313
+ id: tags
1314
+ run: |
1315
+ VERSION="\${{ needs.update-and-publish.outputs.new_version }}"
1316
+ CHANNEL="\${{ needs.prepare.outputs.channel }}"
1317
+ PROJECT="\${{ needs.prepare.outputs.project_name }}"
1318
+ TARGET="\${{ matrix.target }}"
1319
+
1320
+ # GHCR tags
1321
+ GHCR_BASE="\${{ env.GHCR_REGISTRY }}/\${{ github.repository_owner }}/\${PROJECT}/\${TARGET}"
1322
+
1323
+ # Docker registry tags
1324
+ DOCKER_BASE="\${{ env.DOCKER_REGISTRY }}/\${PROJECT}/\${TARGET}"
1325
+
1326
+ # Build tag list
1327
+ TAGS="\${GHCR_BASE}:v\${VERSION}"
1328
+ TAGS="\${TAGS},\${DOCKER_BASE}:v\${VERSION}"
1329
+
1330
+ # Add channel tag
1331
+ if [ "\$CHANNEL" = "latest" ] || [ "\$CHANNEL" = "main" ]; then
1332
+ TAGS="\${TAGS},\${GHCR_BASE}:latest"
1333
+ TAGS="\${TAGS},\${DOCKER_BASE}:latest"
1334
+ else
1335
+ TAGS="\${TAGS},\${GHCR_BASE}:\${CHANNEL}"
1336
+ TAGS="\${TAGS},\${DOCKER_BASE}:\${CHANNEL}"
1337
+ fi
1338
+
1339
+ echo "tags=\$TAGS" >> \$GITHUB_OUTPUT
1340
+ echo "Image tags: \$TAGS"
1341
+
1342
+ - name: Build and push \${{ matrix.target }}
1343
+ uses: docker/build-push-action@v5
1344
+ with:
1345
+ context: .
1346
+ file: ./Dockerfile
1347
+ target: \${{ matrix.target }}
1348
+ push: true
1349
+ tags: \${{ steps.tags.outputs.tags }}
1350
+ build-args: |
1351
+ TAG=\${{ needs.prepare.outputs.channel == 'latest' && 'latest' || needs.prepare.outputs.version }}
1352
+ PACKAGE_NAME=\${{ steps.package.outputs.name }}
1353
+ PH_CONNECT_BASE_PATH=/
1354
+ cache-from: type=gha
1355
+ cache-to: type=gha,mode=max
1356
+
1357
+ # ==========================================================================
1358
+ # Summary
1359
+ # ==========================================================================
1360
+ summary:
1361
+ name: Release Summary
1362
+ needs: [prepare, update-and-publish, build-docker]
1363
+ if: always()
1364
+ runs-on: ubuntu-latest
1365
+ steps:
1366
+ - name: Summary
1367
+ run: |
1368
+ echo "## Release Summary" >> \$GITHUB_STEP_SUMMARY
1369
+ echo "" >> \$GITHUB_STEP_SUMMARY
1370
+ echo "| Parameter | Value |" >> \$GITHUB_STEP_SUMMARY
1371
+ echo "|-----------|-------|" >> \$GITHUB_STEP_SUMMARY
1372
+ echo "| Channel | \${{ needs.prepare.outputs.channel }} |" >> \$GITHUB_STEP_SUMMARY
1373
+ echo "| Branch | \${{ needs.prepare.outputs.branch }} |" >> \$GITHUB_STEP_SUMMARY
1374
+ echo "| Powerhouse Version | \${{ needs.prepare.outputs.version }} |" >> \$GITHUB_STEP_SUMMARY
1375
+ echo "| Package Version | \${{ needs.update-and-publish.outputs.new_version }} |" >> \$GITHUB_STEP_SUMMARY
1376
+ echo "| Dry Run | \${{ needs.prepare.outputs.dry_run }} |" >> \$GITHUB_STEP_SUMMARY
1377
+ echo "" >> \$GITHUB_STEP_SUMMARY
1378
+ echo "### Docker Images" >> \$GITHUB_STEP_SUMMARY
1379
+ echo "- \\\`\${{ env.DOCKER_REGISTRY }}/\${{ needs.prepare.outputs.project_name }}/connect:v\${{ needs.update-and-publish.outputs.new_version }}\\\`" >> \$GITHUB_STEP_SUMMARY
1380
+ echo "- \\\`\${{ env.DOCKER_REGISTRY }}/\${{ needs.prepare.outputs.project_name }}/switchboard:v\${{ needs.update-and-publish.outputs.new_version }}\\\`" >> \$GITHUB_STEP_SUMMARY
1381
+ `.raw;
1382
+ //#endregion
1383
+ //#region src/templates/boilerplate/gitignore.ts
1384
+ const gitIgnoreTemplate = `
1385
+ dist
1386
+ coverage
1387
+ node_modules
1388
+ .eslintcache
1389
+ .env.local
1390
+
1391
+ .ph
1392
+ projects-import.js
1393
+ `;
1394
+ //#endregion
1395
+ //#region \0@oxc-project+runtime@0.115.0/helpers/taggedTemplateLiteral.js
1396
+ function _taggedTemplateLiteral(e, t) {
1397
+ return t || (t = e.slice(0)), Object.freeze(Object.defineProperties(e, { raw: { value: Object.freeze(t) } }));
1398
+ }
1399
+ //#endregion
1400
+ //#region src/templates/boilerplate/index.html.ts
1401
+ var _templateObject$1;
1402
+ const indexHtmlTemplate = html(_templateObject$1 || (_templateObject$1 = _taggedTemplateLiteral(["<!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta\n name=\"description\"\n content=\"Connect is a hub for your most important documents and processes, translated into software. Easily capture data in a structured way with dedicated business process packages. Collaborate on shared documents with ease while using your preferred storage solution (decentralized, centralized, or local).\"\n />\n <title>Powerhouse Connect</title>\n <link rel=\"icon\" href=\"/icon.ico\" />\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link\n href=\"https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap\"\n rel=\"stylesheet\"\n />\n </head>\n <body>\n <div id=\"root\"></div>\n <link href=\"/style.css\" rel=\"stylesheet\" />\n <script type=\"module\" src=\"/main.tsx\"><\/script>\n </body>\n </html> "]))).raw;
1403
+ //#endregion
1404
+ //#region src/templates/boilerplate/index.html.legacy.ts
1405
+ var _templateObject;
1406
+ const legacyIndexHtmlTemplate = html(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta\n name=\"description\"\n content=\"Connect is a hub for your most important documents and processes, translated into software. Easily capture data in a structured way with dedicated business process packages. Collaborate on shared documents with ease while using your preferred storage solution (decentralized, centralized, or local).\"\n />\n <title>Powerhouse Connect</title>\n <link rel=\"icon\" href=\"/icon.ico\" />\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link\n href=\"https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap\"\n rel=\"stylesheet\"\n />\n <style>\n @import \"tailwindcss\";\n @import \"@powerhousedao/design-system/style.css\";\n @import \"@powerhousedao/document-engineering/style.css\";\n @source \"./node_modules/@powerhousedao/connect\";\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n // initializes Connect on '<div id=\"root\"></div>'\n import \"@powerhousedao/connect/main.js\";\n <\/script>\n </body>\n </html>\n"]))).raw;
1407
+ //#endregion
1408
+ //#region src/templates/boilerplate/main.tsx.ts
1409
+ const mainTsxTemplate = tsx`
1410
+ import { startConnect } from "@powerhousedao/connect";
1411
+ import * as localPackage from "./index.js";
1412
+
1413
+ startConnect(localPackage);
1414
+ `.raw;
1415
+ //#endregion
1416
+ //#region src/templates/boilerplate/index.ts
1417
+ const indexTsTemplate = ts`
1418
+ import type { Manifest } from "document-model";
1419
+ import manifestJson from "./powerhouse.manifest.json" with { type: "json" };
1420
+ export { documentModels } from "./document-models/document-models.js";
1421
+ export { upgradeManifests } from "./document-models/upgrade-manifests.js";
1422
+ export { editors } from "./editors/editors.js";
1423
+ export { processorFactory } from "./processors/factory.js";
1424
+ export const manifest: Manifest = manifestJson;
1425
+ `.raw;
1426
+ //#endregion
1427
+ //#region src/templates/boilerplate/LICENSE.ts
1428
+ const licenseTemplate = `
1429
+ GNU AFFERO GENERAL PUBLIC LICENSE
1430
+ Version 3, 19 November 2007
1431
+
1432
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
1433
+ Everyone is permitted to copy and distribute verbatim copies
1434
+ of this license document, but changing it is not allowed.
1435
+
1436
+ Preamble
1437
+
1438
+ The GNU Affero General Public License is a free, copyleft license for
1439
+ software and other kinds of works, specifically designed to ensure
1440
+ cooperation with the community in the case of network server software.
1441
+
1442
+ The licenses for most software and other practical works are designed
1443
+ to take away your freedom to share and change the works. By contrast,
1444
+ our General Public Licenses are intended to guarantee your freedom to
1445
+ share and change all versions of a program--to make sure it remains free
1446
+ software for all its users.
1447
+
1448
+ When we speak of free software, we are referring to freedom, not
1449
+ price. Our General Public Licenses are designed to make sure that you
1450
+ have the freedom to distribute copies of free software (and charge for
1451
+ them if you wish), that you receive source code or can get it if you
1452
+ want it, that you can change the software or use pieces of it in new
1453
+ free programs, and that you know you can do these things.
1454
+
1455
+ Developers that use our General Public Licenses protect your rights
1456
+ with two steps: (1) assert copyright on the software, and (2) offer
1457
+ you this License which gives you legal permission to copy, distribute
1458
+ and/or modify the software.
1459
+
1460
+ A secondary benefit of defending all users' freedom is that
1461
+ improvements made in alternate versions of the program, if they
1462
+ receive widespread use, become available for other developers to
1463
+ incorporate. Many developers of free software are heartened and
1464
+ encouraged by the resulting cooperation. However, in the case of
1465
+ software used on network servers, this result may fail to come about.
1466
+ The GNU General Public License permits making a modified version and
1467
+ letting the public access it on a server without ever releasing its
1468
+ source code to the public.
1469
+
1470
+ The GNU Affero General Public License is designed specifically to
1471
+ ensure that, in such cases, the modified source code becomes available
1472
+ to the community. It requires the operator of a network server to
1473
+ provide the source code of the modified version running there to the
1474
+ users of that server. Therefore, public use of a modified version, on
1475
+ a publicly accessible server, gives the public access to the source
1476
+ code of the modified version.
1477
+
1478
+ An older license, called the Affero General Public License and
1479
+ published by Affero, was designed to accomplish similar goals. This is
1480
+ a different license, not a version of the Affero GPL, but Affero has
1481
+ released a new version of the Affero GPL which permits relicensing under
1482
+ this license.
1483
+
1484
+ The precise terms and conditions for copying, distribution and
1485
+ modification follow.
1486
+
1487
+ TERMS AND CONDITIONS
1488
+
1489
+ 0. Definitions.
1490
+
1491
+ "This License" refers to version 3 of the GNU Affero General Public License.
1492
+
1493
+ "Copyright" also means copyright-like laws that apply to other kinds of
1494
+ works, such as semiconductor masks.
1495
+
1496
+ "The Program" refers to any copyrightable work licensed under this
1497
+ License. Each licensee is addressed as "you". "Licensees" and
1498
+ "recipients" may be individuals or organizations.
1499
+
1500
+ To "modify" a work means to copy from or adapt all or part of the work
1501
+ in a fashion requiring copyright permission, other than the making of an
1502
+ exact copy. The resulting work is called a "modified version" of the
1503
+ earlier work or a work "based on" the earlier work.
1504
+
1505
+ A "covered work" means either the unmodified Program or a work based
1506
+ on the Program.
1507
+
1508
+ To "propagate" a work means to do anything with it that, without
1509
+ permission, would make you directly or secondarily liable for
1510
+ infringement under applicable copyright law, except executing it on a
1511
+ computer or modifying a private copy. Propagation includes copying,
1512
+ distribution (with or without modification), making available to the
1513
+ public, and in some countries other activities as well.
1514
+
1515
+ To "convey" a work means any kind of propagation that enables other
1516
+ parties to make or receive copies. Mere interaction with a user through
1517
+ a computer network, with no transfer of a copy, is not conveying.
1518
+
1519
+ An interactive user interface displays "Appropriate Legal Notices"
1520
+ to the extent that it includes a convenient and prominently visible
1521
+ feature that (1) displays an appropriate copyright notice, and (2)
1522
+ tells the user that there is no warranty for the work (except to the
1523
+ extent that warranties are provided), that licensees may convey the
1524
+ work under this License, and how to view a copy of this License. If
1525
+ the interface presents a list of user commands or options, such as a
1526
+ menu, a prominent item in the list meets this criterion.
1527
+
1528
+ 1. Source Code.
1529
+
1530
+ The "source code" for a work means the preferred form of the work
1531
+ for making modifications to it. "Object code" means any non-source
1532
+ form of a work.
1533
+
1534
+ A "Standard Interface" means an interface that either is an official
1535
+ standard defined by a recognized standards body, or, in the case of
1536
+ interfaces specified for a particular programming language, one that
1537
+ is widely used among developers working in that language.
1538
+
1539
+ The "System Libraries" of an executable work include anything, other
1540
+ than the work as a whole, that (a) is included in the normal form of
1541
+ packaging a Major Component, but which is not part of that Major
1542
+ Component, and (b) serves only to enable use of the work with that
1543
+ Major Component, or to implement a Standard Interface for which an
1544
+ implementation is available to the public in source code form. A
1545
+ "Major Component", in this context, means a major essential component
1546
+ (kernel, window system, and so on) of the specific operating system
1547
+ (if any) on which the executable work runs, or a compiler used to
1548
+ produce the work, or an object code interpreter used to run it.
1549
+
1550
+ The "Corresponding Source" for a work in object code form means all
1551
+ the source code needed to generate, install, and (for an executable
1552
+ work) run the object code and to modify the work, including scripts to
1553
+ control those activities. However, it does not include the work's
1554
+ System Libraries, or general-purpose tools or generally available free
1555
+ programs which are used unmodified in performing those activities but
1556
+ which are not part of the work. For example, Corresponding Source
1557
+ includes interface definition files associated with source files for
1558
+ the work, and the source code for shared libraries and dynamically
1559
+ linked subprograms that the work is specifically designed to require,
1560
+ such as by intimate data communication or control flow between those
1561
+ subprograms and other parts of the work.
1562
+
1563
+ The Corresponding Source need not include anything that users
1564
+ can regenerate automatically from other parts of the Corresponding
1565
+ Source.
1566
+
1567
+ The Corresponding Source for a work in source code form is that
1568
+ same work.
1569
+
1570
+ 2. Basic Permissions.
1571
+
1572
+ All rights granted under this License are granted for the term of
1573
+ copyright on the Program, and are irrevocable provided the stated
1574
+ conditions are met. This License explicitly affirms your unlimited
1575
+ permission to run the unmodified Program. The output from running a
1576
+ covered work is covered by this License only if the output, given its
1577
+ content, constitutes a covered work. This License acknowledges your
1578
+ rights of fair use or other equivalent, as provided by copyright law.
1579
+
1580
+ You may make, run and propagate covered works that you do not
1581
+ convey, without conditions so long as your license otherwise remains
1582
+ in force. You may convey covered works to others for the sole purpose
1583
+ of having them make modifications exclusively for you, or provide you
1584
+ with facilities for running those works, provided that you comply with
1585
+ the terms of this License in conveying all material for which you do
1586
+ not control copyright. Those thus making or running the covered works
1587
+ for you must do so exclusively on your behalf, under your direction
1588
+ and control, on terms that prohibit them from making any copies of
1589
+ your copyrighted material outside their relationship with you.
1590
+
1591
+ Conveying under any other circumstances is permitted solely under
1592
+ the conditions stated below. Sublicensing is not allowed; section 10
1593
+ makes it unnecessary.
1594
+
1595
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
1596
+
1597
+ No covered work shall be deemed part of an effective technological
1598
+ measure under any applicable law fulfilling obligations under article
1599
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
1600
+ similar laws prohibiting or restricting circumvention of such
1601
+ measures.
1602
+
1603
+ When you convey a covered work, you waive any legal power to forbid
1604
+ circumvention of technological measures to the extent such circumvention
1605
+ is effected by exercising rights under this License with respect to
1606
+ the covered work, and you disclaim any intention to limit operation or
1607
+ modification of the work as a means of enforcing, against the work's
1608
+ users, your or third parties' legal rights to forbid circumvention of
1609
+ technological measures.
1610
+
1611
+ 4. Conveying Verbatim Copies.
1612
+
1613
+ You may convey verbatim copies of the Program's source code as you
1614
+ receive it, in any medium, provided that you conspicuously and
1615
+ appropriately publish on each copy an appropriate copyright notice;
1616
+ keep intact all notices stating that this License and any
1617
+ non-permissive terms added in accord with section 7 apply to the code;
1618
+ keep intact all notices of the absence of any warranty; and give all
1619
+ recipients a copy of this License along with the Program.
1620
+
1621
+ You may charge any price or no price for each copy that you convey,
1622
+ and you may offer support or warranty protection for a fee.
1623
+
1624
+ 5. Conveying Modified Source Versions.
1625
+
1626
+ You may convey a work based on the Program, or the modifications to
1627
+ produce it from the Program, in the form of source code under the
1628
+ terms of section 4, provided that you also meet all of these conditions:
1629
+
1630
+ a) The work must carry prominent notices stating that you modified
1631
+ it, and giving a relevant date.
1632
+
1633
+ b) The work must carry prominent notices stating that it is
1634
+ released under this License and any conditions added under section
1635
+ 7. This requirement modifies the requirement in section 4 to
1636
+ "keep intact all notices".
1637
+
1638
+ c) You must license the entire work, as a whole, under this
1639
+ License to anyone who comes into possession of a copy. This
1640
+ License will therefore apply, along with any applicable section 7
1641
+ additional terms, to the whole of the work, and all its parts,
1642
+ regardless of how they are packaged. This License gives no
1643
+ permission to license the work in any other way, but it does not
1644
+ invalidate such permission if you have separately received it.
1645
+
1646
+ d) If the work has interactive user interfaces, each must display
1647
+ Appropriate Legal Notices; however, if the Program has interactive
1648
+ interfaces that do not display Appropriate Legal Notices, your
1649
+ work need not make them do so.
1650
+
1651
+ A compilation of a covered work with other separate and independent
1652
+ works, which are not by their nature extensions of the covered work,
1653
+ and which are not combined with it such as to form a larger program,
1654
+ in or on a volume of a storage or distribution medium, is called an
1655
+ "aggregate" if the compilation and its resulting copyright are not
1656
+ used to limit the access or legal rights of the compilation's users
1657
+ beyond what the individual works permit. Inclusion of a covered work
1658
+ in an aggregate does not cause this License to apply to the other
1659
+ parts of the aggregate.
1660
+
1661
+ 6. Conveying Non-Source Forms.
1662
+
1663
+ You may convey a covered work in object code form under the terms
1664
+ of sections 4 and 5, provided that you also convey the
1665
+ machine-readable Corresponding Source under the terms of this License,
1666
+ in one of these ways:
1667
+
1668
+ a) Convey the object code in, or embodied in, a physical product
1669
+ (including a physical distribution medium), accompanied by the
1670
+ Corresponding Source fixed on a durable physical medium
1671
+ customarily used for software interchange.
1672
+
1673
+ b) Convey the object code in, or embodied in, a physical product
1674
+ (including a physical distribution medium), accompanied by a
1675
+ written offer, valid for at least three years and valid for as
1676
+ long as you offer spare parts or customer support for that product
1677
+ model, to give anyone who possesses the object code either (1) a
1678
+ copy of the Corresponding Source for all the software in the
1679
+ product that is covered by this License, on a durable physical
1680
+ medium customarily used for software interchange, for a price no
1681
+ more than your reasonable cost of physically performing this
1682
+ conveying of source, or (2) access to copy the
1683
+ Corresponding Source from a network server at no charge.
1684
+
1685
+ c) Convey individual copies of the object code with a copy of the
1686
+ written offer to provide the Corresponding Source. This
1687
+ alternative is allowed only occasionally and noncommercially, and
1688
+ only if you received the object code with such an offer, in accord
1689
+ with subsection 6b.
1690
+
1691
+ d) Convey the object code by offering access from a designated
1692
+ place (gratis or for a charge), and offer equivalent access to the
1693
+ Corresponding Source in the same way through the same place at no
1694
+ further charge. You need not require recipients to copy the
1695
+ Corresponding Source along with the object code. If the place to
1696
+ copy the object code is a network server, the Corresponding Source
1697
+ may be on a different server (operated by you or a third party)
1698
+ that supports equivalent copying facilities, provided you maintain
1699
+ clear directions next to the object code saying where to find the
1700
+ Corresponding Source. Regardless of what server hosts the
1701
+ Corresponding Source, you remain obligated to ensure that it is
1702
+ available for as long as needed to satisfy these requirements.
1703
+
1704
+ e) Convey the object code using peer-to-peer transmission, provided
1705
+ you inform other peers where the object code and Corresponding
1706
+ Source of the work are being offered to the general public at no
1707
+ charge under subsection 6d.
1708
+
1709
+ A separable portion of the object code, whose source code is excluded
1710
+ from the Corresponding Source as a System Library, need not be
1711
+ included in conveying the object code work.
1712
+
1713
+ A "User Product" is either (1) a "consumer product", which means any
1714
+ tangible personal property which is normally used for personal, family,
1715
+ or household purposes, or (2) anything designed or sold for incorporation
1716
+ into a dwelling. In determining whether a product is a consumer product,
1717
+ doubtful cases shall be resolved in favor of coverage. For a particular
1718
+ product received by a particular user, "normally used" refers to a
1719
+ typical or common use of that class of product, regardless of the status
1720
+ of the particular user or of the way in which the particular user
1721
+ actually uses, or expects or is expected to use, the product. A product
1722
+ is a consumer product regardless of whether the product has substantial
1723
+ commercial, industrial or non-consumer uses, unless such uses represent
1724
+ the only significant mode of use of the product.
1725
+
1726
+ "Installation Information" for a User Product means any methods,
1727
+ procedures, authorization keys, or other information required to install
1728
+ and execute modified versions of a covered work in that User Product from
1729
+ a modified version of its Corresponding Source. The information must
1730
+ suffice to ensure that the continued functioning of the modified object
1731
+ code is in no case prevented or interfered with solely because
1732
+ modification has been made.
1733
+
1734
+ If you convey an object code work under this section in, or with, or
1735
+ specifically for use in, a User Product, and the conveying occurs as
1736
+ part of a transaction in which the right of possession and use of the
1737
+ User Product is transferred to the recipient in perpetuity or for a
1738
+ fixed term (regardless of how the transaction is characterized), the
1739
+ Corresponding Source conveyed under this section must be accompanied
1740
+ by the Installation Information. But this requirement does not apply
1741
+ if neither you nor any third party retains the ability to install
1742
+ modified object code on the User Product (for example, the work has
1743
+ been installed in ROM).
1744
+
1745
+ The requirement to provide Installation Information does not include a
1746
+ requirement to continue to provide support service, warranty, or updates
1747
+ for a work that has been modified or installed by the recipient, or for
1748
+ the User Product in which it has been modified or installed. Access to a
1749
+ network may be denied when the modification itself materially and
1750
+ adversely affects the operation of the network or violates the rules and
1751
+ protocols for communication across the network.
1752
+
1753
+ Corresponding Source conveyed, and Installation Information provided,
1754
+ in accord with this section must be in a format that is publicly
1755
+ documented (and with an implementation available to the public in
1756
+ source code form), and must require no special password or key for
1757
+ unpacking, reading or copying.
1758
+
1759
+ 7. Additional Terms.
1760
+
1761
+ "Additional permissions" are terms that supplement the terms of this
1762
+ License by making exceptions from one or more of its conditions.
1763
+ Additional permissions that are applicable to the entire Program shall
1764
+ be treated as though they were included in this License, to the extent
1765
+ that they are valid under applicable law. If additional permissions
1766
+ apply only to part of the Program, that part may be used separately
1767
+ under those permissions, but the entire Program remains governed by
1768
+ this License without regard to the additional permissions.
1769
+
1770
+ When you convey a copy of a covered work, you may at your option
1771
+ remove any additional permissions from that copy, or from any part of
1772
+ it. (Additional permissions may be written to require their own
1773
+ removal in certain cases when you modify the work.) You may place
1774
+ additional permissions on material, added by you to a covered work,
1775
+ for which you have or can give appropriate copyright permission.
1776
+
1777
+ Notwithstanding any other provision of this License, for material you
1778
+ add to a covered work, you may (if authorized by the copyright holders of
1779
+ that material) supplement the terms of this License with terms:
1780
+
1781
+ a) Disclaiming warranty or limiting liability differently from the
1782
+ terms of sections 15 and 16 of this License; or
1783
+
1784
+ b) Requiring preservation of specified reasonable legal notices or
1785
+ author attributions in that material or in the Appropriate Legal
1786
+ Notices displayed by works containing it; or
1787
+
1788
+ c) Prohibiting misrepresentation of the origin of that material, or
1789
+ requiring that modified versions of such material be marked in
1790
+ reasonable ways as different from the original version; or
1791
+
1792
+ d) Limiting the use for publicity purposes of names of licensors or
1793
+ authors of the material; or
1794
+
1795
+ e) Declining to grant rights under trademark law for use of some
1796
+ trade names, trademarks, or service marks; or
1797
+
1798
+ f) Requiring indemnification of licensors and authors of that
1799
+ material by anyone who conveys the material (or modified versions of
1800
+ it) with contractual assumptions of liability to the recipient, for
1801
+ any liability that these contractual assumptions directly impose on
1802
+ those licensors and authors.
1803
+
1804
+ All other non-permissive additional terms are considered "further
1805
+ restrictions" within the meaning of section 10. If the Program as you
1806
+ received it, or any part of it, contains a notice stating that it is
1807
+ governed by this License along with a term that is a further
1808
+ restriction, you may remove that term. If a license document contains
1809
+ a further restriction but permits relicensing or conveying under this
1810
+ License, you may add to a covered work material governed by the terms
1811
+ of that license document, provided that the further restriction does
1812
+ not survive such relicensing or conveying.
1813
+
1814
+ If you add terms to a covered work in accord with this section, you
1815
+ must place, in the relevant source files, a statement of the
1816
+ additional terms that apply to those files, or a notice indicating
1817
+ where to find the applicable terms.
1818
+
1819
+ Additional terms, permissive or non-permissive, may be stated in the
1820
+ form of a separately written license, or stated as exceptions;
1821
+ the above requirements apply either way.
1822
+
1823
+ 8. Termination.
1824
+
1825
+ You may not propagate or modify a covered work except as expressly
1826
+ provided under this License. Any attempt otherwise to propagate or
1827
+ modify it is void, and will automatically terminate your rights under
1828
+ this License (including any patent licenses granted under the third
1829
+ paragraph of section 11).
1830
+
1831
+ However, if you cease all violation of this License, then your
1832
+ license from a particular copyright holder is reinstated (a)
1833
+ provisionally, unless and until the copyright holder explicitly and
1834
+ finally terminates your license, and (b) permanently, if the copyright
1835
+ holder fails to notify you of the violation by some reasonable means
1836
+ prior to 60 days after the cessation.
1837
+
1838
+ Moreover, your license from a particular copyright holder is
1839
+ reinstated permanently if the copyright holder notifies you of the
1840
+ violation by some reasonable means, this is the first time you have
1841
+ received notice of violation of this License (for any work) from that
1842
+ copyright holder, and you cure the violation prior to 30 days after
1843
+ your receipt of the notice.
1844
+
1845
+ Termination of your rights under this section does not terminate the
1846
+ licenses of parties who have received copies or rights from you under
1847
+ this License. If your rights have been terminated and not permanently
1848
+ reinstated, you do not qualify to receive new licenses for the same
1849
+ material under section 10.
1850
+
1851
+ 9. Acceptance Not Required for Having Copies.
1852
+
1853
+ You are not required to accept this License in order to receive or
1854
+ run a copy of the Program. Ancillary propagation of a covered work
1855
+ occurring solely as a consequence of using peer-to-peer transmission
1856
+ to receive a copy likewise does not require acceptance. However,
1857
+ nothing other than this License grants you permission to propagate or
1858
+ modify any covered work. These actions infringe copyright if you do
1859
+ not accept this License. Therefore, by modifying or propagating a
1860
+ covered work, you indicate your acceptance of this License to do so.
1861
+
1862
+ 10. Automatic Licensing of Downstream Recipients.
1863
+
1864
+ Each time you convey a covered work, the recipient automatically
1865
+ receives a license from the original licensors, to run, modify and
1866
+ propagate that work, subject to this License. You are not responsible
1867
+ for enforcing compliance by third parties with this License.
1868
+
1869
+ An "entity transaction" is a transaction transferring control of an
1870
+ organization, or substantially all assets of one, or subdividing an
1871
+ organization, or merging organizations. If propagation of a covered
1872
+ work results from an entity transaction, each party to that
1873
+ transaction who receives a copy of the work also receives whatever
1874
+ licenses to the work the party's predecessor in interest had or could
1875
+ give under the previous paragraph, plus a right to possession of the
1876
+ Corresponding Source of the work from the predecessor in interest, if
1877
+ the predecessor has it or can get it with reasonable efforts.
1878
+
1879
+ You may not impose any further restrictions on the exercise of the
1880
+ rights granted or affirmed under this License. For example, you may
1881
+ not impose a license fee, royalty, or other charge for exercise of
1882
+ rights granted under this License, and you may not initiate litigation
1883
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
1884
+ any patent claim is infringed by making, using, selling, offering for
1885
+ sale, or importing the Program or any portion of it.
1886
+
1887
+ 11. Patents.
1888
+
1889
+ A "contributor" is a copyright holder who authorizes use under this
1890
+ License of the Program or a work on which the Program is based. The
1891
+ work thus licensed is called the contributor's "contributor version".
1892
+
1893
+ A contributor's "essential patent claims" are all patent claims
1894
+ owned or controlled by the contributor, whether already acquired or
1895
+ hereafter acquired, that would be infringed by some manner, permitted
1896
+ by this License, of making, using, or selling its contributor version,
1897
+ but do not include claims that would be infringed only as a
1898
+ consequence of further modification of the contributor version. For
1899
+ purposes of this definition, "control" includes the right to grant
1900
+ patent sublicenses in a manner consistent with the requirements of
1901
+ this License.
1902
+
1903
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
1904
+ patent license under the contributor's essential patent claims, to
1905
+ make, use, sell, offer for sale, import and otherwise run, modify and
1906
+ propagate the contents of its contributor version.
1907
+
1908
+ In the following three paragraphs, a "patent license" is any express
1909
+ agreement or commitment, however denominated, not to enforce a patent
1910
+ (such as an express permission to practice a patent or covenant not to
1911
+ sue for patent infringement). To "grant" such a patent license to a
1912
+ party means to make such an agreement or commitment not to enforce a
1913
+ patent against the party.
1914
+
1915
+ If you convey a covered work, knowingly relying on a patent license,
1916
+ and the Corresponding Source of the work is not available for anyone
1917
+ to copy, free of charge and under the terms of this License, through a
1918
+ publicly available network server or other readily accessible means,
1919
+ then you must either (1) cause the Corresponding Source to be so
1920
+ available, or (2) arrange to deprive yourself of the benefit of the
1921
+ patent license for this particular work, or (3) arrange, in a manner
1922
+ consistent with the requirements of this License, to extend the patent
1923
+ license to downstream recipients. "Knowingly relying" means you have
1924
+ actual knowledge that, but for the patent license, your conveying the
1925
+ covered work in a country, or your recipient's use of the covered work
1926
+ in a country, would infringe one or more identifiable patents in that
1927
+ country that you have reason to believe are valid.
1928
+
1929
+ If, pursuant to or in connection with a single transaction or
1930
+ arrangement, you convey, or propagate by procuring conveyance of, a
1931
+ covered work, and grant a patent license to some of the parties
1932
+ receiving the covered work authorizing them to use, propagate, modify
1933
+ or convey a specific copy of the covered work, then the patent license
1934
+ you grant is automatically extended to all recipients of the covered
1935
+ work and works based on it.
1936
+
1937
+ A patent license is "discriminatory" if it does not include within
1938
+ the scope of its coverage, prohibits the exercise of, or is
1939
+ conditioned on the non-exercise of one or more of the rights that are
1940
+ specifically granted under this License. You may not convey a covered
1941
+ work if you are a party to an arrangement with a third party that is
1942
+ in the business of distributing software, under which you make payment
1943
+ to the third party based on the extent of your activity of conveying
1944
+ the work, and under which the third party grants, to any of the
1945
+ parties who would receive the covered work from you, a discriminatory
1946
+ patent license (a) in connection with copies of the covered work
1947
+ conveyed by you (or copies made from those copies), or (b) primarily
1948
+ for and in connection with specific products or compilations that
1949
+ contain the covered work, unless you entered into that arrangement,
1950
+ or that patent license was granted, prior to 28 March 2007.
1951
+
1952
+ Nothing in this License shall be construed as excluding or limiting
1953
+ any implied license or other defenses to infringement that may
1954
+ otherwise be available to you under applicable patent law.
1955
+
1956
+ 12. No Surrender of Others' Freedom.
1957
+
1958
+ If conditions are imposed on you (whether by court order, agreement or
1959
+ otherwise) that contradict the conditions of this License, they do not
1960
+ excuse you from the conditions of this License. If you cannot convey a
1961
+ covered work so as to satisfy simultaneously your obligations under this
1962
+ License and any other pertinent obligations, then as a consequence you may
1963
+ not convey it at all. For example, if you agree to terms that obligate you
1964
+ to collect a royalty for further conveying from those to whom you convey
1965
+ the Program, the only way you could satisfy both those terms and this
1966
+ License would be to refrain entirely from conveying the Program.
1967
+
1968
+ 13. Remote Network Interaction; Use with the GNU General Public License.
1969
+
1970
+ Notwithstanding any other provision of this License, if you modify the
1971
+ Program, your modified version must prominently offer all users
1972
+ interacting with it remotely through a computer network (if your version
1973
+ supports such interaction) an opportunity to receive the Corresponding
1974
+ Source of your version by providing access to the Corresponding Source
1975
+ from a network server at no charge, through some standard or customary
1976
+ means of facilitating copying of software. This Corresponding Source
1977
+ shall include the Corresponding Source for any work covered by version 3
1978
+ of the GNU General Public License that is incorporated pursuant to the
1979
+ following paragraph.
1980
+
1981
+ Notwithstanding any other provision of this License, you have
1982
+ permission to link or combine any covered work with a work licensed
1983
+ under version 3 of the GNU General Public License into a single
1984
+ combined work, and to convey the resulting work. The terms of this
1985
+ License will continue to apply to the part which is the covered work,
1986
+ but the work with which it is combined will remain governed by version
1987
+ 3 of the GNU General Public License.
1988
+
1989
+ 14. Revised Versions of this License.
1990
+
1991
+ The Free Software Foundation may publish revised and/or new versions of
1992
+ the GNU Affero General Public License from time to time. Such new versions
1993
+ will be similar in spirit to the present version, but may differ in detail to
1994
+ address new problems or concerns.
1995
+
1996
+ Each version is given a distinguishing version number. If the
1997
+ Program specifies that a certain numbered version of the GNU Affero General
1998
+ Public License "or any later version" applies to it, you have the
1999
+ option of following the terms and conditions either of that numbered
2000
+ version or of any later version published by the Free Software
2001
+ Foundation. If the Program does not specify a version number of the
2002
+ GNU Affero General Public License, you may choose any version ever published
2003
+ by the Free Software Foundation.
2004
+
2005
+ If the Program specifies that a proxy can decide which future
2006
+ versions of the GNU Affero General Public License can be used, that proxy's
2007
+ public statement of acceptance of a version permanently authorizes you
2008
+ to choose that version for the Program.
2009
+
2010
+ Later license versions may give you additional or different
2011
+ permissions. However, no additional obligations are imposed on any
2012
+ author or copyright holder as a result of your choosing to follow a
2013
+ later version.
2014
+
2015
+ 15. Disclaimer of Warranty.
2016
+
2017
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
2018
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
2019
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
2020
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
2021
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2022
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
2023
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
2024
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
2025
+
2026
+ 16. Limitation of Liability.
2027
+
2028
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
2029
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
2030
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
2031
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
2032
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
2033
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
2034
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
2035
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
2036
+ SUCH DAMAGES.
2037
+
2038
+ 17. Interpretation of Sections 15 and 16.
2039
+
2040
+ If the disclaimer of warranty and limitation of liability provided
2041
+ above cannot be given local legal effect according to their terms,
2042
+ reviewing courts shall apply local law that most closely approximates
2043
+ an absolute waiver of all civil liability in connection with the
2044
+ Program, unless a warranty or assumption of liability accompanies a
2045
+ copy of the Program in return for a fee.
2046
+
2047
+ END OF TERMS AND CONDITIONS
2048
+
2049
+ How to Apply These Terms to Your New Programs
2050
+
2051
+ If you develop a new program, and you want it to be of the greatest
2052
+ possible use to the public, the best way to achieve this is to make it
2053
+ free software which everyone can redistribute and change under these terms.
2054
+
2055
+ To do so, attach the following notices to the program. It is safest
2056
+ to attach them to the start of each source file to most effectively
2057
+ state the exclusion of warranty; and each file should have at least
2058
+ the "copyright" line and a pointer to where the full notice is found.
2059
+
2060
+ <one line to give the program's name and a brief idea of what it does.>
2061
+ Copyright (C) <year> <name of author>
2062
+
2063
+ This program is free software: you can redistribute it and/or modify
2064
+ it under the terms of the GNU Affero General Public License as published
2065
+ by the Free Software Foundation, either version 3 of the License, or
2066
+ (at your option) any later version.
2067
+
2068
+ This program is distributed in the hope that it will be useful,
2069
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2070
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2071
+ GNU Affero General Public License for more details.
2072
+
2073
+ You should have received a copy of the GNU Affero General Public License
2074
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
2075
+
2076
+ Also add information on how to contact you by electronic and paper mail.
2077
+
2078
+ If your software can interact with users remotely through a computer
2079
+ network, you should also make sure that it provides a way for users to
2080
+ get its source. For example, if your program is a web application, its
2081
+ interface could display a "Source" link that leads users to an archive
2082
+ of the code. There are many ways you could offer source, and different
2083
+ solutions will be better for different programs; see section 13 for the
2084
+ specific requirements.
2085
+
2086
+ You should also get your employer (if you work as a programmer) or school,
2087
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
2088
+ For more information on this, and how to apply and follow the GNU AGPL, see
2089
+ <https://www.gnu.org/licenses/>.
2090
+ `;
2091
+ //#endregion
2092
+ //#region src/templates/boilerplate/mcp.json.ts
2093
+ const mcpTemplate = json`
2094
+ {
2095
+ "mcpServers": {
2096
+ "reactor-mcp": {
2097
+ "type": "http",
2098
+ "url": "http://localhost:4001/mcp"
2099
+ }
2100
+ }
2101
+ }
2102
+ `.raw;
2103
+ //#endregion
2104
+ //#region src/templates/boilerplate/npmrc.ts
2105
+ const npmrcTemplate = `@jsr:registry=https://npm.jsr.io`;
2106
+ //#endregion
2107
+ //#region src/templates/boilerplate/package.json.ts
2108
+ const exportsTemplate = json`
2109
+ ".": {
2110
+ "types": "./dist/index.d.ts",
2111
+ "browser": "./dist/browser/index.js",
2112
+ "node": "./dist/node/index.mjs"
2113
+ },
2114
+ "./document-models": {
2115
+ "types": "./dist/document-models/index.d.ts",
2116
+ "browser": "./dist/browser/document-models/index.js",
2117
+ "node": "./dist/node/document-models/index.mjs"
2118
+ },
2119
+ "./document-models/*": {
2120
+ "types": "./dist/document-models/*/index.d.ts",
2121
+ "browser": "./dist/browser/document-models/*/index.js",
2122
+ "node": "./dist/node/document-models/*/index.mjs"
2123
+ },
2124
+ "./editors": {
2125
+ "types": "./dist/editors/index.d.ts",
2126
+ "browser": "./dist/browser/editors/index.js",
2127
+ "node": "./dist/node/editors/index.mjs"
2128
+ },
2129
+ "./editors/*": {
2130
+ "types": "./dist/editors/*/index.d.ts",
2131
+ "browser": "./dist/browser/editors/*/index.js",
2132
+ "node": "./dist/node/editors/*/index.mjs"
2133
+ },
2134
+ "./subgraphs": {
2135
+ "types": "./dist/subgraphs/index.d.ts",
2136
+ "browser": "./dist/browser/subgraphs/index.js",
2137
+ "node": "./dist/node/subgraphs/index.mjs"
2138
+ },
2139
+ "./processors": {
2140
+ "types": "./dist/processors/index.d.ts",
2141
+ "browser": "./dist/browser/processors/index.js",
2142
+ "node": "./dist/node/processors/index.mjs"
2143
+ },
2144
+ "./manifest": "./dist/powerhouse.manifest.json",
2145
+ "./style.css": "./dist/style.css"
2146
+ `.raw;
2147
+ const scriptsTemplate = json`
2148
+ "test": "vitest run",
2149
+ "test:watch": "vitest",
2150
+ "lint": "eslint --config eslint.config.js --cache --cache-strategy content",
2151
+ "lint:fix": "npm run lint -- --fix",
2152
+ "tsc": "tsc",
2153
+ "tsc:watch": "tsc --watch",
2154
+ "check-circular-imports": "npx dpdm -T ./index.ts",
2155
+ "generate": "ph-cli generate",
2156
+ "connect": "ph-cli connect",
2157
+ "build": "ph-cli build",
2158
+ "reactor": "ph-cli reactor",
2159
+ "service": "ph-cli service",
2160
+ "vetra": "ph-cli vetra",
2161
+ "service-startup": "bash ./node_modules/@powerhousedao/ph-cli/dist/scripts/service-startup.sh",
2162
+ "service-unstartup": "bash ./node_modules/@powerhousedao/ph-cli/dist/scripts/service-unstartup.sh"
2163
+ `.raw;
2164
+ const dependenciesTemplate = (versionedDependencies) => json`
2165
+ ${versionedDependencies.join(",\n")},
2166
+ "@powerhousedao/document-engineering": "1.40.1",
2167
+ "graphql": "^16.10.0",
2168
+ "graphql-tag": "^2.12.6",
2169
+ "zod": "^4.3.5",
2170
+ "react": "^19.2.3",
2171
+ "react-dom": "^19.2.3"
2172
+ `.raw;
2173
+ const devDependenciesTemplate = (versionedDevDependencies) => json`
2174
+ ${versionedDevDependencies.join(",\n")},
2175
+ "@eslint/js": "^9.38.0",
2176
+ "@tailwindcss/cli": "^4.1.18",
2177
+ "@types/node": "^24.9.2",
2178
+ "@types/react": "^19.2.3",
2179
+ "eslint": "^9.38.0",
2180
+ "eslint-plugin-react": "^7.37.5",
2181
+ "eslint-plugin-react-hooks": "^7.0.1",
2182
+ "eslint-config-prettier": "^10.1.8",
2183
+ "eslint-plugin-prettier": "^5.5.4",
2184
+ "globals": "^16.4.0",
2185
+ "tailwindcss": "^4.1.16",
2186
+ "typescript": "^5.9.3",
2187
+ "typescript-eslint": "^8.46.2",
2188
+ "vitest": "4.1.1",
2189
+ "@vitejs/plugin-react": "6.0.1",
2190
+ "vite-tsconfig-paths": "6.1.1"
2191
+ `.raw;
2192
+ const packageJsonTemplate = (projectName, versionedDependencies, versionedDevDependencies) => json`
2193
+ {
2194
+ "name": "${projectName}",
2195
+ "version": "1.0.0",
2196
+ "license": "AGPL-3.0-only",
2197
+ "type": "module",
2198
+ "files": [
2199
+ "/dist"
2200
+ ],
2201
+ "exports": {
2202
+ ${exportsTemplate}
2203
+ },
2204
+ "scripts": {
2205
+ ${scriptsTemplate}
2206
+ },
2207
+ "dependencies": {
2208
+ ${dependenciesTemplate(versionedDependencies)}
2209
+ },
2210
+ "devDependencies": {
2211
+ ${devDependenciesTemplate(versionedDevDependencies)}
2212
+ }
2213
+ }
2214
+ `.raw;
2215
+ //#endregion
2216
+ //#region src/templates/boilerplate/package.json.legacy.ts
2217
+ const packageJsonScriptsTemplate = {
2218
+ build: "npm run tsc && npm run tailwind",
2219
+ test: "vitest run",
2220
+ "test:watch": "vitest",
2221
+ lint: "eslint --config eslint.config.js --cache --cache-strategy content",
2222
+ "lint:fix": "npm run lint -- --fix",
2223
+ tsc: "tsc",
2224
+ "tsc:watch": "tsc --watch",
2225
+ tailwind: "pnpm exec tailwindcss -i ./style.css -o ./dist/style.css",
2226
+ prepublishOnly: "npm run build",
2227
+ "check-circular-imports": "npx dpdm -T ./index.ts",
2228
+ generate: "ph-cli generate",
2229
+ connect: "ph-cli connect",
2230
+ reactor: "ph-cli reactor",
2231
+ service: "ph-cli service",
2232
+ vetra: "ph-cli vetra",
2233
+ migrate: "ph-cli migrate",
2234
+ "service-startup": "bash ./node_modules/@powerhousedao/ph-cli/dist/scripts/service-startup.sh",
2235
+ "service-unstartup": "bash ./node_modules/@powerhousedao/ph-cli/dist/scripts/service-unstartup.sh"
2236
+ };
2237
+ const packageJsonExportsTemplate = {
2238
+ ".": {
2239
+ types: "./dist/index.d.ts",
2240
+ default: "./dist/index.js"
2241
+ },
2242
+ "./document-models": {
2243
+ types: "./dist/document-models/index.d.ts",
2244
+ default: "./dist/document-models/index.js"
2245
+ },
2246
+ "./editors": {
2247
+ types: "./dist/editors/index.d.ts",
2248
+ default: "./dist/editors/index.js"
2249
+ },
2250
+ "./document-models/*": {
2251
+ types: "./dist/document-models/*/index.d.ts",
2252
+ default: "./dist/document-models/*/index.js"
2253
+ },
2254
+ "./editors/*": {
2255
+ types: "./dist/editors/*/index.d.ts",
2256
+ default: "./dist/editors/*/index.js"
2257
+ },
2258
+ "./subgraphs": {
2259
+ types: "./dist/subgraphs/index.d.ts",
2260
+ default: "./dist/subgraphs/index.js"
2261
+ },
2262
+ "./processors": {
2263
+ types: "./dist/processors/index.d.ts",
2264
+ default: "./dist/processors/index.js"
2265
+ },
2266
+ "./manifest": { default: "./dist/powerhouse.manifest.json" },
2267
+ "./style.css": "./dist/style.css"
2268
+ };
2269
+ //#endregion
2270
+ //#region src/templates/boilerplate/powerhouse.config.json.ts
2271
+ function makeVetraConfigField(vetraDriveUrl) {
2272
+ if (!vetraDriveUrl) return "";
2273
+ return json`
2274
+ ,
2275
+ "vetra": {
2276
+ "driveId": "${vetraDriveUrl.split("/").pop() ?? ""}",
2277
+ "driveUrl": "${vetraDriveUrl}"
2278
+ }
2279
+ `.raw;
2280
+ }
2281
+ async function buildPowerhouseConfigTemplate(args) {
2282
+ return json`
2283
+ {
2284
+ "documentModelsDir": "./document-models",
2285
+ "editorsDir": "./editors",
2286
+ "processorsDir": "./processors",
2287
+ "subgraphsDir": "./subgraphs",
2288
+ "studio": {
2289
+ "port": 3000
2290
+ },
2291
+ "reactor": {
2292
+ "port": 4001
2293
+ },
2294
+ "packages": [
2295
+ ]${makeVetraConfigField(args.remoteDrive)}
2296
+ }
2297
+ `.raw;
2298
+ }
2299
+ //#endregion
2300
+ //#region src/templates/boilerplate/powerhouse.manifest.json.ts
2301
+ const powerhouseManifestTemplate = (projectName) => json`
2302
+ {
2303
+ "name": "${projectName}",
2304
+ "description": "",
2305
+ "category": "",
2306
+ "publisher": {
2307
+ "name": "",
2308
+ "url": ""
2309
+ },
2310
+ "documentModels": [],
2311
+ "editors": [],
2312
+ "apps": [],
2313
+ "subgraphs": [],
2314
+ "importScripts": []
2315
+ }
2316
+
2317
+ `.raw;
2318
+ //#endregion
2319
+ //#region src/templates/boilerplate/README.md.ts
2320
+ const readmeTemplate = md`
2321
+ # Document Model Boilerplate
2322
+
2323
+ This Document Model Boilerplate provides code generation for scaffolding editors and models.
2324
+ It ensures compatibility with host applications like Connect and the Reactors for seamless document model and editor integration.
2325
+
2326
+ ## Standard Document Model Workflow with help of the boilerplate.
2327
+
2328
+ This tutorial will guide you through the process of creating a new document model using the Document Model Editor in the Connect app.
2329
+
2330
+ <details>
2331
+ <summary>Available NPM commands</summary>
2332
+
2333
+ - \`generate\`: Updates the generated code according to the JSON spec and GraphQL schema of your document model, made in Connect.
2334
+ - \`lint\`: Checks for errors with ESLint and TypeScript checking.
2335
+ - \`format\`: Formats the code using Prettier.
2336
+ - \`build\`: Builds the library project using Vite.
2337
+ - \`storybook\`: Starts Storybook in development mode.
2338
+ - \`build-storybook\`: Builds Storybook.
2339
+ - \`test\`: Runs Jest for testing.
2340
+
2341
+ </details>
2342
+
2343
+ ### 1. Defining Your Document Model GraphQL Schema
2344
+
2345
+ Start by creating your own 'Powerhouse Project' (Document model + editor).
2346
+
2347
+ Step 1: Run the following command to set up your project inside this directory:
2348
+
2349
+ ~~~bash
2350
+ npm create document-model-lib
2351
+ ~~~
2352
+
2353
+ Step 2: Use the Document Model Editor in the Connect app
2354
+
2355
+ The following command gives you access to all the powerhouse CLI tools available, install it globally if you are a poweruser.
2356
+
2357
+ ~~~bash
2358
+ npm install ph-cmd
2359
+ ~~~
2360
+
2361
+ Now you are able to launch Connect in Studio Mode (Locally):
2362
+
2363
+ ~~~bash
2364
+ npm run connect
2365
+ ~~~
2366
+
2367
+ Open the 'Document Model' creator at the bottom of connect to define your document mode with it's GraphQL Schema Definition.
2368
+ This schema will define the structure and fields for your document model using GraphQL.
2369
+ Follow one of our tutorials on Academy to get familiar with the process.
2370
+
2371
+ ### 2. Defining Document Model Operations
2372
+
2373
+ Using the Document Model Operations Editor, define the operations for your document model and their GraphQL counterparts.
2374
+ These operations will handle state changes within your document model.
2375
+
2376
+ **Best Practices:**
2377
+
2378
+ - Clearly define CRUD operations (Create, Read, Update, Delete).
2379
+ - Use GraphQL input types to specify the parameters for each operation.
2380
+ - Ensure that operations align with user intent to maintain a clean and understandable API.
2381
+
2382
+ ### 3. Generating Scaffolding Code
2383
+
2384
+ Export your document model as a .zip file from Connect.
2385
+ Import the .zip file into your project directory created in Step 1.
2386
+ Run the following command to generate the scaffolding code:
2387
+
2388
+ ~~~bash
2389
+ npm run generate YourModelName.phdm.zip
2390
+ ~~~
2391
+
2392
+ This will create a new directory under /document-models containing:
2393
+
2394
+ JSON file with the document model specification.
2395
+ GraphQL file with state and operation schemas.
2396
+ A gen/ folder with autogenerated code.
2397
+ A src/ folder for your custom code implementation.
2398
+
2399
+ ### 4. Implementing Reducer Code and Unit Tests
2400
+
2401
+ Navigate to the reducer directory:
2402
+
2403
+ ~~~bash
2404
+ cd document-models/"YourModelName"/src/reducers
2405
+ ~~~
2406
+
2407
+ Implement the reducer functions for each document model operation. These functions will handle state transitions.
2408
+
2409
+ Add utility functions in:
2410
+
2411
+ ~~~bash
2412
+ document-models/"YourModelName"/src/utils.ts
2413
+ ~~~
2414
+
2415
+ Write unit tests to ensure the correctness of your reducers:
2416
+
2417
+ Test files should be located in:
2418
+
2419
+ ~~~bash
2420
+ document-models/"YourModelName"/src/reducers/tests
2421
+ ~~~
2422
+
2423
+ Run the tests:
2424
+
2425
+ ~~~bash
2426
+ npm test
2427
+ ~~~
2428
+
2429
+ Test the editor functionality:
2430
+
2431
+ ~~~bash
2432
+ npm run connect
2433
+ ~~~
2434
+
2435
+ ### 5. Implementing Document Editors
2436
+
2437
+ Generate the editor template for your document model:
2438
+
2439
+ ~~~bash
2440
+ npm run generate -- --editor YourModelName --document-types powerhouse/YourModelName
2441
+ ~~~
2442
+
2443
+ The --editor flag specifies the name of your document model.
2444
+ The --document-types flag links the editor to your document model type.
2445
+ After generation:
2446
+
2447
+ Open the editor template:
2448
+
2449
+ ~~~bash
2450
+ editors/YourModelName/editor.tsx
2451
+ ~~~
2452
+
2453
+ Customize the editor interface to suit your document model.
2454
+
2455
+ ### 6. Testing the Document Editor
2456
+
2457
+ Run the Connect app to test your document editor:
2458
+
2459
+ ~~~bash
2460
+ npm run connect
2461
+ ~~~
2462
+
2463
+ Verify that the editor functions as expected.
2464
+ Perform end-to-end testing to ensure smooth integration between the document model and its editor.
2465
+
2466
+ ### 7. Adding a Manifest File
2467
+
2468
+ Create a manifest file to describe your document model and editor. This enables proper integration with the host application.
2469
+
2470
+ **Example manifest.json:**
2471
+
2472
+ ~~~json
2473
+ {
2474
+ "name": "your-model-name",
2475
+ "description": "A brief description of your document model.",
2476
+ "category": "your-category", // e.g., "Finance", "People Ops", "Legal"
2477
+ "publisher": {
2478
+ "name": "your-publisher-name",
2479
+ "url": "your-publisher-url"
2480
+ },
2481
+ "documentModels": [
2482
+ {
2483
+ "id": "your-model-id",
2484
+ "name": "your-model-name"
2485
+ }
2486
+ ],
2487
+ "editors": [
2488
+ {
2489
+ "id": "your-editor-id",
2490
+ "name": "your-editor-name",
2491
+ "documentTypes": ["your-model-id"]
2492
+ }
2493
+ ]
2494
+ }
2495
+ ~~~
2496
+
2497
+ ### Steps to finalize:
2498
+
2499
+ Place the manifest file at your project root.
2500
+ Update your index.js to export your modules and include the new document model and editor.
2501
+
2502
+ ### Final Thoughts
2503
+
2504
+ You've now successfully created a Document Model and its corresponding Editor using the Connect app!
2505
+
2506
+ Next Steps:
2507
+
2508
+ - Expand functionality: Add more operations or complex logic to your document model.
2509
+ - Improve UX: Enhance the document editor for a smoother user experience.
2510
+ - Integrate with other systems: Use APIs or GraphQL to connect your document model with external services.
2511
+ `.raw;
2512
+ //#endregion
2513
+ //#region src/templates/boilerplate/style.css.ts
2514
+ const styleTemplate = css`
2515
+ @import "tailwindcss";
2516
+ @import "@powerhousedao/design-system/theme.css";
2517
+ @import "@powerhousedao/connect/style.css";
2518
+
2519
+ @theme {
2520
+ /* You can customize the theme by overriding the theme variables here */
2521
+ /* See https://tailwindcss.com/docs/theme#using-a-custom-theme for details */
2522
+
2523
+ /* If you would prefer to use plain css, add your styles below this @theme tag as you normally would */
2524
+
2525
+ /* A sensible CSS reset is applied by default. If you would prefer to use a different reset or none at all, uncomment the following line */
2526
+
2527
+ /* --*: initial; */
2528
+ }
2529
+ `.raw;
2530
+ //#endregion
2531
+ //#region src/templates/boilerplate/subgraphs/index.ts
2532
+ const subgraphsIndexTemplate = "";
2533
+ //#endregion
2534
+ //#region src/templates/boilerplate/tsconfig.json.ts
2535
+ const tsconfigPathsTemplate = json`
2536
+ "document-models": [
2537
+ "./document-models/index.ts"
2538
+ ],
2539
+ "document-models/*": [
2540
+ "./document-models/*/index.ts"
2541
+ ],
2542
+ "editors": [
2543
+ "./editors/index.ts"
2544
+ ],
2545
+ "editors/*": [
2546
+ "./editors/*/index.ts"
2547
+ ],
2548
+ "processors/*": [
2549
+ "./processors/*/index.ts"
2550
+ ],
2551
+ "subgraphs": [
2552
+ "./subgraphs/index.ts"
2553
+ ],
2554
+ "subgraphs/*": [
2555
+ "./subgraphs/*/index.ts"
2556
+ ]`.raw;
2557
+ const tsConfigTemplate = json`
2558
+ {
2559
+ "compilerOptions": {
2560
+ "outDir": "./dist",
2561
+ "rootDir": ".",
2562
+ // paths for easy access to project modules
2563
+ "paths": {
2564
+ ${tsconfigPathsTemplate}
2565
+ },
2566
+ "module": "nodenext",
2567
+ "moduleDetection": "force",
2568
+ "target": "esnext",
2569
+ "jsx": "react-jsx",
2570
+ "types": ["node", "vitest/globals"],
2571
+ "lib": ["ESNext", "dom", "dom.iterable"],
2572
+ "declaration": true,
2573
+ "declarationMap": true,
2574
+ "emitDeclarationOnly": true,
2575
+ "strict": true,
2576
+ "verbatimModuleSyntax": true,
2577
+ "isolatedModules": true,
2578
+ "noUncheckedSideEffectImports": true,
2579
+ "skipLibCheck": true
2580
+ },
2581
+ "include": ["**/*", "./powerhouse.manifest.json"],
2582
+ "exclude": ["dist", "node_modules", ".ph"]
2583
+ }
2584
+ `.raw;
2585
+ //#endregion
2586
+ //#region src/templates/boilerplate/vite.config.ts.ts
2587
+ const viteConfigTemplate = ts`
2588
+ import { getConnectBaseViteConfig } from "@powerhousedao/builder-tools";
2589
+ import { defineConfig, mergeConfig, type UserConfig } from "vite";
2590
+
2591
+ export default defineConfig(({ mode }) => {
2592
+ const baseConnectViteConfig = getConnectBaseViteConfig({
2593
+ mode,
2594
+ dirname: import.meta.dirname,
2595
+ });
2596
+
2597
+ const additionalViteConfig: UserConfig = {
2598
+ // add your own vite config here
2599
+ };
2600
+
2601
+ const config = mergeConfig(baseConnectViteConfig, additionalViteConfig);
2602
+
2603
+ return config;
2604
+ });
2605
+ `;
2606
+ //#endregion
2607
+ //#region src/templates/boilerplate/vitest.config.ts.ts
2608
+ const vitestConfigTemplate = ts`
2609
+ import { defineConfig } from "vitest/config";
2610
+ import react from "@vitejs/plugin-react";
2611
+ import tsconfigPaths from "vite-tsconfig-paths";
2612
+
2613
+ export default defineConfig({
2614
+ test: {
2615
+ globals: true,
2616
+ },
2617
+ plugins: [tsconfigPaths(), react()],
2618
+ });
2619
+
2620
+ `;
2621
+ //#endregion
2622
+ //#region src/templates/cli-docs/docs-from-cli-help.ts
2623
+ function groupHelpTopicsByCategory(helpTopics) {
2624
+ const helpTopicsByCategory = {};
2625
+ for (const helpTopic of helpTopics) if (!helpTopicsByCategory[helpTopic.category]) helpTopicsByCategory[helpTopic.category] = [helpTopic];
2626
+ else helpTopicsByCategory[helpTopic.category]?.push(helpTopic);
2627
+ return helpTopicsByCategory;
2628
+ }
2629
+ function makeTableOfContents(commandsHelpInfo) {
2630
+ const commandNames = commandsHelpInfo.map(({ name }) => name);
2631
+ const tableOfContentsEntries = [];
2632
+ for (const name of commandNames) tableOfContentsEntries.push(`- [${capitalCase(name)}](#${kebabCase(name)})\n`);
2633
+ return tableOfContentsEntries.join("");
2634
+ }
2635
+ function makeDefaultsDescriptors(defaults) {
2636
+ return defaults.filter((d) => d !== "optional" && d !== "[...optional]").map((d) => {
2637
+ const [label, ...rest] = d.split(":").map((s) => s.trim());
2638
+ return `**${label}**: \`${rest.join("")}\``;
2639
+ });
2640
+ }
2641
+ function makeRequiredDescriptor(defaults) {
2642
+ if (defaults.includes("optional") || defaults.includes("[...optional]") || defaults.some((d) => d.includes("default"))) return "";
2643
+ return "*[required]*";
2644
+ }
2645
+ function makeHeadingFromUsage(usage) {
2646
+ if (usage.includes("--")) return `#### ${capitalCase(usage.split(" ")[0].replace("--", ""))}`;
2647
+ return `#### ${capitalCase(usage.replace("[", "").replace("]", ""))}`;
2648
+ }
2649
+ function makeCommandHelpTopicDocs(helpTopic) {
2650
+ const { defaults, description, usage } = helpTopic;
2651
+ return `${makeHeadingFromUsage(usage)} ${makeRequiredDescriptor(defaults)}<br>
2652
+ ${description}<br><br>
2653
+ **usage:** \`${usage}\`<br>
2654
+ ${makeDefaultsDescriptors(defaults).join("<br>")}
2655
+ `;
2656
+ }
2657
+ function makeCommandHelpTopicsDocs(helpTopics) {
2658
+ return helpTopics.map(makeCommandHelpTopicDocs).join("");
2659
+ }
2660
+ function makeCommandHelpTopicsDocsForCategories(helpTopics) {
2661
+ const helpTopicsByCategory = groupHelpTopicsByCategory(helpTopics);
2662
+ const helpTopicsDocs = [];
2663
+ for (const [category, helpTopics] of Object.entries(helpTopicsByCategory)) {
2664
+ const helpTopicDocs = makeCommandHelpTopicsDocs(helpTopics ?? []);
2665
+ helpTopicsDocs.push(`### ${category}
2666
+ ${helpTopicDocs}
2667
+ `);
2668
+ }
2669
+ return helpTopicsDocs.join("");
2670
+ }
2671
+ function makeCommandDoc(commandHelpInfo) {
2672
+ const { name, description, helpTopics } = commandHelpInfo;
2673
+ return `## ${capitalCase(name)}
2674
+ ${description}
2675
+ ${makeCommandHelpTopicsDocsForCategories(helpTopics)}`;
2676
+ }
2677
+ function makeCommandDocs(commandsHelpInfo) {
2678
+ return commandsHelpInfo.map(makeCommandDoc).join("");
2679
+ }
2680
+ const docsFromCliHelpTemplate = (v) => `# ${v.docsTitle}<br>
2681
+ ${v.docsIntroduction}<br><br>
2682
+ ${v.cliDescription}<br>
2683
+ ## Table of Contents
2684
+ ${makeTableOfContents(v.commandsHelpInfo)}<br>
2685
+ ${makeCommandDocs(v.commandsHelpInfo)}
2686
+ `;
2687
+ //#endregion
2688
+ //#region src/templates/document-editor/editor.ts
2689
+ const documentEditorEditorFileTemplate = (v) => tsx`
2690
+ import { DocumentStateViewer, DocumentToolbar } from "@powerhousedao/design-system/connect";
2691
+ import { ${v.useSelectedDocumentHookName}, actions } from "${v.documentModelImportPath}";
2692
+
2693
+ export default function Editor() {
2694
+ const [document, dispatch] = ${v.useSelectedDocumentHookName}();
2695
+
2696
+ const handleSetName = (name: string) => {
2697
+ // 'actions' contains all available actions for this document type
2698
+ dispatch(actions.setName(name));
2699
+ };
2700
+
2701
+ return (
2702
+ <div className="mx-auto max-w-4xl bg-gray-50 p-6">
2703
+ <DocumentToolbar />
2704
+
2705
+ {/* "ph-default-styles" sets default styles for basic UI elements */}
2706
+ <div className="ph-default-styles">
2707
+ {/* Edit document name */}
2708
+ <label className="my-6">
2709
+ <h3>Document Name</h3>
2710
+ <input
2711
+ type="text"
2712
+ defaultValue={document.header.name}
2713
+ placeholder="Enter document name..."
2714
+ title="Edit document name and click outside to save."
2715
+ autoFocus
2716
+ onBlur={(e) => handleSetName(e.target.value.trim())}
2717
+ onKeyDown={(e) => {
2718
+ if (e.key === "Enter") {
2719
+ e.currentTarget.blur();
2720
+ }
2721
+ }}
2722
+ className="font-semibold"
2723
+ />
2724
+ </label>
2725
+ <hr />
2726
+
2727
+ {/* Document header info */}
2728
+ <div className="mb-6 grid grid-cols-2 gap-x-8">
2729
+ <label>
2730
+ <h3 className="text-base">ID</h3>
2731
+ <input
2732
+ type="text"
2733
+ value={document.header.id}
2734
+ readOnly
2735
+ className="font-mono"
2736
+ />
2737
+ </label>
2738
+ <label>
2739
+ <h3 className="text-base">Created</h3>
2740
+ <input
2741
+ type="text"
2742
+ value={new Date(document.header.createdAtUtcIso).toLocaleString()}
2743
+ readOnly
2744
+ />
2745
+ </label>
2746
+ <label>
2747
+ <h3 className="text-base">Type</h3>
2748
+ <input type="text" value={document.header.documentType} readOnly />
2749
+ </label>
2750
+ <label>
2751
+ <h3 className="text-base">Last Modified</h3>
2752
+ <input
2753
+ type="text"
2754
+ value={new Date(
2755
+ document.header.lastModifiedAtUtcIso,
2756
+ ).toLocaleString()}
2757
+ readOnly
2758
+ />
2759
+ </label>
2760
+ </div>
2761
+
2762
+ {/* Document state */}
2763
+ <div className="mt-6">
2764
+ <h3 className="text-base">Document State</h3>
2765
+ <DocumentStateViewer state={document.state} />
2766
+ </div>
2767
+ </div>
2768
+ </div>
2769
+ );
2770
+ }
2771
+ `.raw;
2772
+ //#endregion
2773
+ //#region src/templates/document-editor/module.ts
2774
+ const documentEditorModuleFileTemplate = (v) => tsx`
2775
+ import type { EditorModule } from "document-model";
2776
+ import { lazy } from "react";
2777
+
2778
+ /** Document editor module for the "${v.documentTypes}" document type */
2779
+ export const ${v.pascalCaseEditorName}: EditorModule = {
2780
+ Component: lazy(() => import("./editor.js")),
2781
+ documentTypes: ${v.documentTypes},
2782
+ config: {
2783
+ id: "${v.editorId}",
2784
+ name: "${v.editorName}",
2785
+ },
2786
+ };
2787
+ `.raw;
2788
+ //#endregion
2789
+ //#region src/templates/document-model/actions.ts
2790
+ function buildModuleActionsName(module, camelCaseDocumentType) {
2791
+ const camelCaseModuleName = camelCase(module.name);
2792
+ return `${camelCaseDocumentType}${camelCaseModuleName.charAt(0).toUpperCase()}${camelCaseModuleName.slice(1)}Actions`;
2793
+ }
2794
+ function buildModuleActionsNames(modules, camelCaseDocumentType) {
2795
+ return modules.map((m) => buildModuleActionsName(m, camelCaseDocumentType));
2796
+ }
2797
+ function buildModuleActionsImports(modules, camelCaseDocumentType) {
2798
+ return `import { ${buildModuleActionsNames(modules, camelCaseDocumentType).join(",\n")} } from "./gen/creators.js";`;
2799
+ }
2800
+ function buildModuleActionsSpreadExport(modules, camelCaseDocumentType) {
2801
+ return `
2802
+ export const actions = { ...baseActions, ${buildModuleActionsNames(modules, camelCaseDocumentType).map((n) => `...${n}`).join(",\n")} }`;
2803
+ }
2804
+ const documentModelRootActionsFileTemplate = (v) => ts`
2805
+ import { baseActions } from "document-model";
2806
+ ${buildModuleActionsImports(v.modules, v.camelCaseDocumentType)}
2807
+
2808
+ /** Actions for the ${v.pascalCaseDocumentType} document model */
2809
+ ${buildModuleActionsSpreadExport(v.modules, v.camelCaseDocumentType)}
2810
+ `.raw;
2811
+ //#endregion
2812
+ //#region src/templates/document-model/gen/actions.ts
2813
+ function makeModuleActionsTypeImport(module, pascalCaseDocumentType) {
2814
+ return `import type { ${pascalCaseDocumentType}${pascalCase(module.name)}Action } from "./${kebabCase(module.name)}/actions.js";`;
2815
+ }
2816
+ function makeModuleActionsTypeImports(modules, pascalCaseDocumentType) {
2817
+ return modules.map((module) => makeModuleActionsTypeImport(module, pascalCaseDocumentType)).join("\n");
2818
+ }
2819
+ function makeModuleActionsTypeExport(module) {
2820
+ return `export * from "./${kebabCase(module.name)}/actions.js";`;
2821
+ }
2822
+ function makeModuleActionsTypeExports(modules) {
2823
+ return modules.map(makeModuleActionsTypeExport).join("\n");
2824
+ }
2825
+ function makeModuleActionTypeName(module, pascalCaseDocumentType) {
2826
+ return `${pascalCaseDocumentType}${pascalCase(module.name)}Action`;
2827
+ }
2828
+ function makeModuleActionTypesUnion(modules, pascalCaseDocumentType) {
2829
+ return modules.map((module) => makeModuleActionTypeName(module, pascalCaseDocumentType)).join("|\n");
2830
+ }
2831
+ function makeDocumentActionType(modules, pascalCaseDocumentType) {
2832
+ return `export type ${pascalCaseDocumentType}Action = ${makeModuleActionTypesUnion(modules, pascalCaseDocumentType)};`;
2833
+ }
2834
+ const documentModelGenActionsFileTemplate = (v) => ts`
2835
+ ${makeModuleActionsTypeImports(v.modules, v.pascalCaseDocumentType)}
2836
+
2837
+ ${makeModuleActionsTypeExports(v.modules)}
2838
+
2839
+ ${makeDocumentActionType(v.modules, v.pascalCaseDocumentType)}
2840
+ `.raw;
2841
+ //#endregion
2842
+ //#region src/templates/document-model/gen/controller.ts
2843
+ const documentModelGenControllerFileTemplate = (v) => ts`
2844
+ import { PHDocumentController } from "document-model";
2845
+ import { ${v.pascalCaseDocumentType} } from "../module.js";
2846
+ import type { ${v.actionTypeName}, ${v.phStateName} } from "./types.js";
2847
+
2848
+ export const ${v.pascalCaseDocumentType}Controller = PHDocumentController.forDocumentModel<
2849
+ ${v.phStateName},
2850
+ ${v.actionTypeName}
2851
+ >(${v.pascalCaseDocumentType});
2852
+ `.raw;
2853
+ //#endregion
2854
+ //#region src/templates/document-model/gen/creators.ts
2855
+ function buildModuleCreatorsExport(module, camelCaseDocumentType) {
2856
+ const kebabCaseModuleName = kebabCase(module.name);
2857
+ const camelCaseModuleName = camelCase(module.name);
2858
+ const namespaceName = `${camelCaseDocumentType}${camelCaseModuleName.charAt(0).toUpperCase()}${camelCaseModuleName.slice(1)}Actions`;
2859
+ return [`export * from "./${kebabCaseModuleName}/creators.js";`, `export * as ${namespaceName} from "./${kebabCaseModuleName}/creators.js";`];
2860
+ }
2861
+ function buildCreatorsExports(modules, camelCaseDocumentType) {
2862
+ return modules.flatMap((module) => buildModuleCreatorsExport(module, camelCaseDocumentType)).join("\n");
2863
+ }
2864
+ const documentModelGenCreatorsFileTemplate = (v) => ts`
2865
+ ${buildCreatorsExports(v.modules, v.camelCaseDocumentType)}
2866
+ `.raw;
2867
+ //#endregion
2868
+ //#region src/templates/document-model/gen/document-schema.ts
2869
+ const documentModelDocumentSchemaFileTemplate = (v) => ts`
2870
+ import {
2871
+ BaseDocumentHeaderSchema,
2872
+ BaseDocumentStateSchema,
2873
+ } from "document-model";
2874
+ import { z } from "zod";
2875
+ import { ${v.documentTypeVariableName} } from "./document-type.js";
2876
+ import { ${v.stateSchemaName} } from "./schema/zod.js";
2877
+ import type { ${v.phDocumentTypeName}, ${v.phStateName} } from "./types.js";
2878
+
2879
+ /** Schema for validating the header object of a ${v.pascalCaseDocumentType} document */
2880
+ export const ${v.phDocumentTypeName}HeaderSchema = BaseDocumentHeaderSchema.extend({
2881
+ documentType: z.literal(${v.documentTypeVariableName}),
2882
+ });
2883
+
2884
+ /** Schema for validating the state object of a ${v.pascalCaseDocumentType} document */
2885
+ export const ${v.phStateName}Schema = BaseDocumentStateSchema.extend({
2886
+ global: ${v.stateSchemaName}(),
2887
+ });
2888
+
2889
+ export const ${v.phDocumentSchemaName} = z.object({
2890
+ header: ${v.phDocumentTypeName}HeaderSchema,
2891
+ state: ${v.phStateName}Schema,
2892
+ initialState: ${v.phStateName}Schema,
2893
+ });
2894
+
2895
+ /** Simple helper function to check if a state object is a ${v.pascalCaseDocumentType} document state object */
2896
+ export function ${v.isPhStateOfTypeFunctionName}(
2897
+ state: unknown,
2898
+ ): state is ${v.phStateName} {
2899
+ return ${v.phStateName}Schema.safeParse(state).success;
2900
+ }
2901
+
2902
+ /** Simple helper function to assert that a document state object is a ${v.pascalCaseDocumentType} document state object */
2903
+ export function ${v.assertIsPhStateOfTypeFunctionName}(
2904
+ state: unknown,
2905
+ ): asserts state is ${v.phStateName} {
2906
+ ${v.phStateName}Schema.parse(state);
2907
+ }
2908
+
2909
+ /** Simple helper function to check if a document is a ${v.pascalCaseDocumentType} document */
2910
+ export function ${v.isPhDocumentOfTypeFunctionName}(
2911
+ document: unknown,
2912
+ ): document is ${v.phDocumentTypeName} {
2913
+ return ${v.phDocumentSchemaName}.safeParse(document).success;
2914
+ }
2915
+
2916
+ /** Simple helper function to assert that a document is a ${v.pascalCaseDocumentType} document */
2917
+ export function ${v.assertIsPhDocumentOfTypeFunctionName}(
2918
+ document: unknown,
2919
+ ): asserts document is ${v.phDocumentTypeName} {
2920
+ ${v.phDocumentSchemaName}.parse(document);
2921
+ }
2922
+ `.raw;
2923
+ //#endregion
2924
+ //#region src/templates/document-model/gen/document-type.ts
2925
+ const documentModelDocumentTypeTemplate = (v) => ts`
2926
+ export const ${v.documentTypeVariableName} = "${v.documentTypeId}";
2927
+ `.raw;
2928
+ //#endregion
2929
+ //#region src/templates/document-model/gen/index.ts
2930
+ function buildModuleOperationsExports(module) {
2931
+ return `export * from "./${kebabCase(module.name)}/operations.js";`;
2932
+ }
2933
+ function buildModulesOperationsExports(modules) {
2934
+ return modules.map(buildModuleOperationsExports).join("\n");
2935
+ }
2936
+ const documentModelGenIndexFileTemplate = (v) => ts`
2937
+ export * from './actions.js';
2938
+ export * from './document-model.js';
2939
+ export * from './types.js';
2940
+ export * from './creators.js';
2941
+ export {
2942
+ create${v.phDocumentTypeName},
2943
+ createState,
2944
+ defaultPHState,
2945
+ defaultGlobalState,
2946
+ defaultLocalState,
2947
+ } from './ph-factories.js';
2948
+ export * from "./utils.js";
2949
+ export * from "./reducer.js";
2950
+ export * from "./controller.js";
2951
+ export * from "./schema/index.js";
2952
+ export * from "./document-type.js";
2953
+ export * from "./document-schema.js";
2954
+ ${buildModulesOperationsExports(v.modules)}
2955
+ `.raw;
2956
+ //#endregion
2957
+ //#region src/templates/document-model/gen/modules/actions.ts
2958
+ function getActionTypeExport(action) {
2959
+ const baseActionTypeName = action.hasAttachment ? "ActionWithAttachment" : "Action";
2960
+ const actionTypeName = getActionTypeName(action);
2961
+ const actionInputName = getActionInputName(action) ?? `"{}"`;
2962
+ return ts`export type ${actionTypeName} = ${baseActionTypeName} & { type: "${getActionType(action)}"; input: ${actionInputName} };`.raw;
2963
+ }
2964
+ function getActionTypeExports(actions) {
2965
+ return actions.map(getActionTypeExport).join("\n");
2966
+ }
2967
+ function getModuleExportType(actions, pascalCaseDocumentName, pascalCaseModuleName) {
2968
+ return ts`export type ${pascalCaseDocumentName}${pascalCaseModuleName}Action = ${actions.map(getActionTypeName).join(" |\n")};`.raw;
2969
+ }
2970
+ function getDocumentModelActionTypeImportNames(actions) {
2971
+ const actionTypeImports = ["Action"];
2972
+ if (actions.some((a) => a.hasAttachment)) actionTypeImports.push("ActionWithAttachment");
2973
+ return actionTypeImports.join(",\n");
2974
+ }
2975
+ const documentModelOperationModuleActionsFileTemplate = (v) => ts`
2976
+ import type { ${getDocumentModelActionTypeImportNames(v.actions)} } from 'document-model';
2977
+ import type {
2978
+ ${getActionInputTypeNames(v.actions)}
2979
+ } from '../types.js';
2980
+
2981
+ ${getActionTypeExports(v.actions)}
2982
+
2983
+ ${getModuleExportType(v.actions, v.pascalCaseDocumentType, v.pascalCaseModuleName)}
2984
+ `.raw;
2985
+ //#endregion
2986
+ //#region src/templates/document-model/gen/modules/creators.ts
2987
+ function makeDocumentModelTypeImports(actions) {
2988
+ const actionTypeImports = ["createAction"];
2989
+ if (actions.some((a) => a.hasAttachment)) actionTypeImports.push("AttachmentInput");
2990
+ return actionTypeImports.join(",\n");
2991
+ }
2992
+ function makeActionInputSchemaName(action) {
2993
+ if (!action.hasInput) return;
2994
+ return `${pascalCase(action.name)}InputSchema`;
2995
+ }
2996
+ function makeActionInputTypeName(action) {
2997
+ if (!action.hasInput) return;
2998
+ return `${pascalCase(action.name)}Input`;
2999
+ }
3000
+ function makeActionTypeName(action) {
3001
+ return `${pascalCase(action.name)}Action`;
3002
+ }
3003
+ function makeActionInputSchemaImports(actions) {
3004
+ return actions.map(makeActionInputSchemaName).filter(Boolean).join(",\n");
3005
+ }
3006
+ function makeActionInputTypeImports(actions) {
3007
+ return actions.map(makeActionInputTypeName).filter(Boolean).join(",\n");
3008
+ }
3009
+ function makeActionTypeImports(actions) {
3010
+ return actions.map(makeActionTypeName).join(",\n");
3011
+ }
3012
+ function makeActionCreatorWithInput(actionWithInput) {
3013
+ if (!actionWithInput.hasInput) return;
3014
+ const camelCaseActionName = camelCase(actionWithInput.name);
3015
+ const constantCaseActionName = constantCase(actionWithInput.name);
3016
+ const actionTypeName = makeActionTypeName(actionWithInput);
3017
+ const inputSchemaName = makeActionInputSchemaName(actionWithInput);
3018
+ const inputTypeName = makeActionInputTypeName(actionWithInput);
3019
+ const argsArray = [actionWithInput.isEmptyInput ? `input: ${inputTypeName} = {}` : `input: ${inputTypeName}`];
3020
+ if (actionWithInput.hasAttachment) argsArray.push(`attachments: AttachmentInput[]`);
3021
+ return ts`
3022
+ export const ${camelCaseActionName} = (${argsArray.join(", ")}) =>
3023
+ createAction<${actionTypeName}>(
3024
+ "${constantCaseActionName}",
3025
+ {...input},
3026
+ ${actionWithInput.hasAttachment ? "attachments" : "undefined"},
3027
+ ${inputSchemaName},
3028
+ "${actionWithInput.scope}"
3029
+ );`.raw;
3030
+ }
3031
+ function makeActionCreatorWithoutInput(actionWithoutInput) {
3032
+ if (actionWithoutInput.hasInput) return;
3033
+ const camelCaseActionName = camelCase(actionWithoutInput.name);
3034
+ const constantCaseActionName = constantCase(actionWithoutInput.name);
3035
+ return ts`
3036
+ export const ${camelCaseActionName} = () =>
3037
+ createAction<${makeActionTypeName(actionWithoutInput)}>("${constantCaseActionName}");`.raw;
3038
+ }
3039
+ function makeCreatorsForActionsWithInput(actions) {
3040
+ return actions.filter((a) => a.hasInput).map(makeActionCreatorWithInput).join("\n\n");
3041
+ }
3042
+ function makeActionCreatorsWithoutInput(actions) {
3043
+ return actions.filter((a) => !a.hasInput).map(makeActionCreatorWithoutInput).join("\n\n");
3044
+ }
3045
+ const documentModelOperationsModuleCreatorsFileTemplate = (v) => ts`
3046
+
3047
+ import { ${makeDocumentModelTypeImports(v.actions)} } from "document-model";
3048
+ import {
3049
+ ${makeActionInputSchemaImports(v.actions)}
3050
+ } from '../schema/zod.js';
3051
+ import type {
3052
+ ${makeActionInputTypeImports(v.actions)}
3053
+ } from '../types.js';
3054
+ import type {
3055
+ ${makeActionTypeImports(v.actions)}
3056
+ } from './actions.js';
3057
+
3058
+ ${makeCreatorsForActionsWithInput(v.actions)}
3059
+
3060
+ ${makeActionCreatorsWithoutInput(v.actions)}
3061
+ `.raw;
3062
+ //#endregion
3063
+ //#region src/templates/document-model/gen/modules/error.ts
3064
+ function getErrorName(error) {
3065
+ if (!error.name) return;
3066
+ return pascalCase(error.name);
3067
+ }
3068
+ function getErrorNames(errors) {
3069
+ return errors.map(getErrorName).filter((name) => name !== void 0);
3070
+ }
3071
+ function getErrorCodeType(errors) {
3072
+ return ts`export type ErrorCode = ${getErrorNames(errors).map((name) => `"${name}"`).join(" |\n")};`.raw;
3073
+ }
3074
+ function errorClassTemplate(error) {
3075
+ const errorName = getErrorName(error);
3076
+ if (!errorName) return;
3077
+ return ts`
3078
+ export class ${errorName} extends Error implements ReducerError {
3079
+ errorCode = "${errorName}" as ErrorCode;
3080
+ constructor(message = "${errorName}") {
3081
+ super(message);
3082
+ }
3083
+ }
3084
+ `.raw;
3085
+ }
3086
+ function getErrorClassImplementations(errors) {
3087
+ return errors.map((error) => errorClassTemplate(error)).filter(Boolean).join("\n\n");
3088
+ }
3089
+ function getErrorsImplementations(errors) {
3090
+ if (!errors.length) return "";
3091
+ const deduplicatedErrors = errors.reduce((acc, error) => {
3092
+ if (!acc.some((e) => getErrorName(e) === getErrorName(error))) acc.push(error);
3093
+ return acc;
3094
+ }, new Array());
3095
+ return ts`
3096
+ ${getErrorCodeType(deduplicatedErrors)}
3097
+
3098
+ export interface ReducerError {
3099
+ errorCode: ErrorCode;
3100
+ }
3101
+
3102
+ ${getErrorClassImplementations(deduplicatedErrors)}
3103
+ `.raw;
3104
+ }
3105
+ function getActionErrorsExport(action) {
3106
+ const errors = action.errors;
3107
+ if (errors.length === 0) return;
3108
+ return ts`
3109
+ ${pascalCase(action.name)}: { ${getErrorNames(errors).filter(Boolean).join(",\n")} }
3110
+ `.raw;
3111
+ }
3112
+ function getErrorsExport(actions) {
3113
+ return ts`
3114
+ export const errors = { ${actions.map(getActionErrorsExport).filter(Boolean).join(",\n")} };
3115
+ `.raw;
3116
+ }
3117
+ const documentModelOperationsModuleErrorFileTemplate = (v) => ts`
3118
+ ${getErrorsImplementations(v.errors)}
3119
+ ${getErrorsExport(v.actions)}
3120
+ `.raw;
3121
+ //#endregion
3122
+ //#region src/templates/document-model/gen/modules/operations.ts
3123
+ function getActionTypeNames(actions) {
3124
+ return actions.map(getActionTypeName);
3125
+ }
3126
+ function getActionTypeImports(actions) {
3127
+ return getActionTypeNames(actions).join(",\n");
3128
+ }
3129
+ function getOperationsInterfaceName(pascalCaseDocumentType, module) {
3130
+ return `${pascalCaseDocumentType}${pascalCase(module.name)}Operations`;
3131
+ }
3132
+ function getActionOperationFieldName(action) {
3133
+ return `${camelCase(action.name)}Operation`;
3134
+ }
3135
+ function getActionOperationStateTypeName(action, pascalCaseDocumentType) {
3136
+ if (!action.state) return `${pascalCaseDocumentType}State`;
3137
+ return `${pascalCaseDocumentType}_${pascalCase(action.state)}_State`;
3138
+ }
3139
+ function getActionOperationStateTypeImports(actions, pascalCaseDocumentType) {
3140
+ const stateTypeNames = actions.map((action) => getActionOperationStateTypeName(action, pascalCaseDocumentType));
3141
+ return Array.from(new Set(stateTypeNames)).join(",\n");
3142
+ }
3143
+ function getActionOperationFunction(action, pascalCaseDocumentType) {
3144
+ return ts`
3145
+ (state: ${getActionOperationStateTypeName(action, pascalCaseDocumentType)}, action: ${getActionTypeName(action)}, dispatch?: SignalDispatch) => void
3146
+ `.raw;
3147
+ }
3148
+ function getOperationsInterfaceField(action, pascalCaseDocumentType) {
3149
+ return ts`
3150
+ ${getActionOperationFieldName(action)}: ${getActionOperationFunction(action, pascalCaseDocumentType)}
3151
+ `.raw;
3152
+ }
3153
+ function getOperationsInterfaceFields(actions, pascalCaseDocumentType) {
3154
+ return actions.map((action) => getOperationsInterfaceField(action, pascalCaseDocumentType)).join(",");
3155
+ }
3156
+ const documentModelOperationsModuleOperationsFileTemplate = (v) => ts`
3157
+ import { type SignalDispatch } from 'document-model';
3158
+ import type {
3159
+ ${getActionTypeImports(v.actions)}
3160
+ } from './actions.js';
3161
+ import type {
3162
+ ${getActionOperationStateTypeImports(v.actions, v.pascalCaseDocumentType)}
3163
+ } from "../types.js";
3164
+
3165
+ export interface ${getOperationsInterfaceName(v.pascalCaseDocumentType, v.module)} {
3166
+ ${getOperationsInterfaceFields(v.actions, v.pascalCaseDocumentType)}
3167
+ }
3168
+ `.raw;
3169
+ //#endregion
3170
+ //#region src/templates/document-model/gen/ph-factories.ts
3171
+ const documentModelPhFactoriesFileTemplate = (v) => ts`
3172
+ /**
3173
+ * Factory methods for creating ${v.phDocumentTypeName} instances
3174
+ */
3175
+ import type {
3176
+ PHAuthState,
3177
+ PHDocumentState,
3178
+ PHBaseState,
3179
+ } from "document-model";
3180
+ import {
3181
+ createBaseState,
3182
+ defaultBaseState,
3183
+ } from "document-model";
3184
+ import type {
3185
+ ${v.phDocumentTypeName},
3186
+ ${v.globalStateName},
3187
+ ${v.localStateName},
3188
+ ${v.phStateName},
3189
+ } from "./types.js";
3190
+ import { utils } from "./utils.js";
3191
+
3192
+ export function defaultGlobalState(): ${v.globalStateName} {
3193
+ return ${v.initialGlobalState};
3194
+ }
3195
+
3196
+ export function defaultLocalState(): ${v.localStateName} {
3197
+ return ${v.initialLocalState};
3198
+ }
3199
+
3200
+ export function defaultPHState(): ${v.phStateName} {
3201
+ return {
3202
+ ...defaultBaseState(),
3203
+ global: defaultGlobalState(),
3204
+ local: defaultLocalState(),
3205
+ };
3206
+ }
3207
+
3208
+ export function createGlobalState(
3209
+ state?: Partial<${v.globalStateName}>,
3210
+ ): ${v.globalStateName} {
3211
+ return {
3212
+ ...defaultGlobalState(),
3213
+ ...(state || {}),
3214
+ } as ${v.globalStateName};
3215
+ }
3216
+
3217
+ export function createLocalState(
3218
+ state?: Partial<${v.localStateName}>,
3219
+ ): ${v.localStateName} {
3220
+ return {
3221
+ ...defaultLocalState(),
3222
+ ...(state || {}),
3223
+ } as ${v.localStateName};
3224
+ }
3225
+
3226
+ export function createState(
3227
+ baseState?: Partial<PHBaseState>,
3228
+ globalState?: Partial<${v.globalStateName}>,
3229
+ localState?: Partial<${v.localStateName}>,
3230
+ ): ${v.phStateName} {
3231
+ return {
3232
+ ...createBaseState(baseState?.auth, baseState?.document),
3233
+ global: createGlobalState(globalState),
3234
+ local: createLocalState(localState),
3235
+ };
3236
+ }
3237
+
3238
+ /**
3239
+ * Creates a ${v.phDocumentTypeName} with custom global and local state
3240
+ * This properly handles the PHBaseState requirements while allowing
3241
+ * document-specific state to be set.
3242
+ */
3243
+ export function create${v.phDocumentTypeName}(
3244
+ state?: Partial<{
3245
+ auth?: Partial<PHAuthState>;
3246
+ document?: Partial<PHDocumentState>;
3247
+ global?: Partial<${v.globalStateName}>;
3248
+ local?: Partial<${v.localStateName}>;
3249
+ }>,
3250
+ ): ${v.phDocumentTypeName} {
3251
+ const document = utils.createDocument(
3252
+ state ? createState(
3253
+ createBaseState(state.auth, state.document),
3254
+ state.global,
3255
+ state.local,
3256
+ ) : undefined
3257
+ );
3258
+
3259
+ return document;
3260
+ }
3261
+ `.raw;
3262
+ //#endregion
3263
+ //#region src/templates/document-model/gen/reducer.ts
3264
+ function makePascalCaseOperationName(operation) {
3265
+ if (!operation.name) throw new Error("Operation is missing name");
3266
+ return pascalCase(operation.name);
3267
+ }
3268
+ function makeCamelCaseOperationName(operation) {
3269
+ if (!operation.name) throw new Error("Operation is missing name");
3270
+ return camelCase(operation.name);
3271
+ }
3272
+ function makeConstantCaseOperationName(operation) {
3273
+ if (!operation.name) throw new Error("Operation is missing name");
3274
+ return constantCase(operation.name);
3275
+ }
3276
+ function makeOperationInputSchema(operation) {
3277
+ return `${makePascalCaseOperationName(operation)}InputSchema`;
3278
+ }
3279
+ function makeOperationInputSchemaImports(modules) {
3280
+ return `import { ${modules.flatMap((module) => module.operations.map(makeOperationInputSchema)).join(",\n")} } from "./schema/zod.js";`;
3281
+ }
3282
+ function makeModuleOperationsImport(module, camelCaseDocumentType) {
3283
+ return `import { ${camelCaseDocumentType}${pascalCase(module.name)}Operations } from "../src/reducers/${kebabCase(module.name)}.js";`;
3284
+ }
3285
+ function makeModulesOperationsImports(modules, camelCaseDocumentType) {
3286
+ return modules.map((module) => makeModuleOperationsImport(module, camelCaseDocumentType)).join("\n");
3287
+ }
3288
+ function makeOperationInputSchemaInvocation(operation) {
3289
+ const operationInputSchema = makeOperationInputSchema(operation);
3290
+ const constantCaseOperationName = makeConstantCaseOperationName(operation);
3291
+ if (operation.schema === null) return ts`
3292
+ if (Object.keys(action.input).length > 0) throw new Error("Expected empty input for action ${constantCaseOperationName}");
3293
+ `.raw;
3294
+ return ts`${operationInputSchema}().parse(action.input);`.raw;
3295
+ }
3296
+ function makeOperationsObjectName(module, camelCaseDocumentType) {
3297
+ return `${camelCaseDocumentType}${pascalCase(module.name)}Operations`;
3298
+ }
3299
+ function makeOperationName(operation) {
3300
+ return `${makeCamelCaseOperationName(operation)}Operation`;
3301
+ }
3302
+ function makeOperationInvocation(module, operation, camelCaseDocumentType) {
3303
+ return ts`
3304
+ ${makeOperationsObjectName(module, camelCaseDocumentType)}.${makeOperationName(operation)}((state as any)[action.scope], action as any, dispatch);
3305
+ `.raw;
3306
+ }
3307
+ function makeModuleOperationCaseStatement(module, camelCaseDocumentType) {
3308
+ return module.operations.map((operation) => ts`
3309
+ case "${makeConstantCaseOperationName(operation)}": {
3310
+ ${makeOperationInputSchemaInvocation(operation)}
3311
+ ${makeOperationInvocation(module, operation, camelCaseDocumentType)}
3312
+ break;
3313
+ }
3314
+ `.raw);
3315
+ }
3316
+ function makeModuleOperationsCaseStatements(modules, camelCaseDocumentType) {
3317
+ return modules.map((module) => makeModuleOperationCaseStatement(module, camelCaseDocumentType).join("\n")).join("\n");
3318
+ }
3319
+ const documentModelGenReducerFileTemplate = (v) => ts`
3320
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3321
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
3322
+ import type { Reducer, StateReducer } from "document-model";
3323
+ import { isDocumentAction, createReducer } from "document-model";
3324
+ import type { ${v.phStateName} } from "${v.versionedDocumentModelPackageImportPath}";
3325
+
3326
+ ${makeModulesOperationsImports(v.modules, v.camelCaseDocumentType)}
3327
+
3328
+ ${makeOperationInputSchemaImports(v.modules)}
3329
+
3330
+ const stateReducer: StateReducer<${v.phStateName}> =
3331
+ (state, action, dispatch) => {
3332
+ if (isDocumentAction(action)) {
3333
+ return state;
3334
+ }
3335
+ switch (action.type) {
3336
+ ${makeModuleOperationsCaseStatements(v.modules, v.camelCaseDocumentType)}
3337
+ default:
3338
+ return state;
3339
+ }
3340
+ }
3341
+
3342
+ export const reducer: Reducer<${v.phStateName}> = createReducer(stateReducer);
3343
+ `.raw;
3344
+ //#endregion
3345
+ //#region src/templates/document-model/gen/schema/index.ts
3346
+ const documentModelSchemaIndexTemplate = ts`
3347
+ export * from "./types.js";
3348
+ export * from "./zod.js";
3349
+ `.raw;
3350
+ //#endregion
3351
+ //#region src/templates/document-model/gen/types.ts
3352
+ function buildEmptyLocalStateType(hasLocalSchema, localStateName) {
3353
+ if (hasLocalSchema) return "";
3354
+ return `type ${localStateName} = Record<PropertyKey, never>;`;
3355
+ }
3356
+ function buildLocalStateTypeImport(hasLocalSchema, localStateName) {
3357
+ if (!hasLocalSchema) return "";
3358
+ return localStateName;
3359
+ }
3360
+ const documentModelGenTypesTemplate = (v) => ts`
3361
+ import type { PHDocument, PHBaseState } from 'document-model';
3362
+ import type { ${v.actionTypeName} } from './actions.js';
3363
+ import type {
3364
+ ${v.stateName} as ${v.globalStateName},
3365
+ ${buildLocalStateTypeImport(v.hasLocalSchema, v.localStateName)}
3366
+ } from './schema/types.js';
3367
+
3368
+ ${buildEmptyLocalStateType(v.hasLocalSchema, v.localStateName)}
3369
+
3370
+ type ${v.phStateName} = PHBaseState & {
3371
+ global: ${v.globalStateName};
3372
+ local: ${v.localStateName};
3373
+ };
3374
+ type ${v.phDocumentTypeName} = PHDocument<${v.phStateName}>;
3375
+
3376
+ export * from './schema/types.js';
3377
+
3378
+ export type {
3379
+ ${v.globalStateName},
3380
+ ${v.localStateName},
3381
+ ${v.phStateName},
3382
+ ${v.actionTypeName},
3383
+ ${v.phDocumentTypeName},
3384
+ };
3385
+ `.raw;
3386
+ //#endregion
3387
+ //#region src/templates/document-model/gen/utils.ts
3388
+ const documentModelGenUtilsTemplate = (v) => ts`
3389
+ import type {
3390
+ DocumentModelUtils,
3391
+ } from "document-model";
3392
+ import {
3393
+ baseCreateDocument,
3394
+ baseSaveToFileHandle,
3395
+ baseLoadFromInput,
3396
+ defaultBaseState,
3397
+ generateId,
3398
+ } from "document-model";
3399
+ import { reducer } from './reducer.js';
3400
+ import { ${v.documentTypeVariableName} } from "./document-type.js";
3401
+ import {
3402
+ ${v.assertIsPhDocumentOfTypeFunctionName},
3403
+ ${v.assertIsPhStateOfTypeFunctionName},
3404
+ ${v.isPhDocumentOfTypeFunctionName},
3405
+ ${v.isPhStateOfTypeFunctionName},
3406
+ } from "./document-schema.js";
3407
+ import type { ${v.globalStateName}, ${v.localStateName}, ${v.phStateName} } from './types.js';
3408
+
3409
+ export const initialGlobalState: ${v.globalStateName} = ${v.initialGlobalState};
3410
+ export const initialLocalState: ${v.localStateName} = ${v.initialLocalState};
3411
+
3412
+ export const utils: DocumentModelUtils<${v.phStateName}> = {
3413
+ fileExtension: "${v.fileExtension}",
3414
+ createState(state) {
3415
+ return { ...defaultBaseState(), global: { ...initialGlobalState, ...state?.global }, local: { ...initialLocalState, ...state?.local } };
3416
+ },
3417
+ createDocument(state) {
3418
+ const document = baseCreateDocument(
3419
+ utils.createState,
3420
+ state
3421
+ );
3422
+
3423
+ document.header.documentType = ${v.documentTypeVariableName};
3424
+
3425
+ // for backwards compatibility, but this is NOT a valid signed document id
3426
+ document.header.id = generateId();
3427
+
3428
+ return document;
3429
+ },
3430
+ saveToFileHandle(document, input) {
3431
+ return baseSaveToFileHandle(document, input);
3432
+ },
3433
+ loadFromInput(input) {
3434
+ return baseLoadFromInput(input, reducer);
3435
+ },
3436
+ isStateOfType(state) {
3437
+ return ${v.isPhStateOfTypeFunctionName}(state);
3438
+ },
3439
+ assertIsStateOfType(state) {
3440
+ return ${v.assertIsPhStateOfTypeFunctionName}(state);
3441
+ },
3442
+ isDocumentOfType(document) {
3443
+ return ${v.isPhDocumentOfTypeFunctionName}(document);
3444
+ },
3445
+ assertIsDocumentOfType(document) {
3446
+ return ${v.assertIsPhDocumentOfTypeFunctionName}(document);
3447
+ },
3448
+ };
3449
+ `.raw;
3450
+ //#endregion
3451
+ //#region src/templates/document-model/hooks.ts
3452
+ const documentModelHooksFileTemplate = (v) => ts`
3453
+
3454
+ import type { DocumentDispatch } from "@powerhousedao/reactor-browser";
3455
+ import {
3456
+ useDocumentById,
3457
+ useDocumentsInSelectedDrive,
3458
+ useDocumentsInSelectedFolder,
3459
+ useSelectedDocument,
3460
+ } from "@powerhousedao/reactor-browser";
3461
+ import type {
3462
+ ${v.actionTypeName},
3463
+ ${v.phDocumentTypeName},
3464
+ } from "${v.versionedDocumentModelPackageImportPath}";
3465
+ import {
3466
+ ${v.assertIsPhDocumentOfTypeFunctionName},
3467
+ ${v.isPhDocumentOfTypeFunctionName}
3468
+ } from "./gen/document-schema.js";
3469
+
3470
+ /** Hook to get a ${v.pascalCaseDocumentType} document by its id */
3471
+ export function ${v.useByIdHookName}(
3472
+ documentId: string | null | undefined,
3473
+ ):
3474
+ | [${v.phDocumentTypeName}, DocumentDispatch<${v.actionTypeName}>]
3475
+ | [undefined, undefined] {
3476
+ const [document, dispatch] = useDocumentById(documentId);
3477
+ if (!${v.isPhDocumentOfTypeFunctionName}(document)) return [undefined, undefined];
3478
+ return [document, dispatch];
3479
+ }
3480
+
3481
+ /** Hook to get the selected ${v.pascalCaseDocumentType} document */
3482
+ export function ${v.useSelectedHookName}():
3483
+ | [${v.phDocumentTypeName}, DocumentDispatch<${v.actionTypeName}>] {
3484
+ const [document, dispatch] = useSelectedDocument();
3485
+
3486
+ ${v.assertIsPhDocumentOfTypeFunctionName}(document);
3487
+ return [document, dispatch] as const;
3488
+ }
3489
+
3490
+ /** Hook to get all ${v.pascalCaseDocumentType} documents in the selected drive */
3491
+ export function ${v.useInSelectedDriveHookName}() {
3492
+ const documentsInSelectedDrive = useDocumentsInSelectedDrive();
3493
+ return documentsInSelectedDrive?.filter(${v.isPhDocumentOfTypeFunctionName});
3494
+ }
3495
+
3496
+ /** Hook to get all ${v.pascalCaseDocumentType} documents in the selected folder */
3497
+ export function ${v.useInSelectedFolderHookName}() {
3498
+ const documentsInSelectedFolder = useDocumentsInSelectedFolder();
3499
+ return documentsInSelectedFolder?.filter(${v.isPhDocumentOfTypeFunctionName});
3500
+ }
3501
+ `.raw;
3502
+ //#endregion
3503
+ //#region src/templates/document-model/index.ts
3504
+ const documentModelIndexTemplate = ts`
3505
+ export * from "./gen/index.js";
3506
+ export * from "./src/index.js";
3507
+ export * from "./hooks.js";
3508
+ export { actions } from "./actions.js";
3509
+ export { utils } from "./utils.js";
3510
+ `.raw;
3511
+ //#endregion
3512
+ //#region src/templates/document-model/module.ts
3513
+ function documentModelModuleFileTemplate({ phStateName, pascalCaseDocumentType, version }) {
3514
+ return ts`
3515
+ import type { DocumentModelModule } from "document-model";
3516
+ import { createState, defaultBaseState } from "document-model";
3517
+ import type { ${phStateName} } from "./gen/types.js";
3518
+ import { documentModel } from "./gen/document-model.js";
3519
+ import { reducer } from "./gen/reducer.js";
3520
+ import { actions } from "./actions.js";
3521
+ import { utils } from "./utils.js";
3522
+
3523
+ /** Document model module for the ${pascalCaseDocumentType} document type */
3524
+ export const ${pascalCaseDocumentType}: DocumentModelModule<${phStateName}> = {
3525
+ version: ${version},
3526
+ reducer,
3527
+ actions,
3528
+ utils,
3529
+ documentModel: createState(defaultBaseState(), documentModel),
3530
+ };
3531
+ `.raw;
3532
+ }
3533
+ //#endregion
3534
+ //#region src/templates/document-model/src/index.ts
3535
+ const documentModelSrcIndexFileTemplate = ts`
3536
+ export * from "./utils.js";
3537
+ `.raw;
3538
+ //#endregion
3539
+ //#region src/templates/document-model/tests/document-model.test.ts
3540
+ const documentModelTestFileTemplate = (v) => ts`
3541
+ /**
3542
+ * This is a scaffold file meant for customization:
3543
+ * - change it by adding new tests or modifying the existing ones
3544
+ */
3545
+ /**
3546
+ * This is a scaffold file meant for customization:
3547
+ * - change it by adding new tests or modifying the existing ones
3548
+ */
3549
+
3550
+ import { describe, it, expect } from "vitest";
3551
+ import {
3552
+ utils,
3553
+ initialGlobalState,
3554
+ initialLocalState,
3555
+ ${v.documentTypeVariableName},
3556
+ ${v.isPhDocumentOfTypeFunctionName},
3557
+ ${v.assertIsPhDocumentOfTypeFunctionName},
3558
+ ${v.isPhStateOfTypeFunctionName},
3559
+ ${v.assertIsPhStateOfTypeFunctionName},
3560
+ } from "${v.versionedDocumentModelPackageImportPath}";
3561
+ import { ZodError } from "zod";
3562
+
3563
+ describe("${v.pascalCaseDocumentType} Document Model", () => {
3564
+ it("should create a new ${v.pascalCaseDocumentType} document", () => {
3565
+ const document = utils.createDocument();
3566
+
3567
+ expect(document).toBeDefined();
3568
+ expect(document.header.documentType).toBe(${v.documentTypeVariableName});
3569
+ });
3570
+
3571
+ it("should create a new ${v.pascalCaseDocumentType} document with a valid initial state", () => {
3572
+ const document = utils.createDocument();
3573
+ expect(document.state.global).toStrictEqual(initialGlobalState);
3574
+ expect(document.state.local).toStrictEqual(initialLocalState);
3575
+ expect(${v.isPhDocumentOfTypeFunctionName}(document)).toBe(true);
3576
+ expect(${v.isPhStateOfTypeFunctionName}(document.state)).toBe(true);
3577
+ });
3578
+ it("should reject a document that is not a ${v.pascalCaseDocumentType} document", () => {
3579
+ const wrongDocumentType = utils.createDocument();
3580
+ wrongDocumentType.header.documentType = "the-wrong-thing-1234";
3581
+ try {
3582
+ expect(${v.assertIsPhDocumentOfTypeFunctionName}(wrongDocumentType)).toThrow();
3583
+ expect(${v.isPhDocumentOfTypeFunctionName}(wrongDocumentType)).toBe(false);
3584
+ } catch (error) {
3585
+ expect(error).toBeInstanceOf(ZodError);
3586
+ }
3587
+ });
3588
+ const wrongState = utils.createDocument();
3589
+ // @ts-expect-error - we are testing the error case
3590
+ wrongState.state.global = {
3591
+ ...{ notWhat: "you want" },
3592
+ };
3593
+ try {
3594
+ expect(${v.isPhStateOfTypeFunctionName}(wrongState.state)).toBe(false);
3595
+ expect(${v.assertIsPhStateOfTypeFunctionName}(wrongState.state)).toThrow();
3596
+ expect(${v.isPhDocumentOfTypeFunctionName}(wrongState)).toBe(false);
3597
+ expect(${v.assertIsPhDocumentOfTypeFunctionName}(wrongState)).toThrow();
3598
+ } catch (error) {
3599
+ expect(error).toBeInstanceOf(ZodError);
3600
+ }
3601
+
3602
+ const wrongInitialState = utils.createDocument();
3603
+ // @ts-expect-error - we are testing the error case
3604
+ wrongInitialState.initialState.global = {
3605
+ ...{ notWhat: "you want" },
3606
+ };
3607
+ try {
3608
+ expect(${v.isPhStateOfTypeFunctionName}(wrongInitialState.state)).toBe(false);
3609
+ expect(${v.assertIsPhStateOfTypeFunctionName}(wrongInitialState.state)).toThrow();
3610
+ expect(${v.isPhDocumentOfTypeFunctionName}(wrongInitialState)).toBe(false);
3611
+ expect(${v.assertIsPhDocumentOfTypeFunctionName}(wrongInitialState)).toThrow();
3612
+ } catch (error) {
3613
+ expect(error).toBeInstanceOf(ZodError);
3614
+ }
3615
+
3616
+ const missingIdInHeader = utils.createDocument();
3617
+ // @ts-expect-error - we are testing the error case
3618
+ delete missingIdInHeader.header.id;
3619
+ try {
3620
+ expect(${v.isPhDocumentOfTypeFunctionName}(missingIdInHeader)).toBe(false);
3621
+ expect(${v.assertIsPhDocumentOfTypeFunctionName}(missingIdInHeader)).toThrow();
3622
+ } catch (error) {
3623
+ expect(error).toBeInstanceOf(ZodError);
3624
+ }
3625
+
3626
+ const missingNameInHeader = utils.createDocument();
3627
+ // @ts-expect-error - we are testing the error case
3628
+ delete missingNameInHeader.header.name;
3629
+ try {
3630
+ expect(${v.isPhDocumentOfTypeFunctionName}(missingNameInHeader)).toBe(false);
3631
+ expect(${v.assertIsPhDocumentOfTypeFunctionName}(missingNameInHeader)).toThrow();
3632
+ } catch (error) {
3633
+ expect(error).toBeInstanceOf(ZodError);
3634
+ }
3635
+
3636
+ const missingCreatedAtUtcIsoInHeader = utils.createDocument();
3637
+ // @ts-expect-error - we are testing the error case
3638
+ delete missingCreatedAtUtcIsoInHeader.header.createdAtUtcIso;
3639
+ try {
3640
+ expect(${v.isPhDocumentOfTypeFunctionName}(missingCreatedAtUtcIsoInHeader)).toBe(false);
3641
+ expect(${v.assertIsPhDocumentOfTypeFunctionName}(missingCreatedAtUtcIsoInHeader)).toThrow();
3642
+ } catch (error) {
3643
+ expect(error).toBeInstanceOf(ZodError);
3644
+ }
3645
+
3646
+ const missingLastModifiedAtUtcIsoInHeader = utils.createDocument();
3647
+ // @ts-expect-error - we are testing the error case
3648
+ delete missingLastModifiedAtUtcIsoInHeader.header.lastModifiedAtUtcIso;
3649
+ try {
3650
+ expect(${v.isPhDocumentOfTypeFunctionName}(missingLastModifiedAtUtcIsoInHeader)).toBe(false);
3651
+ expect(
3652
+ ${v.assertIsPhDocumentOfTypeFunctionName}(missingLastModifiedAtUtcIsoInHeader),
3653
+ ).toThrow();
3654
+ } catch (error) {
3655
+ expect(error).toBeInstanceOf(ZodError);
3656
+ }
3657
+ });
3658
+ `.raw;
3659
+ //#endregion
3660
+ //#region src/templates/document-model/tests/module.test.ts
3661
+ function makeModuleOperationsTypeName(module) {
3662
+ return `${pascalCase(module.name)}Operations`;
3663
+ }
3664
+ function makeCamelCaseActionNamesForImport(actions) {
3665
+ return actions.map((a) => camelCase(a.name));
3666
+ }
3667
+ function makeActionInputSchemasForImport(actions) {
3668
+ return actions.map((a) => `${pascalCase(a.name)}InputSchema`);
3669
+ }
3670
+ function makeTestCaseForAction(action, isPhDocumentOfTypeFunctionName) {
3671
+ const camelCaseActionName = camelCase(action.name);
3672
+ const pascalCaseActionName = pascalCase(action.name);
3673
+ const constantCaseActionName = constantCase(action.name);
3674
+ const actionInputSchemaName = `${pascalCaseActionName}InputSchema`;
3675
+ const scope = action.scope;
3676
+ return ts`
3677
+ it('should handle ${camelCaseActionName} operation', () => {
3678
+ const document = utils.createDocument();
3679
+ const input = generateMock(
3680
+ ${actionInputSchemaName}(),
3681
+ );
3682
+
3683
+ const updatedDocument = reducer(
3684
+ document,
3685
+ ${camelCaseActionName}(input),
3686
+ );
3687
+
3688
+ expect(${isPhDocumentOfTypeFunctionName}(updatedDocument)).toBe(true);
3689
+ expect(updatedDocument.operations.${scope}).toHaveLength(1);
3690
+ expect(updatedDocument.operations.${scope}[0].action.type).toBe(
3691
+ "${constantCaseActionName}",
3692
+ );
3693
+ expect(updatedDocument.operations.${scope}[0].action.input).toStrictEqual(input);
3694
+ expect(updatedDocument.operations.${scope}[0].index).toEqual(0);
3695
+ });
3696
+ `.raw;
3697
+ }
3698
+ function makeActionImportNames(v) {
3699
+ const actionNames = makeCamelCaseActionNamesForImport(v.actions);
3700
+ const inputSchemaNames = makeActionInputSchemasForImport(v.actions);
3701
+ return [
3702
+ "reducer",
3703
+ "utils",
3704
+ v.isPhDocumentOfTypeFunctionName,
3705
+ ...actionNames,
3706
+ ...inputSchemaNames
3707
+ ];
3708
+ }
3709
+ function makeActionsImports(v) {
3710
+ return ts`
3711
+ import {
3712
+ ${makeActionImportNames(v).join("\n")}
3713
+ } from "${v.versionedDocumentModelPackageImportPath}";
3714
+ `.raw;
3715
+ }
3716
+ function makeTestCasesForActions(actions, isPhDocumentOfTypeFunctionName) {
3717
+ return actions.map((action) => makeTestCaseForAction(action, isPhDocumentOfTypeFunctionName)).join("\n\n");
3718
+ }
3719
+ const documentModelOperationsModuleTestFileTemplate = (v) => ts`
3720
+ /**
3721
+ * This is a scaffold file meant for customization:
3722
+ * - change it by adding new tests or modifying the existing ones
3723
+ */
3724
+
3725
+ import { describe, it, expect } from 'vitest';
3726
+ import { generateMock } from '@powerhousedao/common';
3727
+ import {
3728
+ reducer,
3729
+ utils,
3730
+ ${v.isPhDocumentOfTypeFunctionName},
3731
+ ${makeCamelCaseActionNamesForImport(v.actions)},
3732
+ ${makeActionInputSchemasForImport(v.actions)},
3733
+ } from "${v.versionedDocumentModelPackageImportPath}";
3734
+
3735
+ describe("${makeModuleOperationsTypeName(v.module)}", () => {
3736
+ ${makeTestCasesForActions(v.actions, v.isPhDocumentOfTypeFunctionName)}
3737
+ });
3738
+
3739
+ `.raw;
3740
+ //#endregion
3741
+ //#region src/templates/document-model/src/utils.ts
3742
+ const documentModelSrcUtilsTemplate = ts`
3743
+ export {};
3744
+ `.raw;
3745
+ //#endregion
3746
+ //#region src/templates/document-model/upgrades/upgrade-manifest.ts
3747
+ const upgradeManifestTemplate = (v) => ts`
3748
+ import type { UpgradeManifest } from "document-model";
3749
+ import { latestVersion, supportedVersions } from "./versions.js";
3750
+
3751
+ export const ${v.upgradeManifestName}: UpgradeManifest<typeof supportedVersions> = {
3752
+ documentType: "${v.documentModelId}",
3753
+ latestVersion,
3754
+ supportedVersions,
3755
+ upgrades: {},
3756
+ };
3757
+ `.raw;
3758
+ //#endregion
3759
+ //#region src/templates/document-model/upgrades/upgrade-transition.ts
3760
+ const upgradeTransitionTemplate = (v) => ts`
3761
+ import type { Action, PHDocument, UpgradeTransition } from "document-model";
3762
+ import type { ${v.phStateName} as StateV${v.previousVersion} } from "${v.documentModelPackageImportPath}/v${v.previousVersion}";
3763
+ import type { ${v.phStateName} as StateV${v.version} } from "${v.documentModelPackageImportPath}/v${v.version}";
3764
+
3765
+ function upgradeReducer(
3766
+ document: PHDocument<StateV${v.previousVersion}>,
3767
+ action: Action,
3768
+ ): PHDocument<StateV${v.version}> {
3769
+ return {
3770
+ ...document,
3771
+ };
3772
+ }
3773
+
3774
+ export const v${v.version}: UpgradeTransition = {
3775
+ toVersion: ${v.version},
3776
+ upgradeReducer,
3777
+ description: "",
3778
+ };
3779
+ `.raw;
3780
+ //#endregion
3781
+ //#region src/templates/document-model/utils.ts
3782
+ const documentModelUtilsTemplate = ({ phStateName, pascalCaseDocumentType }) => ts`
3783
+ import type { DocumentModelUtils } from "document-model";
3784
+ import type { ${phStateName} } from "./gen/types.js";
3785
+ import { utils as genUtils } from "./gen/utils.js";
3786
+ import * as customUtils from "./src/utils.js";
3787
+
3788
+ /** Utils for the ${pascalCaseDocumentType} document model */
3789
+ export const utils: DocumentModelUtils<${phStateName}> = { ...genUtils, ...customUtils };
3790
+ `.raw;
3791
+ //#endregion
3792
+ //#region src/templates/drive-editor/components/CreateDocument.ts
3793
+ const createDocumentFileTemplate = tsx`
3794
+ import type { VetraDocumentModelModule } from "@powerhousedao/reactor-browser";
3795
+ import {
3796
+ showCreateDocumentModal,
3797
+ useAllowedDocumentModelModules,
3798
+ } from "@powerhousedao/reactor-browser";
3799
+
3800
+ /**
3801
+ * Document creation UI component.
3802
+ * Displays available document types as clickable buttons.
3803
+ */
3804
+ export function CreateDocument() {
3805
+ const allowedDocumentModelModules = useAllowedDocumentModelModules();
3806
+
3807
+ return (
3808
+ <div>
3809
+ {/* Customize section title here */}
3810
+ <h3 className="mb-3 mt-4 text-sm font-bold text-gray-600">
3811
+ Create document
3812
+ </h3>
3813
+ {/* Customize layout by changing flex-wrap, gap, or grid layout */}
3814
+ <div className="flex w-full flex-wrap gap-4">
3815
+ {allowedDocumentModelModules?.map((documentModelModule) => {
3816
+ return (
3817
+ <CreateDocumentButton
3818
+ key={documentModelModule.documentModel.global.id}
3819
+ documentModelModule={documentModelModule}
3820
+ />
3821
+ );
3822
+ })}
3823
+ </div>
3824
+ </div>
3825
+ );
3826
+ }
3827
+
3828
+ type Props = {
3829
+ documentModelModule: VetraDocumentModelModule;
3830
+ };
3831
+ function CreateDocumentButton({ documentModelModule }: Props) {
3832
+ const documentType = documentModelModule.documentModel.global.id;
3833
+ const documentModelName =
3834
+ documentModelModule.documentModel.global.name || documentType;
3835
+ const documentModelDescription =
3836
+ documentModelModule.documentModel.global.description;
3837
+ return (
3838
+ <button
3839
+ className="cursor-pointer rounded-md bg-gray-200 py-2 px-3 hover:bg-gray-300"
3840
+ title={documentModelName}
3841
+ aria-description={documentModelDescription}
3842
+ onClick={() => showCreateDocumentModal(documentType)}
3843
+ >
3844
+ {documentModelName}
3845
+ </button>
3846
+ );
3847
+ }
3848
+ `.raw;
3849
+ //#endregion
3850
+ //#region src/templates/drive-editor/components/DriveContents.ts
3851
+ const driveEditorDriveContentsFileTemplate = () => tsx`
3852
+ import { CreateDocument } from "./CreateDocument.js";
3853
+ import { EmptyState } from "./EmptyState.js";
3854
+ import { Files } from "./Files.js";
3855
+ import { Folders } from "./Folders.js";
3856
+ import { NavigationBreadcrumbs } from "./NavigationBreadcrumbs.js";
3857
+
3858
+ /** Shows the documents and folders in the selected drive */
3859
+ export function DriveContents() {
3860
+ return (
3861
+ <div className="space-y-6 px-6">
3862
+ <NavigationBreadcrumbs />
3863
+ <Folders />
3864
+ <Files />
3865
+ <EmptyState />
3866
+ <CreateDocument />
3867
+ </div>
3868
+ );
3869
+ }
3870
+
3871
+
3872
+ `.raw;
3873
+ //#endregion
3874
+ //#region src/templates/drive-editor/components/DriveExplorer.ts
3875
+ const driveExplorerFileTemplate = tsx`
3876
+ import type { EditorProps } from "document-model";
3877
+ import { FolderTree } from "./FolderTree.js";
3878
+ import { DriveContents } from "./DriveContents.js";
3879
+
3880
+ /**
3881
+ * Main drive explorer component with sidebar navigation and content area.
3882
+ * Layout: Left sidebar (folder tree) + Right content area (files/folders + document editor)
3883
+ */
3884
+ export function DriveExplorer({ children }: EditorProps) {
3885
+ // if a document is selected then it's editor will be passed as children
3886
+ const showDocumentEditor = !!children;
3887
+
3888
+ return (
3889
+ <div className="flex h-full">
3890
+ <FolderTree />
3891
+ <div className="flex-1 overflow-y-auto p-4">
3892
+ {/* Conditional rendering: Document editor or folder contents */}
3893
+ {showDocumentEditor ? (
3894
+ /* Document editor view */
3895
+ children
3896
+ ) : (
3897
+ /* Folder contents view */
3898
+ <DriveContents />
3899
+ )}
3900
+ </div>
3901
+ </div>
3902
+ );
3903
+ }
3904
+ `.raw;
3905
+ //#endregion
3906
+ //#region src/templates/drive-editor/components/EmptyState.ts
3907
+ const emptyStateFileTemplate = tsx`
3908
+ import { useNodesInSelectedDriveOrFolder } from "@powerhousedao/reactor-browser";
3909
+
3910
+ /** Shows a message when the selected drive or folder is empty */
3911
+ export function EmptyState() {
3912
+ const nodes = useNodesInSelectedDriveOrFolder();
3913
+ const hasNodes = nodes.length > 0;
3914
+ if (hasNodes) return null;
3915
+
3916
+ return (
3917
+ <div className="py-12 text-center text-gray-500">
3918
+ <p className="text-lg">This folder is empty</p>
3919
+ <p className="mt-2 text-sm">Create your first document or folder below</p>
3920
+ </div>
3921
+ );
3922
+ }
3923
+ `.raw;
3924
+ //#endregion
3925
+ //#region src/templates/drive-editor/components/Files.ts
3926
+ const driveEditorFilesFileTemplate = () => tsx`
3927
+ import { FileItem } from "@powerhousedao/design-system/connect";
3928
+ import {
3929
+ useNodesInSelectedDriveOrFolder,
3930
+ isFileNodeKind,
3931
+ } from "@powerhousedao/reactor-browser";
3932
+
3933
+ /** Shows the files in the selected drive or folder */
3934
+ export function Files() {
3935
+ const nodes = useNodesInSelectedDriveOrFolder();
3936
+ const fileNodes = nodes.filter((n) => isFileNodeKind(n));
3937
+ const hasFiles = fileNodes.length > 0;
3938
+
3939
+ if (!hasFiles) return null;
3940
+
3941
+ return (
3942
+ <div>
3943
+ <h3 className="mb-2 text-sm font-semibold text-gray-600">Documents</h3>
3944
+ <div className="flex flex-wrap gap-4">
3945
+ {fileNodes.map((fileNode) => (
3946
+ <FileItem key={fileNode.id} fileNode={fileNode} />
3947
+ ))}
3948
+ </div>
3949
+ </div>
3950
+ );
3951
+ }
3952
+
3953
+ `.raw;
3954
+ //#endregion
3955
+ //#region src/templates/drive-editor/components/Folders.ts
3956
+ const driveEditorFoldersFileTemplate = () => tsx`
3957
+ import { FolderItem } from "@powerhousedao/design-system/connect";
3958
+ import {
3959
+ useNodesInSelectedDriveOrFolder,
3960
+ isFolderNodeKind,
3961
+ } from "@powerhousedao/reactor-browser";
3962
+
3963
+ /** Shows the folders in the selected drive or folder */
3964
+ export function Folders() {
3965
+ const nodes = useNodesInSelectedDriveOrFolder();
3966
+ const folderNodes = nodes.filter((n) => isFolderNodeKind(n));
3967
+ const hasFolders = folderNodes.length > 0;
3968
+ if (!hasFolders) return null;
3969
+
3970
+ return (
3971
+ <div>
3972
+ <h3 className="mb-2 text-sm font-bold text-gray-600">Folders</h3>
3973
+ <div className="flex flex-wrap gap-4">
3974
+ {folderNodes.map((folderNode) => (
3975
+ <FolderItem key={folderNode.id} folderNode={folderNode} />
3976
+ ))}
3977
+ </div>
3978
+ </div>
3979
+ );
3980
+ }
3981
+ `.raw;
3982
+ //#endregion
3983
+ //#region src/templates/drive-editor/components/FolderTree.ts
3984
+ const folderTreeFileTemplate = tsx`
3985
+ import {
3986
+ Sidebar,
3987
+ SidebarProvider,
3988
+ type SidebarNode,
3989
+ } from "@powerhousedao/document-engineering";
3990
+ import {
3991
+ setSelectedNode,
3992
+ useNodesInSelectedDrive,
3993
+ useSelectedDrive,
3994
+ useSelectedNode,
3995
+ } from "@powerhousedao/reactor-browser";
3996
+ import type { Node } from "@powerhousedao/shared/document-drive";
3997
+ import { useMemo } from "react";
3998
+
3999
+ function buildSidebarNodes(
4000
+ nodes: Node[],
4001
+ parentId: string | null | undefined,
4002
+ ): SidebarNode[] {
4003
+ return nodes
4004
+ .filter((n) => {
4005
+ if (parentId == null) {
4006
+ return n.parentFolder == null;
4007
+ }
4008
+ return n.parentFolder === parentId;
4009
+ })
4010
+ .map((node): SidebarNode => {
4011
+ if (node.kind === "folder") {
4012
+ return {
4013
+ id: node.id,
4014
+ title: node.name,
4015
+ icon: "FolderClose" as const,
4016
+ expandedIcon: "FolderOpen" as const,
4017
+ children: buildSidebarNodes(nodes, node.id),
4018
+ };
4019
+ }
4020
+ return {
4021
+ id: node.id,
4022
+ title: node.name,
4023
+ icon: "File" as const,
4024
+ };
4025
+ });
4026
+ }
4027
+
4028
+ function transformNodesToSidebarNodes(
4029
+ nodes: Node[],
4030
+ driveName: string,
4031
+ ): SidebarNode[] {
4032
+ return [
4033
+ {
4034
+ id: "root",
4035
+ title: driveName,
4036
+ icon: "Drive" as const,
4037
+ children: buildSidebarNodes(nodes, null),
4038
+ },
4039
+ ];
4040
+ }
4041
+
4042
+ /**
4043
+ * Hierarchical folder tree navigation component using Sidebar from document-engineering.
4044
+ * Displays folders and files in a tree structure with expand/collapse functionality, search, and resize support.
4045
+ */
4046
+ export function FolderTree() {
4047
+ const [selectedDrive] = useSelectedDrive();
4048
+ const nodes = useNodesInSelectedDrive();
4049
+ const selectedNode = useSelectedNode();
4050
+ const driveName = selectedDrive.header.name;
4051
+ // Transform Node[] to hierarchical SidebarNode structure
4052
+ const sidebarNodes = useMemo(
4053
+ () => transformNodesToSidebarNodes(nodes || [], driveName),
4054
+ [nodes, driveName],
4055
+ );
4056
+
4057
+ const handleActiveNodeChange = (node: SidebarNode) => {
4058
+ // If root node is selected, pass undefined to match existing behavior
4059
+ if (node.id === "root") {
4060
+ setSelectedNode(undefined);
4061
+ } else {
4062
+ setSelectedNode(node.id);
4063
+ }
4064
+ };
4065
+ // Map selectedNodeId to activeNodeId (use "root" when undefined)
4066
+ const activeNodeId =
4067
+ !selectedNode || selectedNode.id === selectedDrive.header.id
4068
+ ? "root"
4069
+ : selectedNode.id;
4070
+
4071
+ return (
4072
+ <SidebarProvider nodes={sidebarNodes}>
4073
+ <Sidebar
4074
+ className="pt-1"
4075
+ nodes={sidebarNodes}
4076
+ activeNodeId={activeNodeId}
4077
+ onActiveNodeChange={handleActiveNodeChange}
4078
+ sidebarTitle="Drive Explorer"
4079
+ showSearchBar={true}
4080
+ resizable={true}
4081
+ allowPinning={false}
4082
+ showStatusFilter={false}
4083
+ initialWidth={256}
4084
+ defaultLevel={2}
4085
+ />
4086
+ </SidebarProvider>
4087
+ );
4088
+ }
4089
+ `.raw;
4090
+ //#endregion
4091
+ //#region src/templates/drive-editor/components/NavigationBreadcrumbs.ts
4092
+ const driveExplorerNavigationBreadcrumbsFileTemplate = () => tsx`
4093
+ import { Breadcrumbs } from "@powerhousedao/design-system/connect";
4094
+
4095
+ /** Shows the navigation breadcrumbs for the selected drive or folder */
4096
+ export function NavigationBreadcrumbs() {
4097
+ return (
4098
+ <div className="border-b border-gray-200 pb-3 space-y-3">
4099
+ <Breadcrumbs />
4100
+ </div>
4101
+ );
4102
+ }
4103
+ `.raw;
4104
+ //#endregion
4105
+ //#region src/templates/drive-editor/config.ts
4106
+ const driveEditorConfigFileTemplate = (v) => ts`
4107
+ import type { PHDriveEditorConfig } from "@powerhousedao/reactor-browser";
4108
+
4109
+ /** Editor config for the <%= pascalCaseDriveEditorName %> */
4110
+ export const editorConfig: PHDriveEditorConfig = {
4111
+ isDragAndDropEnabled: ${v.isDragAndDropEnabledString},
4112
+ allowedDocumentTypes: ${v.allowedDocumentTypesString}
4113
+ };
4114
+ `.raw;
4115
+ //#endregion
4116
+ //#region src/templates/drive-editor/editor.ts
4117
+ const driveEditorEditorFileTemplate = () => tsx`
4118
+ import { useSetPHDriveEditorConfig } from "@powerhousedao/reactor-browser";
4119
+ import type { EditorProps } from "document-model";
4120
+ import { DriveExplorer } from "./components/DriveExplorer.js";
4121
+ import { editorConfig } from "./config.js";
4122
+
4123
+ /** Editor component for the drive editor */
4124
+ export default function Editor(props: EditorProps) {
4125
+ // set the config for this drive editor
4126
+ // you can update these configs in \`./config.ts\`
4127
+ useSetPHDriveEditorConfig(editorConfig);
4128
+ return (
4129
+ <div className="bg-gray-50 p-6">
4130
+ <DriveExplorer {...props} />
4131
+ </div>
4132
+ );
4133
+ }
4134
+ `.raw;
4135
+ //#endregion
4136
+ //#region src/templates/processors/utils.ts
4137
+ function getDocumentType(documentTypes) {
4138
+ if (!documentTypes.length) return `"*"`;
4139
+ return documentTypes.map((type) => `"${type}"`).join(", ");
4140
+ }
4141
+ //#endregion
4142
+ //#region src/templates/processors/analytics/factory.ts
4143
+ const analyticsFactoryTemplate = (v) => ts`
4144
+ import type {
4145
+ ProcessorApp,
4146
+ ProcessorFactoryBuilder,
4147
+ ProcessorRecord,
4148
+ IProcessorHostModule,
4149
+ } from "@powerhousedao/reactor-browser";
4150
+ import { type PHDocumentHeader } from "document-model";
4151
+ import { ${v.pascalCaseName} } from "./processor.js";
4152
+
4153
+ export const ${v.camelCaseName}FactoryBuilder: ProcessorFactoryBuilder = (module: IProcessorHostModule) => async (driveHeader: PHDocumentHeader, processorApp?: ProcessorApp) => {
4154
+ return [
4155
+ {
4156
+ processor: new ${v.pascalCaseName}(module.analyticsStore),
4157
+ filter: {
4158
+ branch: ["main"],
4159
+ documentId: ["*"],
4160
+ scope: ["*"],
4161
+ documentType: [${getDocumentType(v.documentTypes)}],
4162
+ },
4163
+ },
4164
+ ];
4165
+ }
4166
+ `.raw;
4167
+ //#endregion
4168
+ //#region src/templates/processors/analytics/processor.ts
4169
+ const analyticsProcessorTemplate = (v) => ts`
4170
+ import type { AnalyticsSeriesInput, AnalyticsPath, IAnalyticsStore } from "@powerhousedao/analytics-engine-core";
4171
+ import type { OperationWithContext, IProcessor } from "@powerhousedao/reactor-browser";
4172
+
4173
+ export class ${v.pascalCaseName} implements IProcessor {
4174
+ private readonly NAMESPACE = "${v.pascalCaseName}";
4175
+
4176
+ private readonly inputs: AnalyticsSeriesInput[] = [];
4177
+
4178
+ constructor(private readonly analyticsStore: IAnalyticsStore) {
4179
+ //
4180
+ }
4181
+
4182
+ onOperations(operations: OperationWithContext[]): Promise<void> {
4183
+ return Promise.resolve();
4184
+ }
4185
+
4186
+ onDisconnect(): Promise<void> {
4187
+ return Promise.resolve();
4188
+ }
4189
+
4190
+ private async clearSource(source: AnalyticsPath) {
4191
+ try {
4192
+ await this.analyticsStore.clearSeriesBySource(source, true);
4193
+ } catch (e) {
4194
+ console.error(e);
4195
+ }
4196
+ }
4197
+ }
4198
+ `.raw;
4199
+ //#endregion
4200
+ //#region src/templates/processors/analytics/index.ts
4201
+ const analyticsIndexTemplate = ts`
4202
+ export * from "./factory.js";
4203
+ export * from "./processor.js";
4204
+ `.raw;
4205
+ //#endregion
4206
+ //#region src/templates/processors/factory.ts
4207
+ const processorsFactoryTemplate = ts`
4208
+ /**
4209
+ * This file aggregates all processor factories
4210
+ * Auto-generated by codegen - DO NOT EDIT MANUALLY
4211
+ */
4212
+
4213
+ import type {
4214
+ IProcessorHostModule,
4215
+ ProcessorRecord,
4216
+ } from "@powerhousedao/reactor-browser";
4217
+ import type { PHDocumentHeader } from "document-model";
4218
+
4219
+ export const processorFactory = async (module: IProcessorHostModule) => {
4220
+ const { processorFactoryBuilders } =
4221
+ module.processorApp === "connect"
4222
+ ? await import("./connect.js")
4223
+ : await import("./switchboard.js");
4224
+
4225
+ const factories = await Promise.all(
4226
+ processorFactoryBuilders.map(
4227
+ async (buildFactory) => await buildFactory(module),
4228
+ ),
4229
+ );
4230
+
4231
+ // Return the inner function that will be called for each drive
4232
+ return async (driveHeader: PHDocumentHeader): Promise<ProcessorRecord[]> => {
4233
+ const processors: ProcessorRecord[] = [];
4234
+
4235
+ // Call each cached factory with the driveHeader
4236
+ for (const factory of factories) {
4237
+ const factoryProcessors = await factory(driveHeader, module.processorApp);
4238
+ processors.push(...factoryProcessors);
4239
+ }
4240
+
4241
+ return processors;
4242
+ };
4243
+ };
4244
+ `.raw;
4245
+ //#endregion
4246
+ //#region src/templates/processors/factory-builders.ts
4247
+ const factoryBuildersTemplate = ts`
4248
+ import type { ProcessorFactoryBuilder } from "@powerhousedao/reactor";
4249
+
4250
+ export const processorFactoryBuilders: ProcessorFactoryBuilder[] = [];
4251
+ `.raw;
4252
+ //#endregion
4253
+ //#region src/templates/processors/index.ts
4254
+ const processorsIndexTemplate = ts`
4255
+ /**
4256
+ * Processor exports
4257
+ * This file is auto-generated and updated by codegen
4258
+ */
4259
+
4260
+ export { processorFactory } from "./factory.js";
4261
+ `.raw;
4262
+ //#endregion
4263
+ //#region src/templates/processors/relational-db/factory.ts
4264
+ const relationalDbFactoryTemplate = (v) => ts`
4265
+ import type {
4266
+ IProcessorHostModule,
4267
+ ProcessorApp,
4268
+ ProcessorFactoryBuilder,
4269
+ ProcessorFilter,
4270
+ ProcessorRecord,
4271
+ } from "@powerhousedao/reactor-browser"
4272
+ import type { PHDocumentHeader } from "document-model";
4273
+ import { ${v.pascalCaseName} } from "./processor.js";
4274
+
4275
+ export const ${v.camelCaseName}FactoryBuilder: ProcessorFactoryBuilder = (module: IProcessorHostModule) => async (driveHeader: PHDocumentHeader, processorApp?: ProcessorApp) => {
4276
+ // Create a namespace for the processor and the provided drive id
4277
+ const namespace = ${v.pascalCaseName}.getNamespace(driveHeader.id);
4278
+
4279
+ // Create a namespaced db for the processor
4280
+ const store = await module.relationalDb.createNamespace<${v.pascalCaseName}>(
4281
+ namespace,
4282
+ );
4283
+
4284
+ // Create a filter for the processor
4285
+ const filter: ProcessorFilter = {
4286
+ branch: ["main"],
4287
+ documentId: ["*"],
4288
+ documentType: [${getDocumentType(v.documentTypes)}],
4289
+ scope: ["global"],
4290
+ };
4291
+
4292
+ // Create the processor
4293
+ const processor = new ${v.pascalCaseName}(namespace, filter, store);
4294
+ return [
4295
+ {
4296
+ processor,
4297
+ filter,
4298
+ },
4299
+ ];
4300
+ }
4301
+ `.raw;
4302
+ //#endregion
4303
+ //#region src/templates/processors/relational-db/index.ts
4304
+ const relationalDbIndexTemplate = ts`
4305
+ export * from "./factory.js";
4306
+ export * from "./processor.js";
4307
+ `.raw;
4308
+ //#endregion
4309
+ //#region src/templates/processors/relational-db/processor.ts
4310
+ const defaultNamespaceComment = "// Default namespace: `${this.name}_${driveId.replaceAll(\"-\", \"_\")}`";
4311
+ const relationalDbProcessorTemplate = (v) => ts`
4312
+ import { RelationalDbProcessor } from "@powerhousedao/reactor-browser";
4313
+ import type { OperationWithContext } from "document-model";
4314
+ import { up } from "./migrations.js";
4315
+ import type { DB } from "./schema.js";
4316
+
4317
+ export class ${v.pascalCaseName} extends RelationalDbProcessor<DB> {
4318
+ onOperations(operations: OperationWithContext[]): Promise<void> {
4319
+ return Promise.resolve();
4320
+ }
4321
+
4322
+ onDisconnect(): Promise<void> {
4323
+ return Promise.resolve();
4324
+ }
4325
+
4326
+ static override getNamespace(driveId: string): string {
4327
+ ${defaultNamespaceComment}
4328
+ return super.getNamespace(driveId);
4329
+ }
4330
+
4331
+ override async initAndUpgrade(): Promise<void> {
4332
+ await up(this.relationalDb);
4333
+ }
4334
+ }
4335
+ `.raw;
4336
+ //#endregion
4337
+ //#region src/templates/processors/relational-db/migrations.ts
4338
+ const relationalDbMigrationsTemplate = () => ts`
4339
+ import type { IRelationalDb } from "@powerhousedao/reactor-browser"
4340
+
4341
+ export async function up(db: IRelationalDb<any>): Promise<void> {
4342
+ // Create table
4343
+ await db.schema
4344
+ .createTable("todo")
4345
+ .addColumn("task", "varchar(255)")
4346
+ .addColumn("status", "boolean")
4347
+ .addPrimaryKeyConstraint("todo_pkey", [
4348
+ "task"
4349
+ ])
4350
+ .ifNotExists()
4351
+ .execute();
4352
+ }
4353
+
4354
+ export async function down(db: IRelationalDb<any>): Promise<void> {
4355
+ // drop table
4356
+ await db.schema.dropTable("todo").execute();
4357
+ }
4358
+ `.raw;
4359
+ //#endregion
4360
+ //#region src/templates/processors/relational-db/schema.ts
4361
+ const relationalDbSchemaTemplate = () => ts`
4362
+ export interface Todo {
4363
+ status: boolean | null;
4364
+ task: string;
4365
+ }
4366
+
4367
+ export interface DB {
4368
+ todo: Todo;
4369
+ }
4370
+ `.raw;
4371
+ //#endregion
4372
+ //#region src/templates/subgraphs/index-file.ts
4373
+ const subgraphIndexFileTemplate = (v) => ts`
4374
+ import { BaseSubgraph } from "@powerhousedao/reactor-api";
4375
+ import type { DocumentNode } from "graphql";
4376
+ import { schema } from "./schema.js";
4377
+ import { getResolvers } from "./resolvers.js";
4378
+
4379
+ export class ${v.pascalCaseName}Subgraph extends BaseSubgraph {
4380
+ name = "${v.kebabCaseName}";
4381
+ typeDefs: DocumentNode = schema;
4382
+ resolvers = getResolvers(this);
4383
+ additionalContextFields = {};
4384
+ async onSetup() {}
4385
+ async onDisconnect() {}
4386
+ }
4387
+ `.raw;
4388
+ //#endregion
4389
+ //#region src/templates/subgraphs/lib-file.ts
4390
+ const subgraphLibFileTemplate = () => ts`
4391
+ /**
4392
+ * This is a scaffold file meant for customization.
4393
+ * Delete the file and run the code generator again to have it reset
4394
+ */
4395
+ `.raw;
4396
+ //#endregion
4397
+ //#region src/templates/subgraphs/custom-schema.ts
4398
+ const customSubgraphSchemaTemplate = (v) => ts`
4399
+ import { gql } from "graphql-tag";
4400
+ import type { DocumentNode } from "graphql";
4401
+
4402
+ export const schema: DocumentNode = gql\`
4403
+ """
4404
+ ${v.pascalCaseName} Queries
4405
+ """
4406
+ type ${v.pascalCaseName}Queries {
4407
+ example(driveId: String!): String
4408
+ }
4409
+
4410
+ type Query {
4411
+ ${v.camelCaseName}: ${v.pascalCaseName}Queries!
4412
+ }
4413
+
4414
+ \`
4415
+ `.raw;
4416
+ //#endregion
4417
+ //#region src/templates/subgraphs/custom-resolvers.ts
4418
+ const customSubgraphResolversTemplate = (v) => ts`
4419
+ import { type ISubgraph } from "@powerhousedao/reactor-api";
4420
+
4421
+ export const getResolvers = (subgraph: ISubgraph): Record<string, unknown> => {
4422
+ const reactor = subgraph.reactorClient;
4423
+
4424
+ return ({
4425
+ Query: {
4426
+ ${v.camelCaseName}: () => ({}), // namespace resolver for nested queries
4427
+ },
4428
+ ${v.pascalCaseName}Queries: {
4429
+ example: async (parent: unknown, args: { driveId: string }) => {
4430
+ return "example";
4431
+ },
4432
+ },
4433
+ });
4434
+ };
4435
+ `.raw;
4436
+ //#endregion
4437
+ //#region src/templates/subgraphs/document-model-schema.ts
4438
+ const documentModelSubgraphSchemaTemplate = (v) => {
4439
+ const mutationFields = v.modules.flatMap((module) => module.operations.map((op) => ` ${v.pascalCaseDocumentType}_${camel$1(op.name)}(driveId:String, docId:PHID, input:${v.pascalCaseDocumentType}_${pascal$1(op.name)}Input): Int`)).join("\n");
4440
+ const moduleSchemas = v.modules.map((module) => {
4441
+ return `${`\n"""\nModule: ${pascal$1(module.name)}\n"""`}\n${module.operations.map((op) => op.schema).join("\n")}`;
4442
+ }).join("\n");
4443
+ return `import { gql } from "graphql-tag";
4444
+ import type { DocumentNode } from "graphql";
4445
+
4446
+ export const schema: DocumentNode = gql\`
4447
+ """
4448
+ Queries: ${v.pascalCaseDocumentType} Document
4449
+ """
4450
+
4451
+ type ${v.pascalCaseDocumentType}Queries {
4452
+ getDocument(docId: PHID!, driveId: PHID): ${v.pascalCaseDocumentType}
4453
+ getDocuments(driveId: String): [${v.pascalCaseDocumentType}!]
4454
+ }
4455
+
4456
+ type Query {
4457
+ ${v.pascalCaseDocumentType}: ${v.pascalCaseDocumentType}Queries
4458
+ }
4459
+
4460
+ """
4461
+ Mutations: ${v.pascalCaseDocumentType}
4462
+ """
4463
+ type Mutation {
4464
+
4465
+ ${v.pascalCaseDocumentType}_createDocument(name:String!, driveId:String): String
4466
+
4467
+ ${mutationFields}
4468
+ }
4469
+
4470
+ ${moduleSchemas}
4471
+ \`
4472
+ `;
4473
+ };
4474
+ function pascal$1(name) {
4475
+ return name.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
4476
+ }
4477
+ function camel$1(name) {
4478
+ const p = pascal$1(name);
4479
+ return p.charAt(0).toLowerCase() + p.slice(1);
4480
+ }
4481
+ //#endregion
4482
+ //#region src/templates/subgraphs/document-model-resolvers.ts
4483
+ const documentModelSubgraphResolversTemplate = (v) => {
4484
+ const inputTypeImports = v.modules.flatMap((m) => m.operations.map((o) => `${pascal(o.name)}Input`)).join(",\n ");
4485
+ const operationMutations = v.modules.flatMap((module) => module.operations.map((op) => ` ${v.pascalCaseDocumentType}_${camel(op.name)}: async (_: unknown, args: { docId: string, input: ${pascal(op.name)}Input}) => {
4486
+ const { docId, input } = args;
4487
+ const doc = await reactorClient.get<${v.pascalCaseDocumentType}Document>(docId);
4488
+ if(!doc) {
4489
+ throw new Error("Document not found");
4490
+ }
4491
+
4492
+ await reactorClient.execute(
4493
+ docId,
4494
+ "main",
4495
+ [actions.${camel(op.name)}(input)]
4496
+ );
4497
+
4498
+ return true;
4499
+ },
4500
+ `)).join("\n");
4501
+ return `import type { BaseSubgraph } from "@powerhousedao/reactor-api";
4502
+ import { addFile } from "@powerhousedao/shared/document-drive";
4503
+ import { setName } from "document-model";
4504
+ import {
4505
+ actions,
4506
+ ${v.documentTypeVariableName},
4507
+ } from "${v.documentModelDir}";
4508
+ import type {
4509
+ ${v.phDocumentTypeName},
4510
+ ${inputTypeImports}
4511
+ } from "${v.documentModelDir}";
4512
+
4513
+ export const getResolvers = (subgraph: BaseSubgraph): Record<string, unknown> => {
4514
+ const reactorClient = subgraph.reactorClient;
4515
+
4516
+ return ({
4517
+ Query: {
4518
+ ${v.pascalCaseDocumentType}: async () => {
4519
+ return {
4520
+ getDocument: async (args: { docId: string, driveId: string }) => {
4521
+ const { docId, driveId } = args;
4522
+
4523
+ if(!docId) {
4524
+ throw new Error("Document id is required");
4525
+ }
4526
+
4527
+ if(driveId) {
4528
+ const children = await reactorClient.getChildren(driveId);
4529
+ const childIds = children.results.map(d => d.header.id);
4530
+ if(!childIds.includes(docId)) {
4531
+ throw new Error(\`Document with id \${docId} is not part of \${driveId}\`);
4532
+ }
4533
+ }
4534
+
4535
+ const doc = await reactorClient.get<${v.phDocumentTypeName}>(docId);
4536
+ return {
4537
+ driveId: driveId,
4538
+ ...doc,
4539
+ ...doc.header,
4540
+ created: doc.header.createdAtUtcIso,
4541
+ lastModified: doc.header.lastModifiedAtUtcIso,
4542
+ state: doc.state.global,
4543
+ stateJSON: doc.state.global,
4544
+ revision: doc.header?.revision?.global ?? 0,
4545
+ };
4546
+ },
4547
+ getDocuments: async (args: { driveId?: string }) => {
4548
+ const { driveId } = args;
4549
+ const result = await reactorClient.find({ type: ${v.documentTypeVariableName}, ...(driveId ? { parentId: driveId } : {}) });
4550
+ return result.results.map((_doc) => {
4551
+ const doc = _doc as ${v.phDocumentTypeName};
4552
+ return {
4553
+ driveId: driveId,
4554
+ ...doc,
4555
+ ...doc.header,
4556
+ created: doc.header.createdAtUtcIso,
4557
+ lastModified: doc.header.lastModifiedAtUtcIso,
4558
+ state: doc.state.global,
4559
+ stateJSON: doc.state.global,
4560
+ revision: doc.header?.revision?.global ?? 0,
4561
+ };
4562
+ });
4563
+ },
4564
+ };
4565
+ },
4566
+ },
4567
+ Mutation: {
4568
+ ${v.pascalCaseDocumentType}_createDocument: async (_: unknown, args: { name: string, driveId?: string }) => {
4569
+ const { driveId, name } = args;
4570
+ const document = await reactorClient.createEmpty(${v.documentTypeVariableName});
4571
+
4572
+ if(driveId) {
4573
+ await reactorClient.execute(
4574
+ driveId,
4575
+ "main",
4576
+ [addFile({
4577
+ name,
4578
+ id: document.header.id,
4579
+ documentType: ${v.documentTypeVariableName},
4580
+ })],
4581
+ );
4582
+ }
4583
+
4584
+ if(name) {
4585
+ await reactorClient.execute(
4586
+ document.header.id,
4587
+ "main",
4588
+ [setName(name)],
4589
+ );
4590
+ }
4591
+
4592
+ return document.header.id;
4593
+ },
4594
+
4595
+ ${operationMutations}
4596
+ },
4597
+ });
4598
+ };
4599
+ `;
4600
+ };
4601
+ function pascal(name) {
4602
+ return name.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
4603
+ }
4604
+ function camel(name) {
4605
+ const p = pascal(name);
4606
+ return p.charAt(0).toLowerCase() + p.slice(1);
4607
+ }
4608
+ //#endregion
4609
+ export { documentModelDocumentSchemaFileTemplate as $, upgradeManifestTemplate as A, eslintConfigTemplate as At, documentModelHooksFileTemplate as B, claudeSettingsLocalTemplate as Bt, driveEditorFilesFileTemplate as C, indexTsTemplate as Ct, createDocumentFileTemplate as D, gitIgnoreTemplate as Dt, driveEditorDriveContentsFileTemplate as E, indexHtmlTemplate as Et, makeTestCaseForAction as F, switchboardEntrypointTemplate as Ft, documentModelPhFactoriesFileTemplate as G, documentModelGenTypesTemplate as H, documentModelTestFileTemplate as I, nginxConfTemplate as It, documentModelOperationsModuleCreatorsFileTemplate as J, documentModelOperationsModuleOperationsFileTemplate as K, documentModelSrcIndexFileTemplate as L, dockerfileTemplate as Lt, documentModelOperationsModuleTestFileTemplate as M, editorsTemplate as Mt, makeActionImportNames as N, documentModelsIndexTemplate as Nt, documentModelUtilsTemplate as O, syncAndPublishWorkflowTemplate as Ot, makeActionsImports as P, documentModelsTemplate as Pt, documentModelDocumentTypeTemplate as Q, documentModelModuleFileTemplate as R, connectEntrypointTemplate as Rt, driveEditorFoldersFileTemplate as S, licenseTemplate as St, driveExplorerFileTemplate as T, legacyIndexHtmlTemplate as Tt, documentModelSchemaIndexTemplate as U, documentModelGenUtilsTemplate as V, agentsTemplate as Vt, documentModelGenReducerFileTemplate as W, getModuleExportType as X, documentModelOperationModuleActionsFileTemplate as Y, documentModelGenIndexFileTemplate as Z, analyticsFactoryTemplate as _, packageJsonScriptsTemplate as _t, subgraphLibFileTemplate as a, documentEditorEditorFileTemplate as at, driveExplorerNavigationBreadcrumbsFileTemplate as b, npmrcTemplate as bt, relationalDbMigrationsTemplate as c, viteConfigTemplate as ct, relationalDbFactoryTemplate as d, subgraphsIndexTemplate as dt, documentModelGenCreatorsFileTemplate as et, processorsIndexTemplate as f, styleTemplate as ft, analyticsProcessorTemplate as g, packageJsonExportsTemplate as gt, analyticsIndexTemplate as h, buildPowerhouseConfigTemplate as ht, customSubgraphSchemaTemplate as i, documentEditorModuleFileTemplate as it, documentModelSrcUtilsTemplate as j, editorsIndexTemplate as jt, upgradeTransitionTemplate as k, geminiSettingsTemplate as kt, relationalDbProcessorTemplate as l, tsConfigTemplate as lt, processorsFactoryTemplate as m, powerhouseManifestTemplate as mt, documentModelSubgraphSchemaTemplate as n, documentModelGenActionsFileTemplate as nt, subgraphIndexFileTemplate as o, docsFromCliHelpTemplate as ot, factoryBuildersTemplate as p, readmeTemplate as pt, documentModelOperationsModuleErrorFileTemplate as q, customSubgraphResolversTemplate as r, documentModelRootActionsFileTemplate as rt, relationalDbSchemaTemplate as s, vitestConfigTemplate as st, documentModelSubgraphResolversTemplate as t, documentModelGenControllerFileTemplate as tt, relationalDbIndexTemplate as u, tsconfigPathsTemplate as ut, driveEditorEditorFileTemplate as v, exportsTemplate as vt, emptyStateFileTemplate as w, mainTsxTemplate as wt, folderTreeFileTemplate as x, mcpTemplate as xt, driveEditorConfigFileTemplate as y, packageJsonTemplate as yt, documentModelIndexTemplate as z, cursorMcpTemplate as zt };
4610
+
4611
+ //# sourceMappingURL=templates-CKdxigVj.mjs.map