@gnar-engine/cli 1.0.3 → 1.0.5

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 (259) hide show
  1. package/bootstrap/deploy.localdev.yml +44 -30
  2. package/bootstrap/secrets.localdev.yml +20 -14
  3. package/bootstrap/services/control/src/config.js +4 -0
  4. package/bootstrap/services/{agent → page}/Dockerfile +3 -3
  5. package/bootstrap/services/page/package.json +16 -0
  6. package/bootstrap/services/page/src/app.js +50 -0
  7. package/bootstrap/services/page/src/commands/block.handler.js +94 -0
  8. package/bootstrap/services/page/src/commands/page.handler.js +167 -0
  9. package/bootstrap/services/page/src/config.js +62 -0
  10. package/bootstrap/services/page/src/controllers/block.http.controller.js +87 -0
  11. package/bootstrap/services/page/src/controllers/message.controller.js +51 -0
  12. package/bootstrap/services/page/src/controllers/page.http.controller.js +89 -0
  13. package/bootstrap/services/page/src/policies/block.policy.js +50 -0
  14. package/bootstrap/services/page/src/policies/page.policy.js +49 -0
  15. package/bootstrap/services/page/src/schema/page.schema.js +139 -0
  16. package/bootstrap/services/page/src/services/block.service.js +83 -0
  17. package/bootstrap/services/page/src/services/page.service.js +83 -0
  18. package/bootstrap/services/portal/Dockerfile +7 -10
  19. package/bootstrap/services/portal/README.md +66 -15
  20. package/bootstrap/services/portal/index.html +13 -0
  21. package/bootstrap/services/portal/nginx.conf +5 -12
  22. package/bootstrap/services/portal/package.json +27 -53
  23. package/bootstrap/services/portal/public/vite.svg +1 -0
  24. package/bootstrap/services/portal/react-router.config.js +7 -0
  25. package/bootstrap/services/portal/src/App.jsx +16 -0
  26. package/bootstrap/services/portal/src/assets/gnar-engine-white-logo.svg +9 -0
  27. package/bootstrap/services/portal/src/assets/icon-agent.svg +6 -0
  28. package/bootstrap/services/portal/src/assets/icon-cog.svg +4 -0
  29. package/bootstrap/services/portal/src/assets/icon-delete.svg +3 -0
  30. package/bootstrap/services/portal/src/assets/icon-home.svg +3 -0
  31. package/bootstrap/services/portal/src/assets/icon-padlock.svg +3 -0
  32. package/bootstrap/services/portal/src/assets/icon-page.svg +6 -0
  33. package/bootstrap/services/portal/src/assets/icon-reports.svg +3 -0
  34. package/bootstrap/services/portal/src/assets/icon-user.svg +3 -0
  35. package/bootstrap/services/portal/src/assets/icon-users.svg +3 -0
  36. package/bootstrap/services/portal/src/assets/login-green-rad-back-1.jpg +0 -0
  37. package/bootstrap/services/portal/src/assets/react.svg +1 -0
  38. package/bootstrap/services/portal/src/components/CrudList/CrudList.jsx +85 -0
  39. package/bootstrap/services/portal/src/components/CrudList/CrudList.less +59 -0
  40. package/bootstrap/services/portal/src/{ui/customSelect → components/CustomSelect}/CustomSelect.jsx +21 -3
  41. package/bootstrap/services/portal/src/components/LoginForm/LoginForm.jsx +58 -0
  42. package/bootstrap/services/portal/src/components/PageBlockSwitch/PageBlockSwitch.jsx +129 -0
  43. package/bootstrap/services/portal/src/components/Sidebar/Sidebar.jsx +33 -0
  44. package/bootstrap/services/portal/src/components/Sidebar/Sidebar.less +37 -0
  45. package/bootstrap/services/portal/src/components/Topbar/Topbar.jsx +19 -0
  46. package/bootstrap/services/portal/src/components/Topbar/Topbar.less +22 -0
  47. package/bootstrap/services/portal/src/components/UserInfo/UserInfo.jsx +33 -0
  48. package/bootstrap/services/portal/src/components/UserInfo/UserInfo.less +21 -0
  49. package/bootstrap/services/portal/src/css/style.css +446 -742
  50. package/bootstrap/services/portal/src/data/pages.data.js +10 -0
  51. package/bootstrap/services/portal/src/elements/CustomSelect/CustomSelect.jsx +65 -0
  52. package/bootstrap/services/portal/src/{ui/customSelect/customSelect.less → elements/CustomSelect/CustomSelect.less} +17 -7
  53. package/bootstrap/services/portal/src/elements/ImageInput/ImageInput.jsx +115 -0
  54. package/bootstrap/services/portal/src/elements/ImageInput/ImageInput.less +43 -0
  55. package/bootstrap/services/portal/src/elements/ImageMultiInput/ImageMultiInput.jsx +124 -0
  56. package/bootstrap/services/portal/src/elements/ImageMultiInput/ImageMultiInput.less +0 -0
  57. package/bootstrap/services/portal/src/elements/Repeater/Repeater.jsx +52 -0
  58. package/bootstrap/services/portal/src/elements/Repeater/Repeater.less +70 -0
  59. package/bootstrap/services/portal/src/elements/RichTextInput/RichTextInput.jsx +18 -0
  60. package/bootstrap/services/portal/src/elements/RichTextInput/RichTextInput.less +37 -0
  61. package/bootstrap/services/portal/src/elements/SaveButton/SaveButton.jsx +45 -0
  62. package/bootstrap/services/portal/src/elements/SelectRepeater/SelectRepeater.jsx +63 -0
  63. package/bootstrap/services/portal/src/elements/SelectRepeater/SelectRepeater.less +23 -0
  64. package/bootstrap/services/portal/src/elements/TextInput/TextInput.jsx +17 -0
  65. package/bootstrap/services/portal/src/layouts/Card/Card.jsx +15 -0
  66. package/bootstrap/services/portal/src/layouts/PortalLayout/PortalLayout.jsx +29 -0
  67. package/bootstrap/services/portal/src/layouts/PortalLayout/PortalLayout.less +49 -0
  68. package/bootstrap/services/portal/src/main.jsx +51 -0
  69. package/bootstrap/services/portal/src/pages/BlockSinglePage/BlockSinglePage.jsx +277 -0
  70. package/bootstrap/services/portal/src/pages/BlocksPage/BlocksPage.jsx +23 -0
  71. package/bootstrap/services/portal/src/pages/DashboardPage/DashboardPage.jsx +11 -0
  72. package/bootstrap/services/portal/src/pages/DashboardPage/DashboardPage.less +0 -0
  73. package/bootstrap/services/portal/src/pages/LoginPage/LoginPage.jsx +21 -0
  74. package/bootstrap/services/portal/src/pages/LoginPage/LoginPage.less +51 -0
  75. package/bootstrap/services/portal/src/pages/PageSinglePage/PageSinglePage.jsx +338 -0
  76. package/bootstrap/services/portal/src/pages/PagesPage/PagesPage.jsx +23 -0
  77. package/bootstrap/services/portal/src/pages/UserSinglePage/UserSinglePage.jsx +9 -0
  78. package/bootstrap/services/portal/src/pages/UserSinglePage/UserSinglePage.less +0 -0
  79. package/bootstrap/services/portal/src/pages/UsersPage/UsersPage.jsx +25 -0
  80. package/bootstrap/services/portal/src/pages/UsersPage/UsersPage.less +0 -0
  81. package/bootstrap/services/portal/src/services/block.js +28 -0
  82. package/bootstrap/services/portal/src/services/client.js +67 -0
  83. package/bootstrap/services/portal/src/services/gravatar.js +14 -0
  84. package/bootstrap/services/portal/src/services/page.js +28 -0
  85. package/bootstrap/services/portal/src/services/storage.js +62 -0
  86. package/bootstrap/services/portal/src/services/user.js +41 -0
  87. package/bootstrap/services/portal/src/slices/authSlice.js +44 -14
  88. package/bootstrap/services/portal/src/store/configureStore.js +1 -3
  89. package/bootstrap/services/portal/src/style/cards.less +57 -0
  90. package/bootstrap/services/portal/src/{styles → style}/global.less +90 -45
  91. package/bootstrap/services/portal/src/style/icons.less +21 -0
  92. package/bootstrap/services/portal/src/style/inputs.less +52 -0
  93. package/bootstrap/services/portal/src/style/main.less +28 -0
  94. package/bootstrap/services/portal/src/utils/utils.js +9 -0
  95. package/bootstrap/services/portal/vite.config.js +12 -0
  96. package/bootstrap/services/user/Dockerfile +1 -1
  97. package/bootstrap/services/user/src/app.js +6 -1
  98. package/bootstrap/services/user/src/commands/user.handler.js +0 -3
  99. package/bootstrap/services/user/src/config.js +5 -1
  100. package/bootstrap/services/user/src/policies/user.policy.js +3 -1
  101. package/bootstrap/services/user/src/tests/commands/user.test.js +22 -0
  102. package/install-from-clone.sh +30 -0
  103. package/package.json +1 -1
  104. package/src/cli.js +8 -0
  105. package/src/config.js +2 -1
  106. package/src/dev/commands.js +10 -2
  107. package/src/dev/dev.service.js +167 -52
  108. package/src/provisioner/Dockerfile +27 -0
  109. package/src/provisioner/package.json +19 -0
  110. package/src/provisioner/src/app.js +56 -0
  111. package/src/provisioner/src/services/mongodb.js +58 -0
  112. package/src/provisioner/src/services/mysql.js +51 -0
  113. package/src/provisioner/src/services/secrets.js +84 -0
  114. package/src/scaffolder/commands.js +12 -5
  115. package/src/scaffolder/scaffolder.handler.js +256 -58
  116. package/templates/service/Dockerfile.hbs +4 -1
  117. package/templates/service/package.json.hbs +14 -16
  118. package/templates/service/src/app.js.hbs +53 -0
  119. package/templates/service/{commands → src/commands}/{{serviceName}}.handler.js.hbs +2 -3
  120. package/templates/service/src/mongodb.config.js.hbs +49 -0
  121. package/templates/service/{config.js.hbs → src/mysql.config.js.hbs} +10 -0
  122. package/{bootstrap/services/agent/src/schema/Agent.schema.js → templates/service/src/schema/{{serviceName}}.schema.js.hbs} +3 -3
  123. package/templates/service/src/services/mongodb.{{serviceName}}.service.js.hbs +70 -0
  124. package/bootstrap/services/agent/notes.md +0 -28
  125. package/bootstrap/services/agent/package.json +0 -16
  126. package/bootstrap/services/agent/src/app.js +0 -52
  127. package/bootstrap/services/agent/src/commands/agent.handler.js +0 -104
  128. package/bootstrap/services/agent/src/config.js +0 -52
  129. package/bootstrap/services/agent/src/controllers/http.controller.js +0 -44
  130. package/bootstrap/services/agent/src/controllers/message.controller.js +0 -51
  131. package/bootstrap/services/agent/src/db/migrations/01-init.js +0 -50
  132. package/bootstrap/services/agent/src/db/migrations/02-agent-service-init.js +0 -36
  133. package/bootstrap/services/agent/src/policies/agent.policy.js +0 -13
  134. package/bootstrap/services/agent/src/services/agent.service.js +0 -259
  135. package/bootstrap/services/agent/src/services/chatgpt.service.js +0 -46
  136. package/bootstrap/services/agent/src/services/manifest.service.js +0 -21
  137. package/bootstrap/services/portal/Dockerfile.remote +0 -40
  138. package/bootstrap/services/portal/public/favicon.ico +0 -0
  139. package/bootstrap/services/portal/public/gnar-white.png +0 -0
  140. package/bootstrap/services/portal/public/gnarengine-logo-black.png +0 -0
  141. package/bootstrap/services/portal/public/index.html +0 -43
  142. package/bootstrap/services/portal/public/logo192.png +0 -0
  143. package/bootstrap/services/portal/public/logo512.png +0 -0
  144. package/bootstrap/services/portal/public/manifest.json +0 -25
  145. package/bootstrap/services/portal/public/robots.txt +0 -3
  146. package/bootstrap/services/portal/src/App.js +0 -56
  147. package/bootstrap/services/portal/src/assets/Logo_Anchord_Black.svg +0 -1
  148. package/bootstrap/services/portal/src/assets/Logo_Anchord_Black_Green.svg +0 -1
  149. package/bootstrap/services/portal/src/assets/Logo_Anchord_White_Green.svg +0 -1
  150. package/bootstrap/services/portal/src/assets/activity.svg +0 -3
  151. package/bootstrap/services/portal/src/assets/arrow.svg +0 -3
  152. package/bootstrap/services/portal/src/assets/bin-white.svg +0 -3
  153. package/bootstrap/services/portal/src/assets/bin.svg +0 -3
  154. package/bootstrap/services/portal/src/assets/check.svg +0 -3
  155. package/bootstrap/services/portal/src/assets/chevron.svg +0 -3
  156. package/bootstrap/services/portal/src/assets/contact.svg +0 -3
  157. package/bootstrap/services/portal/src/assets/dots-vertical.svg +0 -5
  158. package/bootstrap/services/portal/src/assets/eye-off.svg +0 -3
  159. package/bootstrap/services/portal/src/assets/eye.svg +0 -4
  160. package/bootstrap/services/portal/src/assets/gnar-engine-black.svg +0 -47
  161. package/bootstrap/services/portal/src/assets/gnar-engine-white.svg +0 -47
  162. package/bootstrap/services/portal/src/assets/gnar_engine.svg +0 -3
  163. package/bootstrap/services/portal/src/assets/gnarengine-logo-black.png +0 -0
  164. package/bootstrap/services/portal/src/assets/home.svg +0 -3
  165. package/bootstrap/services/portal/src/assets/link.svg +0 -3
  166. package/bootstrap/services/portal/src/assets/lock.svg +0 -3
  167. package/bootstrap/services/portal/src/assets/package.svg +0 -4
  168. package/bootstrap/services/portal/src/assets/raffle.svg +0 -3
  169. package/bootstrap/services/portal/src/assets/settings.svg +0 -4
  170. package/bootstrap/services/portal/src/assets/shopping-bag.svg +0 -3
  171. package/bootstrap/services/portal/src/assets/user-black.svg +0 -3
  172. package/bootstrap/services/portal/src/assets/user.svg +0 -3
  173. package/bootstrap/services/portal/src/assets/users.svg +0 -3
  174. package/bootstrap/services/portal/src/assets/wallet.svg +0 -3
  175. package/bootstrap/services/portal/src/data/data.js +0 -70
  176. package/bootstrap/services/portal/src/features/attributeFormRow/AttributeFormRow.jsx +0 -32
  177. package/bootstrap/services/portal/src/features/billingShipping/BillingShipping.jsx +0 -160
  178. package/bootstrap/services/portal/src/features/crud/crudEdit.less +0 -230
  179. package/bootstrap/services/portal/src/features/crud/crudList.less +0 -134
  180. package/bootstrap/services/portal/src/features/crud/crudPage.less +0 -31
  181. package/bootstrap/services/portal/src/features/crudContact/CrudContactList.jsx +0 -108
  182. package/bootstrap/services/portal/src/features/crudContact/CrudContactSingle.jsx +0 -243
  183. package/bootstrap/services/portal/src/features/crudOrder/CrudOrderList.jsx +0 -109
  184. package/bootstrap/services/portal/src/features/crudOrder/CrudOrderSingle.jsx +0 -315
  185. package/bootstrap/services/portal/src/features/crudProducts/CrudProductList.jsx +0 -104
  186. package/bootstrap/services/portal/src/features/crudProducts/CrudProductSingle.jsx +0 -388
  187. package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesList.jsx +0 -104
  188. package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesSingle.jsx +0 -208
  189. package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionList.jsx +0 -110
  190. package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionSingle.jsx +0 -261
  191. package/bootstrap/services/portal/src/features/crudUser/CrudUserList.jsx +0 -107
  192. package/bootstrap/services/portal/src/features/crudUser/CrudUserSingle.jsx +0 -402
  193. package/bootstrap/services/portal/src/features/inventoryFormRow/InventoryFormRow.jsx +0 -30
  194. package/bootstrap/services/portal/src/features/lineItems/LineItems.jsx +0 -113
  195. package/bootstrap/services/portal/src/features/loginForm/LoginForm.jsx +0 -56
  196. package/bootstrap/services/portal/src/features/loginForm/loginForm.less +0 -56
  197. package/bootstrap/services/portal/src/features/notes/Notes.jsx +0 -18
  198. package/bootstrap/services/portal/src/features/passwordReset/PasswordResetForm.jsx +0 -96
  199. package/bootstrap/services/portal/src/features/passwordReset/PasswordResetRequestForm.jsx +0 -74
  200. package/bootstrap/services/portal/src/features/priceFormRow/PriceFormRow.jsx +0 -102
  201. package/bootstrap/services/portal/src/features/priceFormRow/priceFormRow.less +0 -24
  202. package/bootstrap/services/portal/src/features/raffleEntriesList/RaffleEntriesList.jsx +0 -99
  203. package/bootstrap/services/portal/src/features/raffleProductFormRow/RaffleProductFormRow.jsx +0 -46
  204. package/bootstrap/services/portal/src/features/sidebar/Sidebar.jsx +0 -64
  205. package/bootstrap/services/portal/src/features/sidebar/sidebar.less +0 -49
  206. package/bootstrap/services/portal/src/features/skus/Skus.jsx +0 -109
  207. package/bootstrap/services/portal/src/features/subscriptionSchedule/SubscriptionSchedule.jsx +0 -44
  208. package/bootstrap/services/portal/src/features/taxonomyFormRow/TaxonomyFormRow.jsx +0 -32
  209. package/bootstrap/services/portal/src/features/user/User.jsx +0 -54
  210. package/bootstrap/services/portal/src/features/user/user.less +0 -57
  211. package/bootstrap/services/portal/src/includes/utilities.js +0 -259
  212. package/bootstrap/services/portal/src/index.js +0 -14
  213. package/bootstrap/services/portal/src/layouts/CrudLayout.jsx +0 -50
  214. package/bootstrap/services/portal/src/layouts/LoginLayout.jsx +0 -17
  215. package/bootstrap/services/portal/src/layouts/PortalLayout.jsx +0 -48
  216. package/bootstrap/services/portal/src/layouts/loginLayout.less +0 -33
  217. package/bootstrap/services/portal/src/layouts/portalLayout.less +0 -67
  218. package/bootstrap/services/portal/src/pages/contacts/Contacts.jsx +0 -199
  219. package/bootstrap/services/portal/src/pages/dashboard/Dashboard.jsx +0 -17
  220. package/bootstrap/services/portal/src/pages/integrations/Integrations.jsx +0 -10
  221. package/bootstrap/services/portal/src/pages/login/Login.jsx +0 -15
  222. package/bootstrap/services/portal/src/pages/login/login.less +0 -10
  223. package/bootstrap/services/portal/src/pages/orders/Orders.jsx +0 -199
  224. package/bootstrap/services/portal/src/pages/passwordReset/PasswordResetPage.jsx +0 -15
  225. package/bootstrap/services/portal/src/pages/passwordResetRequest/PasswordResetRequestPage.jsx +0 -15
  226. package/bootstrap/services/portal/src/pages/payments/Payments.jsx +0 -10
  227. package/bootstrap/services/portal/src/pages/portal/Portal.jsx +0 -43
  228. package/bootstrap/services/portal/src/pages/products/Products.jsx +0 -212
  229. package/bootstrap/services/portal/src/pages/raffleEntries/RaffleEntries.jsx +0 -124
  230. package/bootstrap/services/portal/src/pages/raffles/Raffles.jsx +0 -186
  231. package/bootstrap/services/portal/src/pages/reports/Reports.jsx +0 -10
  232. package/bootstrap/services/portal/src/pages/settings/Settings.jsx +0 -10
  233. package/bootstrap/services/portal/src/pages/subscriptions/Subscriptions.jsx +0 -199
  234. package/bootstrap/services/portal/src/pages/users/Users.jsx +0 -193
  235. package/bootstrap/services/portal/src/pages/users/users.less +0 -25
  236. package/bootstrap/services/portal/src/styles/inputs.less +0 -157
  237. package/bootstrap/services/portal/src/styles/main.less +0 -26
  238. package/bootstrap/services/portal/src/ui/collapsible/Collapsible.jsx +0 -97
  239. package/bootstrap/services/portal/src/ui/collapsible/collapsible.less +0 -23
  240. package/bootstrap/services/portal/src/ui/customCheckbox/CustomCheckbox.jsx +0 -17
  241. package/bootstrap/services/portal/src/ui/customCheckbox/customCheckbox.less +0 -42
  242. package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelect.jsx +0 -63
  243. package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelectPeriod.jsx +0 -63
  244. package/bootstrap/services/portal/src/ui/goBack/GoBack.jsx +0 -19
  245. package/bootstrap/services/portal/src/ui/loader/Loader.jsx +0 -12
  246. package/bootstrap/services/portal/src/ui/pagination/Pagination.jsx +0 -23
  247. package/bootstrap/services/portal/src/ui/repeater/Repeater.jsx +0 -29
  248. package/bootstrap/services/portal/src/ui/saveButton/SaveButton.jsx +0 -69
  249. package/bootstrap/services/user/src/db/seeders/development/02-portal-admin-user.js +0 -27
  250. package/bootstrap/services/user/src/tests/user.test.js +0 -126
  251. package/templates/service/app.js.hbs +0 -38
  252. package/templates/service/schema/{{serviceName}}.schema.js.hbs +0 -14
  253. /package/bootstrap/services/portal/src/{ui/saveButton/saveButton.less → components/CustomSelect/CustomSelect.less} +0 -0
  254. /package/templates/service/{controllers → src/controllers}/http.controller.js.hbs +0 -0
  255. /package/templates/service/{controllers → src/controllers}/message.controller.js.hbs +0 -0
  256. /package/templates/service/{db → src/mysql.db}/migrations/01-init.js.hbs +0 -0
  257. /package/templates/service/{db → src/mysql.db}/migrations/02-{{lowerCase serviceName}}-service-init.js.hbs +0 -0
  258. /package/templates/service/{policies → src/policies}/{{serviceName}}.policy.js.hbs +0 -0
  259. /package/templates/service/{services/{{serviceName}}.service.js.hbs → src/services/mysql.{{serviceName}}.service.js.hbs} +0 -0
@@ -48,9 +48,9 @@ export const registerScaffolderCommands = (program) => {
48
48
  create
49
49
  .command('service <service>')
50
50
  .description('📦 Create a new service: back-end|front-end')
51
- .action(async (options) => {
51
+ .action(async (service) => {
52
52
  // validate
53
- if (!options.service) {
53
+ if (!service) {
54
54
  console.error('❌ Please specify a service name using gnar create service <serviceName>');
55
55
  }
56
56
 
@@ -95,10 +95,17 @@ export const registerScaffolderCommands = (program) => {
95
95
  try {
96
96
  console.log('Creating new service in... ' + activeProfile.profile.PROJECT_DIR);
97
97
 
98
+ // add trailing slash to project dir if missing
99
+ let projectDir = activeProfile.profile.PROJECT_DIR;
100
+
101
+ if (!activeProfile.profile.PROJECT_DIR.endsWith(path.sep)) {
102
+ projectDir += path.sep;
103
+ }
104
+
98
105
  scaffolder.createNewService({
99
- serviceName: options.service,
106
+ serviceName: service,
100
107
  database: backendAnswers.database,
101
- projectDir: activeProfile.profile.PROJECT_DIR
108
+ projectDir: projectDir
102
109
  });
103
110
 
104
111
  } catch (error) {
@@ -112,7 +119,7 @@ export const registerScaffolderCommands = (program) => {
112
119
  console.log('Creating new service in... ' + activeProfile.profile.PROJECT_DIR);
113
120
 
114
121
  scaffolder.createNewFrontEndService({
115
- serviceName: options.service,
122
+ serviceName: service,
116
123
  projectDir: activeProfile.profile.PROJECT_DIR
117
124
  });
118
125
  } catch (error) {
@@ -3,8 +3,11 @@ import fs from 'fs';
3
3
  import yaml from 'js-yaml';
4
4
  import { profiles } from '../profiles/profiles.client.js';
5
5
  import { helpers } from '../helpers/helpers.js';
6
+ import { directories } from '../cli.js';
6
7
  import Handlebars from 'handlebars';
7
8
 
9
+
10
+
8
11
  /**
9
12
  * Gnar Engine Scaffolder
10
13
  */
@@ -32,53 +35,83 @@ export const scaffolder = {
32
35
  fs.mkdirSync(serviceDir, { recursive: true });
33
36
 
34
37
  // Get all files in the templates directory
35
- const templatesDir = path.join(import.meta.dirname, '../../templates/service');
36
38
  const templateFiles = scaffolder.getAllTemplateFiles({
37
- dir: templatesDir,
38
- baseDir: templatesDir
39
+ dir: directories.scaffolderTemplates,
40
+ baseDir: directories.scaffolderTemplates
39
41
  });
40
42
 
41
- console.log('Template files:', templateFiles);
42
-
43
43
  // Register Handlebars helpers
44
44
  Object.entries(helpers).forEach(([name, fn]) => {
45
45
  Handlebars.registerHelper(name, fn);
46
46
  });
47
47
 
48
- // Write the files to the service directory
49
- templateFiles.forEach(file => {
50
- let sourcePath;
51
- let targetPath;
52
- const templateArgs = {
53
- serviceName,
54
- database
55
- };
56
-
57
- switch (file.extension) {
58
- case '.hbs':
59
- // Compile the Handlebars template for content
60
- const templateContent = fs.readFileSync(file.fullPath, 'utf8');
61
- const compiledTemplate = Handlebars.compile(templateContent);
62
- const renderedContent = compiledTemplate(templateArgs);
63
-
64
- // Compile the Handlebars template for the filename (excluding .hbs)
65
- const filenameTemplate = Handlebars.compile(file.relativePath.replace(/\.hbs$/, ''));
66
- const renderedFilename = filenameTemplate(templateArgs);
67
- targetPath = path.join(serviceDir, renderedFilename);
68
-
69
- // Ensure directory exists
70
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
71
- fs.writeFileSync(targetPath, renderedContent, 'utf8');
72
- break;
73
- default:
74
- // By default, copy the file to the service directory
75
- sourcePath = file.fullPath;
76
- targetPath = path.join(serviceDir, file.relativePath);
77
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
78
- fs.copyFileSync(sourcePath, targetPath);
79
- break;
48
+ // Write the files to the service directory
49
+ templateFiles.forEach(file => {
50
+ let sourcePath;
51
+ let targetPath;
52
+ const templateArgs = {
53
+ serviceName,
54
+ database
55
+ };
56
+
57
+ let fileRelativePath = file.relativePath;
58
+
59
+ // Database specific
60
+ if (fileRelativePath.includes('mongodb.')) {
61
+ if (database !== 'mongodb') {
62
+ return;
63
+ } else {
64
+ fileRelativePath = fileRelativePath.replace('mongodb.', '');
80
65
  }
81
- });
66
+ }
67
+
68
+ if (fileRelativePath.includes('mysql.')) {
69
+ if (database !== 'mysql') {
70
+ return;
71
+ } else {
72
+ fileRelativePath = fileRelativePath.replace('mysql.', '');
73
+ }
74
+ }
75
+
76
+ switch (file.extension) {
77
+ case '.hbs':
78
+ // Compile the Handlebars template for content
79
+ const templateContent = fs.readFileSync(file.fullPath, 'utf8');
80
+ const compiledTemplate = Handlebars.compile(templateContent);
81
+ const renderedContent = compiledTemplate(templateArgs);
82
+
83
+ // Compile the Handlebars template for the filename (excluding .hbs)
84
+ const filenameTemplate = Handlebars.compile(fileRelativePath.replace(/\.hbs$/, ''));
85
+ const renderedFilename = filenameTemplate(templateArgs);
86
+ targetPath = path.join(serviceDir, renderedFilename);
87
+
88
+ // Ensure directory exists
89
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
90
+ fs.writeFileSync(targetPath, renderedContent, 'utf8');
91
+ break;
92
+ default:
93
+ // By default, copy the file to the service directory
94
+ sourcePath = file.fullPath;
95
+ targetPath = path.join(serviceDir, fileRelativePath);
96
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
97
+ fs.copyFileSync(sourcePath, targetPath);
98
+ break;
99
+ }
100
+ });
101
+
102
+ // Scaffold deploy.yml
103
+ scaffolder.scaffoldServiceDeployYml({
104
+ deployPath: path.join(projectDir, 'deploy.localdev.yml'),
105
+ serviceName: serviceName,
106
+ database: database
107
+ });
108
+
109
+ // Scaffold secrets.yml
110
+ scaffolder.scaffoldServiceSecrets({
111
+ secretsPath: path.join(projectDir, 'secrets.localdev.yml'),
112
+ serviceName: serviceName,
113
+ database: database
114
+ });
82
115
 
83
116
  return {
84
117
  message: `Service "${serviceName}" created successfully at ${serviceDir}`,
@@ -105,6 +138,25 @@ export const scaffolder = {
105
138
 
106
139
  // Create the service directory
107
140
  fs.mkdirSync(serviceDir, { recursive: true });
141
+
142
+ // Add to deploy.yml
143
+ scaffolder.scaffoldServiceDeployYml({
144
+ deployPath: path.join(projectDir, 'deploy.localdev.yml'),
145
+ serviceName: serviceName,
146
+ database: null
147
+ });
148
+
149
+ // Scaffold secrets
150
+ scaffolder.scaffoldServiceSecrets({
151
+ secretsPath: path.join(projectDir, 'secrets.localdev.yml'),
152
+ serviceName: serviceName,
153
+ database: null
154
+ });
155
+
156
+ return {
157
+ message: `Front-end service "${serviceName}" created successfully at ${serviceDir}`,
158
+ servicePath: serviceDir
159
+ };
108
160
  },
109
161
 
110
162
  /**
@@ -198,27 +250,15 @@ export const scaffolder = {
198
250
  // create random secrets
199
251
  if (file.relativePath === 'secrets.localdev.yml') {
200
252
  console.log('Creating random secrets: secrets.localdev.yml');
201
- const secretsPath = path.join(bootstrapDir, 'secrets.localdev.yml');
202
- const rawSecrets = fs.readFileSync(secretsPath, 'utf8');
203
- const parsedSecrets = yaml.load(rawSecrets);
204
-
205
- // generate random passwords
206
- Object.keys(parsedSecrets.services).forEach(serviceName => {
207
- Object.keys(parsedSecrets.services[serviceName]).forEach(key => {
208
- if (key.toLowerCase().includes('pass')) {
209
- parsedSecrets.services[serviceName][key] = helpers.generateRandomString(16);
210
- }
211
- });
212
- });
213
253
 
214
- // set random root api key
215
- cliApiKey = helpers.generateRandomString(32);
216
- parsedSecrets.services.user.ROOT_ADMIN_API_KEY = cliApiKey;
217
- parsedSecrets.services.user.ROOT_ADMIN_EMAIL = rootAdminEmail || 'admin@' + projectName + '.local';
218
-
219
- // save updated secrets file
220
- const newSecretsContent = yaml.dump(parsedSecrets);
221
- fs.writeFileSync(secretsPath, newSecretsContent, 'utf8');
254
+ const scaffoldedSecrets = scaffolder.scaffoldProjectSecrets({
255
+ secretsPath: sourcePath,
256
+ bootstrapDir: path.dirname(sourcePath),
257
+ projectName: projectName,
258
+ rootAdminEmail: rootAdminEmail
259
+ });
260
+ cliApiKey = scaffoldedSecrets.cliApiKey;
261
+ sourcePath = path.join(path.dirname(sourcePath), 'secrets.localdev.yml.temp');
222
262
  }
223
263
 
224
264
  fs.mkdirSync(path.dirname(targetPath), { recursive: true });
@@ -248,5 +288,163 @@ export const scaffolder = {
248
288
 
249
289
  console.log('g n a r e n g i n e - Created new project: ' + projectName);
250
290
  console.log('Run `gnar dev up` to start the development server');
291
+ },
292
+
293
+ /**
294
+ * Scaffold secrets for a new project
295
+ *
296
+ * @param {object} param
297
+ * @param {string} param.bootstrapDir - The bootstrap directory path
298
+ * @param {string} param.projectName - The project name
299
+ * @param {string} param.rootAdminEmail - The root admin email
300
+ * @returns {object} - An object containing the CLI API key
301
+ */
302
+ scaffoldProjectSecrets: function ({bootstrapDir, projectName, rootAdminEmail}) {
303
+ const secretsPath = path.join(bootstrapDir, 'secrets.localdev.yml');
304
+ const rawSecrets = fs.readFileSync(secretsPath, 'utf8');
305
+ const parsedSecrets = yaml.load(rawSecrets);
306
+
307
+ // generate random passwords
308
+ try {
309
+ Object.keys(parsedSecrets.services).forEach(serviceName => {
310
+ Object.keys(parsedSecrets.services[serviceName]).forEach(key => {
311
+ if (key.toLowerCase().includes('pass')) {
312
+ parsedSecrets.services[serviceName][key] = helpers.generateRandomString(16);
313
+ }
314
+ });
315
+ });
316
+ } catch (error) {
317
+ throw new Error('Error generating random passwords for project secrets: ' + error.message);
318
+ }
319
+
320
+ // set random root api key
321
+ const cliApiKey = helpers.generateRandomString(32);
322
+ parsedSecrets.services.user.ROOT_ADMIN_API_KEY = cliApiKey;
323
+ parsedSecrets.services.user.ROOT_ADMIN_EMAIL = rootAdminEmail || 'admin@' + projectName + '.local';
324
+
325
+ // save updated secrets file to a temp file version (so we don't overwrite the original in templates)
326
+ const newSecretsContent = yaml.dump(parsedSecrets);
327
+ fs.writeFileSync(secretsPath + '.temp', newSecretsContent, 'utf8');
328
+
329
+ return { cliApiKey };
330
+ },
331
+
332
+ /**
333
+ * Scaffold secrets for a new service
334
+ *
335
+ * @param {object} param
336
+ * @param {string} param.secretsPath - The path to the secrets file
337
+ * @param {string} param.serviceName - The service name
338
+ * @param {string} param.database - The database type
339
+ */
340
+ scaffoldServiceSecrets: function ({secretsPath, serviceName, database}) {
341
+ const rawSecrets = fs.readFileSync(secretsPath, 'utf8');
342
+ const parsedSecrets = yaml.load(rawSecrets);
343
+
344
+ if (!parsedSecrets.services) {
345
+ parsedSecrets.services = {};
346
+ }
347
+
348
+ parsedSecrets.services[serviceName] = {};
349
+
350
+ // generate random passwords
351
+ switch (database) {
352
+ case 'mysql':
353
+ parsedSecrets.services[serviceName]['MYSQL_USER'] = serviceName + '_user';
354
+ parsedSecrets.services[serviceName]['MYSQL_PASSWORD'] = helpers.generateRandomString(16);
355
+ parsedSecrets.services[serviceName]['MYSQL_DATABASE'] = serviceName + '_db';
356
+ parsedSecrets.services[serviceName]['MYSQL_HOST'] = 'db-mysql';
357
+ break;
358
+ case 'mongodb':
359
+ const mongoPassword = helpers.generateRandomString(16);
360
+ const mongoRootPassword = helpers.generateRandomString(16);
361
+ const mongoUser = serviceName + '_user';
362
+ const mongoDatabase = serviceName + '_db';
363
+ const mongoHost = 'db-mongo';
364
+ const mongoUrl = `mongodb://${mongoUser}:${mongoPassword}@${mongoHost}:27017/${mongoDatabase}`;
365
+
366
+ parsedSecrets.services[serviceName]['MONGO_URL'] = mongoUrl;
367
+ parsedSecrets.services[serviceName]['MONGO_USER'] = mongoUser;
368
+ parsedSecrets.services[serviceName]['MONGO_PASSWORD'] = mongoPassword;
369
+ parsedSecrets.services[serviceName]['MONGO_ROOT_PASSWORD'] = mongoRootPassword;
370
+ parsedSecrets.services[serviceName]['MONGO_DATABASE'] = mongoDatabase;
371
+ parsedSecrets.services[serviceName]['MONGO_HOST'] = mongoHost;
372
+ break;
373
+ default:
374
+ // no db
375
+ break;
376
+ }
377
+
378
+ // save updated secrets file
379
+ const newSecretsContent = yaml.dump(parsedSecrets);
380
+ fs.writeFileSync(secretsPath, newSecretsContent, 'utf8');
381
+ },
382
+
383
+ /**
384
+ * Scaffold deploy.yml for a new service
385
+ *
386
+ * @param {object} param
387
+ * @param {string} param.deployPath - The path to the deploy.yml file
388
+ * @param {string} param.serviceName - The service name
389
+ * @param {string} param.database - The database type
390
+ * @param {number} [param.hostPort=null] - The host port (optional)
391
+ */
392
+ scaffoldServiceDeployYml: function ({deployPath, serviceName, database, hostPort = null}) {
393
+ // parse existing deploy.yml
394
+ let deploy = yaml.load(fs.readFileSync(deployPath, 'utf8'));
395
+
396
+ // don't duplicate if service already exists
397
+ const existingService = deploy.config.services.find(svc => svc.name === serviceName);
398
+
399
+ if (existingService) {
400
+ return;
401
+ }
402
+
403
+ // get next available host port if not prescribed
404
+ if (!hostPort) {
405
+ const hostPorts = [];
406
+
407
+ deploy.config.services.forEach(svc => {
408
+ if (svc.ports && svc.ports.length > 0) {
409
+ svc.ports.forEach(portMapping => {
410
+ const [hostPort, containerPort] = portMapping.split(':').map(p => parseInt(p, 10));
411
+ hostPorts.push(hostPort);
412
+ });
413
+ }
414
+ });
415
+
416
+ hostPorts.sort((a, b) => a - b);
417
+ hostPort = hostPorts[hostPorts.length - 1] + 1;
418
+ }
419
+
420
+ // prepare new service config
421
+ const serviceConfig = {
422
+ name: serviceName,
423
+ listener_rules: {
424
+ paths: [
425
+ `/${serviceName}`
426
+ ]
427
+ },
428
+ min_tasks: 1,
429
+ max_tasks: 1,
430
+ command: ["npm", "run", "start:dev"],
431
+ ports: [
432
+ `${hostPort}:3000`
433
+ ]
434
+ }
435
+
436
+ // add database service if required
437
+ if (database) {
438
+ serviceConfig.depends_on = [
439
+ `db-${database}`
440
+ ]
441
+ }
442
+
443
+ // add to deploy config
444
+ deploy.config.services.push(serviceConfig);
445
+
446
+ // write deploy.yml file
447
+ const deployYmlContent = yaml.dump(deploy);
448
+ fs.writeFileSync(deployPath, deployYmlContent, 'utf8');
251
449
  }
252
450
  }
@@ -1,9 +1,12 @@
1
1
  # Dockerfile for {{pascalCase serviceName}} Service
2
- FROM gnarengine/service-core:1.0.0
2
+ FROM node:20-alpine
3
3
 
4
4
  # Set the working directory
5
5
  WORKDIR /usr/gnar_engine/app
6
6
 
7
+ # Define a global env var
8
+ ENV GLOBAL_SERVICE_BASE_DIR=/usr/gnar_engine/app/src/
9
+
7
10
  # Copy package.json and package-lock.json
8
11
  COPY ./services/{{serviceName}}/package*.json ./
9
12
 
@@ -1,18 +1,16 @@
1
1
  {
2
- "name": "{{lowerCase serviceName}}-service",
3
- "version": "1.0.0",
4
- "description": "{{pascalCase serviceName}} microservice for Gnar Engine",
5
- "main": "src/app.js",
6
- "scripts": {
7
- "start": "node src/app.js",
8
- "dev": "nodemon src/app.js"
9
- },
10
- "dependencies": {
11
- "@gnar-engine/core": "^1.0.1"
12
- },
13
- "devDependencies": {
14
- "nodemon": "^3.0.0"
15
- },
16
- "author": "Gnar Software",
17
- "license": "MIT"
2
+ "name": "{{lowerCase serviceName}}-service",
3
+ "version": "1.0.0",
4
+ "description": "{{pascalCase serviceName}} microservice for Gnar Engine",
5
+ "type": "module",
6
+ "scripts": {
7
+ "start": "node ./src/app.js",
8
+ "start:dev": "nodemon --watch ./src ./src/app.js",
9
+ "test": "jest --watchAll --verbose"
10
+ },
11
+ "author": "Gnar Software Ltd.",
12
+ "license": "ISC",
13
+ "dependencies": {
14
+ "@gnar-engine/core": "^1.0.1"
15
+ }
18
16
  }
@@ -0,0 +1,53 @@
1
+ import { message, http, logger, db, registerService, webSockets, test } from '@gnar-engine/core';
2
+ import { config } from './config.js';
3
+ import { messageHandlers } from './controllers/message.controller.js';
4
+ import { httpController as {{lowerCase serviceName}}PlatformHttpController } from './controllers/http.controller.js';
5
+
6
+ /**
7
+ * Initialise service
8
+ */
9
+ export const initService = async () => {
10
+
11
+ // Run migrations
12
+ if (config.db.type == 'mysql') {
13
+ db.migrations.runMigrations({config});
14
+ }
15
+
16
+ // Run seeders
17
+ db.seeders.runSeeders({config});
18
+
19
+ // Import command handlers after the command bus is initialised
20
+ await import('./commands/{{lowerCase serviceName}}.handler.js');
21
+ // Add more handlers as needed
22
+
23
+ // Initialise and register message handlers
24
+ await message.init({
25
+ config: config.message,
26
+ handlers: messageHandlers
27
+ });
28
+
29
+ // Initialise websocket client & server
30
+ await webSockets.init(config.webSockets, config.serviceName);
31
+
32
+ // Register http routes
33
+ await http.registerRoutes({
34
+ controllers: [
35
+ {{lowerCase serviceName}}PlatformHttpController,
36
+ ]
37
+ });
38
+
39
+ // Start the HTTP server
40
+ await http.start();
41
+
42
+ // Register service with control service
43
+ await registerService();
44
+
45
+ logger.info('G n a r E n g i n e | {{capitaliseFirstLetter serviceName}} Service initialised successfully.');
46
+
47
+ // Tests
48
+ if (config.environment === 'test' && config.runTests) {
49
+ test.runCommandTests({config});
50
+ }
51
+ }
52
+
53
+ initService();
@@ -1,8 +1,7 @@
1
1
  import { commands, logger, error } from '@gnar-engine/core';
2
- import { auth } from '../services/authentication.service.js';
3
2
  import { {{serviceName}} } from '../services/{{serviceName}}.service.js';
4
3
  import { config } from '../config.js';
5
- import { validate{{pascalCase serviceName}}, validateServiceAdmin{{pascalCase serviceName}}, validate{{pascalCase serviceName}}Update, validateServiceAdmin{{pascalCase serviceName}}Update } from '../schema/{{serviceName}}.schema.js';
4
+ import { validate{{pascalCase serviceName}} } from '../schema/{{serviceName}}.schema.js';
6
5
 
7
6
 
8
7
  /**
@@ -81,7 +80,7 @@ commands.register('{{serviceName}}Service.update{{pascalCase serviceName}}', asy
81
80
 
82
81
  return await {{serviceName}}.update({
83
82
  id: id,
84
- ...new{{pascalCase serviceName}}Data
83
+ updatedData: new{{pascalCase serviceName}}Data
85
84
  });
86
85
  });
87
86
 
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Gnar Engine Service Config
3
+ */
4
+ export const config = {
5
+ // service name
6
+ serviceName: '{{serviceName}}Service',
7
+
8
+ // microservice | modular-monolith
9
+ architecture: process.env.GLOBAL_ARCHITECTURE || 'microservice',
10
+
11
+ // web server
12
+ http: {
13
+ allowedOrigins: [],
14
+ allowedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
15
+ allowedHeaders: ['Content-Type', 'Authorization'],
16
+ rateLimiting: {
17
+ max: 5,
18
+ timeWindow: '1 minute',
19
+ }
20
+ },
21
+
22
+ // database
23
+ db: {
24
+ // type: mongodb | mysql
25
+ type: 'mongodb',
26
+
27
+ // MongoDB
28
+ host: process.env.{{upperCase serviceName}}_MONGO_HOST,
29
+ database: process.env.{{upperCase serviceName}}_MONGO_DATABASE,
30
+ user: process.env.{{upperCase serviceName}}_MONGO_USER,
31
+ password: process.env.{{upperCase serviceName}}_MONGO_PASSWORD,
32
+ port: process.env.{{upperCase serviceName}}_MONGO_PORT || 27017,
33
+ connectionArgs: {},
34
+ },
35
+
36
+ // message broker
37
+ message: {
38
+ url: process.env.RABBITMQ_URL,
39
+ queueName: '{{serviceName}}ServiceQueue',
40
+ prefetch: 20
41
+ },
42
+
43
+ webSockets: {
44
+ reconnectInterval: 5000,
45
+ maxInitialConnectionAttempts: 5
46
+ },
47
+
48
+ hashNameSpace: '{{uuid}}',
49
+ }
@@ -5,6 +5,10 @@ export const config = {
5
5
  // service name
6
6
  serviceName: '{{serviceName}}Service',
7
7
 
8
+ // environment
9
+ environment: process.env.{{upperCase serviceName}}_NODE_ENV || 'dev',
10
+ runTests: process.env.{{upperCase serviceName}}_RUN_TESTS || false,
11
+
8
12
  // microservice | modular-monolith
9
13
  architecture: process.env.GLOBAL_ARCHITECTURE || 'microservice',
10
14
 
@@ -40,9 +44,15 @@ export const config = {
40
44
 
41
45
  // message broker
42
46
  message: {
47
+ url: process.env.RABBITMQ_URL,
43
48
  queueName: '{{serviceName}}ServiceQueue',
44
49
  prefetch: 20
45
50
  },
46
51
 
52
+ webSockets: {
53
+ reconnectInterval: 5000,
54
+ maxInitialConnectionAttempts: 5
55
+ },
56
+
47
57
  hashNameSpace: '{{uuid}}',
48
58
  }
@@ -1,8 +1,8 @@
1
1
  import { schema } from '@gnar-engine/core';
2
2
  import { config } from '../config.js';
3
3
 
4
- export const AgentSchema = {
5
- schemaName: 'agentService.AgentSchema',
4
+ export const {{serviceName}}Schema = {
5
+ schemaName: '{{serviceName}}Service.{{serviceName}}Schema',
6
6
  schema: {
7
7
  type: 'object',
8
8
  properties: {
@@ -14,4 +14,4 @@ export const AgentSchema = {
14
14
  }
15
15
  };
16
16
 
17
- export const validateAgent = schema.compile(AgentSchema);
17
+ export const validate{{pascalCase serviceName}} = schema.compile({{serviceName}}Schema);