@gnar-engine/cli 1.0.0 → 1.0.1
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.
- package/assets/gnar-engine-logo-white.svg +9 -0
- package/bootstrap/deploy.localdev.yml +51 -0
- package/bootstrap/secrets.localdev.yml +27 -0
- package/bootstrap/services/agent/Dockerfile +23 -0
- package/bootstrap/services/agent/notes.md +28 -0
- package/bootstrap/services/agent/package.json +16 -0
- package/bootstrap/services/agent/src/app.js +52 -0
- package/bootstrap/services/agent/src/commands/agent.handler.js +104 -0
- package/bootstrap/services/agent/src/config.js +52 -0
- package/bootstrap/services/agent/src/controllers/http.controller.js +44 -0
- package/bootstrap/services/agent/src/controllers/message.controller.js +51 -0
- package/bootstrap/services/agent/src/db/migrations/01-init.js +50 -0
- package/bootstrap/services/agent/src/db/migrations/02-agent-service-init.js +36 -0
- package/bootstrap/services/agent/src/policies/agent.policy.js +13 -0
- package/bootstrap/services/agent/src/schema/Agent.schema.js +17 -0
- package/bootstrap/services/agent/src/services/agent.service.js +259 -0
- package/bootstrap/services/agent/src/services/chatgpt.service.js +46 -0
- package/bootstrap/services/agent/src/services/manifest.service.js +21 -0
- package/bootstrap/services/control/Dockerfile +23 -0
- package/bootstrap/services/control/Dockerfile.prod +37 -0
- package/bootstrap/services/control/README.md +25 -0
- package/bootstrap/services/control/package.json +16 -0
- package/bootstrap/services/control/src/app.js +45 -0
- package/bootstrap/services/control/src/commands/control.handler.js +231 -0
- package/bootstrap/services/control/src/commands/service.handler.js +81 -0
- package/bootstrap/services/control/src/commands/task.handler.js +247 -0
- package/bootstrap/services/control/src/config.js +55 -0
- package/bootstrap/services/control/src/controllers/http.controller.js +228 -0
- package/bootstrap/services/control/src/controllers/message.controller.js +40 -0
- package/bootstrap/services/control/src/db/migrations/01-init.js +50 -0
- package/bootstrap/services/control/src/db/migrations/02-control-service-init.js +60 -0
- package/bootstrap/services/control/src/db/migrations/03-alter-tasks.js +29 -0
- package/bootstrap/services/control/src/policies/task.policy.js +53 -0
- package/bootstrap/services/control/src/schema/control.schema.js +42 -0
- package/bootstrap/services/control/src/services/registry.service.js +83 -0
- package/bootstrap/services/control/src/services/reset.service.js +28 -0
- package/bootstrap/services/control/src/services/task.service.js +153 -0
- package/bootstrap/services/control/src/tests/control.test.js +50 -0
- package/bootstrap/services/notification/Dockerfile +23 -0
- package/bootstrap/services/notification/Dockerfile.prod +37 -0
- package/bootstrap/services/notification/README.md +3 -0
- package/bootstrap/services/notification/package.json +34 -0
- package/bootstrap/services/notification/src/app.js +51 -0
- package/bootstrap/services/notification/src/commands/command-bus.js +20 -0
- package/bootstrap/services/notification/src/commands/handlers/control.handler.js +18 -0
- package/bootstrap/services/notification/src/commands/handlers/notification.handler.js +157 -0
- package/bootstrap/services/notification/src/config.js +15 -0
- package/bootstrap/services/notification/src/controllers/message.controller.js +82 -0
- package/bootstrap/services/notification/src/services/logger.service.js +16 -0
- package/bootstrap/services/notification/src/services/ses.service.js +23 -0
- package/bootstrap/services/notification/src/templates/admin-order-recieved.hbs +136 -0
- package/bootstrap/services/notification/src/templates/admin-subscription-failed.hbs +87 -0
- package/bootstrap/services/notification/src/templates/customer-order-recieved.hbs +132 -0
- package/bootstrap/services/notification/src/templates/customer-subscription-failed.hbs +77 -0
- package/bootstrap/services/notification/src/tests/notification.test.js +0 -0
- package/bootstrap/services/portal/Dockerfile +23 -0
- package/bootstrap/services/portal/Dockerfile.remote +40 -0
- package/bootstrap/services/portal/README.md +22 -0
- package/bootstrap/services/portal/nginx.conf +12 -0
- package/bootstrap/services/portal/package.json +59 -0
- package/bootstrap/services/portal/public/favicon.ico +0 -0
- package/bootstrap/services/portal/public/gnar-white.png +0 -0
- package/bootstrap/services/portal/public/gnarengine-logo-black.png +0 -0
- package/bootstrap/services/portal/public/index.html +43 -0
- package/bootstrap/services/portal/public/logo192.png +0 -0
- package/bootstrap/services/portal/public/logo512.png +0 -0
- package/bootstrap/services/portal/public/manifest.json +25 -0
- package/bootstrap/services/portal/public/robots.txt +3 -0
- package/bootstrap/services/portal/src/App.js +56 -0
- package/bootstrap/services/portal/src/assets/Logo_Anchord_Black.svg +1 -0
- package/bootstrap/services/portal/src/assets/Logo_Anchord_Black_Green.svg +1 -0
- package/bootstrap/services/portal/src/assets/Logo_Anchord_White_Green.svg +1 -0
- package/bootstrap/services/portal/src/assets/activity.svg +3 -0
- package/bootstrap/services/portal/src/assets/arrow.svg +3 -0
- package/bootstrap/services/portal/src/assets/bin-white.svg +3 -0
- package/bootstrap/services/portal/src/assets/bin.svg +3 -0
- package/bootstrap/services/portal/src/assets/check.svg +3 -0
- package/bootstrap/services/portal/src/assets/chevron.svg +3 -0
- package/bootstrap/services/portal/src/assets/contact.svg +3 -0
- package/bootstrap/services/portal/src/assets/dots-vertical.svg +5 -0
- package/bootstrap/services/portal/src/assets/eye-off.svg +3 -0
- package/bootstrap/services/portal/src/assets/eye.svg +4 -0
- package/bootstrap/services/portal/src/assets/gnar-engine-black.svg +47 -0
- package/bootstrap/services/portal/src/assets/gnar-engine-white.svg +47 -0
- package/bootstrap/services/portal/src/assets/gnar_engine.svg +3 -0
- package/bootstrap/services/portal/src/assets/gnarengine-logo-black.png +0 -0
- package/bootstrap/services/portal/src/assets/home.svg +3 -0
- package/bootstrap/services/portal/src/assets/link.svg +3 -0
- package/bootstrap/services/portal/src/assets/lock.svg +3 -0
- package/bootstrap/services/portal/src/assets/package.svg +4 -0
- package/bootstrap/services/portal/src/assets/raffle.svg +3 -0
- package/bootstrap/services/portal/src/assets/settings.svg +4 -0
- package/bootstrap/services/portal/src/assets/shopping-bag.svg +3 -0
- package/bootstrap/services/portal/src/assets/user-black.svg +3 -0
- package/bootstrap/services/portal/src/assets/user.svg +3 -0
- package/bootstrap/services/portal/src/assets/users.svg +3 -0
- package/bootstrap/services/portal/src/assets/wallet.svg +3 -0
- package/bootstrap/services/portal/src/css/style.css +1007 -0
- package/bootstrap/services/portal/src/data/data.js +70 -0
- package/bootstrap/services/portal/src/features/attributeFormRow/AttributeFormRow.jsx +32 -0
- package/bootstrap/services/portal/src/features/billingShipping/BillingShipping.jsx +160 -0
- package/bootstrap/services/portal/src/features/crud/crudEdit.less +230 -0
- package/bootstrap/services/portal/src/features/crud/crudList.less +134 -0
- package/bootstrap/services/portal/src/features/crud/crudPage.less +31 -0
- package/bootstrap/services/portal/src/features/crudContact/CrudContactList.jsx +108 -0
- package/bootstrap/services/portal/src/features/crudContact/CrudContactSingle.jsx +243 -0
- package/bootstrap/services/portal/src/features/crudOrder/CrudOrderList.jsx +109 -0
- package/bootstrap/services/portal/src/features/crudOrder/CrudOrderSingle.jsx +315 -0
- package/bootstrap/services/portal/src/features/crudProducts/CrudProductList.jsx +104 -0
- package/bootstrap/services/portal/src/features/crudProducts/CrudProductSingle.jsx +388 -0
- package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesList.jsx +104 -0
- package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesSingle.jsx +208 -0
- package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionList.jsx +110 -0
- package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionSingle.jsx +261 -0
- package/bootstrap/services/portal/src/features/crudUser/CrudUserList.jsx +107 -0
- package/bootstrap/services/portal/src/features/crudUser/CrudUserSingle.jsx +402 -0
- package/bootstrap/services/portal/src/features/inventoryFormRow/InventoryFormRow.jsx +30 -0
- package/bootstrap/services/portal/src/features/lineItems/LineItems.jsx +113 -0
- package/bootstrap/services/portal/src/features/loginForm/LoginForm.jsx +56 -0
- package/bootstrap/services/portal/src/features/loginForm/loginForm.less +56 -0
- package/bootstrap/services/portal/src/features/notes/Notes.jsx +18 -0
- package/bootstrap/services/portal/src/features/passwordReset/PasswordResetForm.jsx +96 -0
- package/bootstrap/services/portal/src/features/passwordReset/PasswordResetRequestForm.jsx +74 -0
- package/bootstrap/services/portal/src/features/priceFormRow/PriceFormRow.jsx +102 -0
- package/bootstrap/services/portal/src/features/priceFormRow/priceFormRow.less +24 -0
- package/bootstrap/services/portal/src/features/raffleEntriesList/RaffleEntriesList.jsx +99 -0
- package/bootstrap/services/portal/src/features/raffleProductFormRow/RaffleProductFormRow.jsx +46 -0
- package/bootstrap/services/portal/src/features/sidebar/Sidebar.jsx +64 -0
- package/bootstrap/services/portal/src/features/sidebar/sidebar.less +49 -0
- package/bootstrap/services/portal/src/features/skus/Skus.jsx +109 -0
- package/bootstrap/services/portal/src/features/subscriptionSchedule/SubscriptionSchedule.jsx +44 -0
- package/bootstrap/services/portal/src/features/taxonomyFormRow/TaxonomyFormRow.jsx +32 -0
- package/bootstrap/services/portal/src/features/user/User.jsx +54 -0
- package/bootstrap/services/portal/src/features/user/user.less +57 -0
- package/bootstrap/services/portal/src/includes/utilities.js +259 -0
- package/bootstrap/services/portal/src/index.js +14 -0
- package/bootstrap/services/portal/src/layouts/CrudLayout.jsx +50 -0
- package/bootstrap/services/portal/src/layouts/LoginLayout.jsx +17 -0
- package/bootstrap/services/portal/src/layouts/PortalLayout.jsx +48 -0
- package/bootstrap/services/portal/src/layouts/loginLayout.less +33 -0
- package/bootstrap/services/portal/src/layouts/portalLayout.less +67 -0
- package/bootstrap/services/portal/src/pages/contacts/Contacts.jsx +199 -0
- package/bootstrap/services/portal/src/pages/dashboard/Dashboard.jsx +17 -0
- package/bootstrap/services/portal/src/pages/integrations/Integrations.jsx +10 -0
- package/bootstrap/services/portal/src/pages/login/Login.jsx +15 -0
- package/bootstrap/services/portal/src/pages/login/login.less +10 -0
- package/bootstrap/services/portal/src/pages/orders/Orders.jsx +199 -0
- package/bootstrap/services/portal/src/pages/passwordReset/PasswordResetPage.jsx +15 -0
- package/bootstrap/services/portal/src/pages/passwordResetRequest/PasswordResetRequestPage.jsx +15 -0
- package/bootstrap/services/portal/src/pages/payments/Payments.jsx +10 -0
- package/bootstrap/services/portal/src/pages/portal/Portal.jsx +43 -0
- package/bootstrap/services/portal/src/pages/products/Products.jsx +212 -0
- package/bootstrap/services/portal/src/pages/raffleEntries/RaffleEntries.jsx +124 -0
- package/bootstrap/services/portal/src/pages/raffles/Raffles.jsx +186 -0
- package/bootstrap/services/portal/src/pages/reports/Reports.jsx +10 -0
- package/bootstrap/services/portal/src/pages/settings/Settings.jsx +10 -0
- package/bootstrap/services/portal/src/pages/subscriptions/Subscriptions.jsx +199 -0
- package/bootstrap/services/portal/src/pages/users/Users.jsx +193 -0
- package/bootstrap/services/portal/src/pages/users/users.less +25 -0
- package/bootstrap/services/portal/src/slices/authSlice.js +71 -0
- package/bootstrap/services/portal/src/store/configureStore.js +12 -0
- package/bootstrap/services/portal/src/styles/global.less +159 -0
- package/bootstrap/services/portal/src/styles/inputs.less +157 -0
- package/bootstrap/services/portal/src/styles/main.less +26 -0
- package/bootstrap/services/portal/src/ui/collapsible/Collapsible.jsx +97 -0
- package/bootstrap/services/portal/src/ui/collapsible/collapsible.less +23 -0
- package/bootstrap/services/portal/src/ui/customCheckbox/CustomCheckbox.jsx +17 -0
- package/bootstrap/services/portal/src/ui/customCheckbox/customCheckbox.less +42 -0
- package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelect.jsx +63 -0
- package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelectPeriod.jsx +63 -0
- package/bootstrap/services/portal/src/ui/customSelect/CustomSelect.jsx +63 -0
- package/bootstrap/services/portal/src/ui/customSelect/customSelect.less +92 -0
- package/bootstrap/services/portal/src/ui/goBack/GoBack.jsx +19 -0
- package/bootstrap/services/portal/src/ui/loader/Loader.jsx +12 -0
- package/bootstrap/services/portal/src/ui/pagination/Pagination.jsx +23 -0
- package/bootstrap/services/portal/src/ui/repeater/Repeater.jsx +29 -0
- package/bootstrap/services/portal/src/ui/saveButton/SaveButton.jsx +69 -0
- package/bootstrap/services/portal/src/ui/saveButton/saveButton.less +0 -0
- package/bootstrap/services/rabbit-mq/Dockerfile.prod +9 -0
- package/bootstrap/services/user/Dockerfile +23 -0
- package/bootstrap/services/user/Dockerfile.prod +37 -0
- package/bootstrap/services/user/README.md +8 -0
- package/bootstrap/services/user/package.json +16 -0
- package/bootstrap/services/user/src/app.js +45 -0
- package/bootstrap/services/user/src/commands/session.handler.js +23 -0
- package/bootstrap/services/user/src/commands/user.handler.js +286 -0
- package/bootstrap/services/user/src/config.js +73 -0
- package/bootstrap/services/user/src/controllers/http.controller.js +156 -0
- package/bootstrap/services/user/src/controllers/message.controller.js +51 -0
- package/bootstrap/services/user/src/db/migrations/01-init.js +50 -0
- package/bootstrap/services/user/src/db/migrations/02-user-service-init.js +63 -0
- package/bootstrap/services/user/src/db/migrations/03-unauth-sessions.js +43 -0
- package/bootstrap/services/user/src/db/seeders/development/01-root-user.js +29 -0
- package/bootstrap/services/user/src/db/seeders/development/02-portal-admin-user.js +27 -0
- package/bootstrap/services/user/src/db/seeders/production/01-root-user.js +29 -0
- package/bootstrap/services/user/src/policies/user.policy.js +81 -0
- package/bootstrap/services/user/src/schema/user.schema.js +69 -0
- package/bootstrap/services/user/src/services/authentication.service.js +127 -0
- package/bootstrap/services/user/src/services/session.service.js +58 -0
- package/bootstrap/services/user/src/services/user.service.js +130 -0
- package/bootstrap/services/user/src/tests/user.test.js +126 -0
- package/package.json +3 -7
- package/src/agent/agent.client.js +28 -0
- package/src/agent/commands.js +48 -0
- package/src/cli.js +30 -0
- package/src/config.js +8 -0
- package/src/control/commands.js +156 -0
- package/src/control/control.client.js +127 -0
- package/src/dev/commands.js +71 -0
- package/src/dev/dev.service.js +320 -0
- package/src/engine/infra.js +142 -0
- package/src/helpers/helpers.js +63 -0
- package/src/profiles/command.js +170 -0
- package/src/profiles/profiles.client.js +101 -0
- package/src/scaffolder/commands.js +123 -0
- package/src/scaffolder/scaffolder.handler.js +252 -0
- package/src/services/client.js +174 -0
- package/templates/service/Dockerfile.hbs +20 -0
- package/templates/service/app.js.hbs +38 -0
- package/templates/service/commands/{{serviceName}}.handler.js.hbs +97 -0
- package/templates/service/config.js.hbs +48 -0
- package/templates/service/controllers/http.controller.js.hbs +87 -0
- package/templates/service/controllers/message.controller.js.hbs +51 -0
- package/templates/service/db/migrations/01-init.js.hbs +50 -0
- package/templates/service/db/migrations/02-{{lowerCase serviceName}}-service-init.js.hbs +23 -0
- package/templates/service/package.json.hbs +18 -0
- package/templates/service/policies/{{serviceName}}.policy.js.hbs +49 -0
- package/templates/service/schema/{{serviceName}}.schema.js.hbs +14 -0
- package/templates/service/services/{{serviceName}}.service.js.hbs +32 -0
- package/dist/cli.js +0 -18
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { logger, db, utils } from '@gnar-engine/core';
|
|
2
|
+
import { config } from '../config.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Authentication Service
|
|
7
|
+
*/
|
|
8
|
+
export const auth = {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create new authenticated session
|
|
12
|
+
*
|
|
13
|
+
* @param {*} userId
|
|
14
|
+
* @returns {string} Session token
|
|
15
|
+
*/
|
|
16
|
+
createSessionToken: async (userId) => {
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const token = utils.uuid();
|
|
20
|
+
|
|
21
|
+
const [result] = await db.execute(
|
|
22
|
+
'INSERT INTO `sessions` (`token`, `user_id`) VALUES (?, ?)',
|
|
23
|
+
[token, userId]
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return token;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
logger.error("Error creating session token: " + error);
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get authenticated user from token
|
|
35
|
+
*
|
|
36
|
+
* @param {string} token - Session token
|
|
37
|
+
* @returns {int} User ID
|
|
38
|
+
*/
|
|
39
|
+
getAuthenticatedUser: async (token) => {
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const [result] = await db.execute(
|
|
43
|
+
'SELECT * FROM `sessions` WHERE `token` = ?',
|
|
44
|
+
[token]
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (result.length === 0) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const session = result[0];
|
|
52
|
+
const createdAt = new Date(session.created_at);
|
|
53
|
+
const now = new Date();
|
|
54
|
+
const oneHour = 60 * 60 * 1000;
|
|
55
|
+
if (now - createdAt > oneHour) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return result[0].user_id;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
logger.error("Error fetching authenticated user:" + error);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Verify user credentials
|
|
68
|
+
*
|
|
69
|
+
* @param {Object} params
|
|
70
|
+
* @param {string} params.username - Username (or email)
|
|
71
|
+
* @param {string} params.password - Password
|
|
72
|
+
* @returns {int} User ID
|
|
73
|
+
*/
|
|
74
|
+
verifyCredentials: async ({username, password}) => {
|
|
75
|
+
|
|
76
|
+
const passwordHash = utils.hash(password, config.hashNameSpace);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
// try username
|
|
80
|
+
let [result] = await db.execute(
|
|
81
|
+
'SELECT * FROM `users` WHERE `username` = ? AND `password` = ?',
|
|
82
|
+
[username, passwordHash]
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (result.length > 0) {
|
|
86
|
+
return result[0].id;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// try username as email
|
|
90
|
+
[result] = await db.execute(
|
|
91
|
+
'SELECT * FROM `users` WHERE `email` = ? AND `password` = ?',
|
|
92
|
+
[username, passwordHash]
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
if (result.length > 0) {
|
|
96
|
+
return result[0].id;
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
logger.error("Error verifying credentials:" + error);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Verify API key with username
|
|
106
|
+
*
|
|
107
|
+
* @param {Object} params
|
|
108
|
+
* @param {string} params.apiKey - API key
|
|
109
|
+
* @param {string} params.username - Username
|
|
110
|
+
* @returns {int} User ID
|
|
111
|
+
*/
|
|
112
|
+
verifyApiKey: async ({apiKey, username}) => {
|
|
113
|
+
try {
|
|
114
|
+
const [result] = await db.execute(
|
|
115
|
+
'SELECT * FROM `users` WHERE `api_key` = ? AND `username` = ?',
|
|
116
|
+
[apiKey, username]
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (result.length > 0) {
|
|
120
|
+
return result[0].id;
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
logger.error("Error verifying API key:" + error);
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { logger, db, utils } from '@gnar-engine/core';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Authentication Service
|
|
6
|
+
*/
|
|
7
|
+
export const unauthenticatedSession = {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create new unauthenticated session token
|
|
11
|
+
*
|
|
12
|
+
* @returns {string} Session token
|
|
13
|
+
*/
|
|
14
|
+
createSessionToken: async () => {
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const sessionToken = utils.uuid();
|
|
18
|
+
|
|
19
|
+
const [result] = await db.execute(
|
|
20
|
+
'INSERT INTO `unauthenticated_sessions` (`token`) VALUES (?)',
|
|
21
|
+
[sessionToken]
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return sessionToken;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
logger.error("Error creating unauthenticated session token: " + error);
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Verify unauthenticated session token
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} params
|
|
35
|
+
* @param {string} params.sessionToken
|
|
36
|
+
* @returns {boolean} Session token valid
|
|
37
|
+
*/
|
|
38
|
+
verifySessionToken: async ({sessionToken}) => {
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
[result] = await db.execute(
|
|
42
|
+
'SELECT * FROM `unauthenticated_sessions` WHERE `token` = ?',
|
|
43
|
+
[sessionToken]
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (result.length > 0) {
|
|
47
|
+
if (result[0].expires_at > new Date()) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return false;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logger.error("Error verifying unauthenticated session token:", error);
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { logger, db, utils } from '@gnar-engine/core';
|
|
2
|
+
import { config} from '../config.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* User Service
|
|
7
|
+
*/
|
|
8
|
+
export const user = {
|
|
9
|
+
|
|
10
|
+
// Get all users
|
|
11
|
+
getAll: async () => {
|
|
12
|
+
try {
|
|
13
|
+
const [results, fields] = await db.execute(
|
|
14
|
+
'SELECT id, username, email, role FROM `users`'
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return results;
|
|
18
|
+
} catch (error) {
|
|
19
|
+
logger.error("Error fetching users:", error);
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Create a user
|
|
25
|
+
create: async ({email, role, password = null, username = null, apiKey = null}) => {
|
|
26
|
+
try {
|
|
27
|
+
const id = utils.uuid();
|
|
28
|
+
let passwordHash = null;
|
|
29
|
+
|
|
30
|
+
if (password) {
|
|
31
|
+
passwordHash = utils.hash(password, config.hashNameSpace);
|
|
32
|
+
}
|
|
33
|
+
console.log('creating user');
|
|
34
|
+
const [result] = await db.execute(
|
|
35
|
+
'INSERT INTO `users` (`id`, `email`, `password`, `username`, `role`, `api_key`) VALUES (?, ?, ?, ?, ?, ?)',
|
|
36
|
+
[id, email, passwordHash, username, role, apiKey]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const [newUser] = await db.execute(
|
|
40
|
+
'SELECT * FROM `users` WHERE `id` = ?',
|
|
41
|
+
[id]
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return newUser[0];
|
|
45
|
+
} catch (error) {
|
|
46
|
+
logger.error("Error creating user:", error);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// Get a user by ID
|
|
52
|
+
getById: async ({id}) => {
|
|
53
|
+
try {
|
|
54
|
+
|
|
55
|
+
const [result] = await db.execute(
|
|
56
|
+
'SELECT * FROM `users` WHERE `id` = ?',
|
|
57
|
+
[id]
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (!result || result.length === 0) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return result[0];
|
|
65
|
+
} catch (error) {
|
|
66
|
+
logger.error("Error fetching user:", error);
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// Get a user by email
|
|
72
|
+
getByEmail: async ({email}) => {
|
|
73
|
+
try {
|
|
74
|
+
const [result] = await db.execute(
|
|
75
|
+
'SELECT * FROM `users` WHERE `email` = ?',
|
|
76
|
+
[email]
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
if (!result || result.length === 0) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return result[0];
|
|
84
|
+
} catch (error) {
|
|
85
|
+
logger.error("Error fetching user by email:", error);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Update a user
|
|
91
|
+
update: async ({id, username, email, role}) => {
|
|
92
|
+
try {
|
|
93
|
+
const [result] = await db.execute(
|
|
94
|
+
'UPDATE `users` SET `username` = ?, `email` = ?, `role` = ? WHERE `id` = ?',
|
|
95
|
+
[username, email, role, id]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const [updatedUser] = await db.execute(
|
|
99
|
+
'SELECT * FROM `users` WHERE `id` = ?',
|
|
100
|
+
[id]
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return updatedUser[0];
|
|
104
|
+
} catch (error) {
|
|
105
|
+
logger.error("Error updating user:", error);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// Delete a user
|
|
111
|
+
delete: async ({id}) => {
|
|
112
|
+
try {
|
|
113
|
+
const [sessionResult] = await db.execute(
|
|
114
|
+
'DELETE FROM sessions WHERE user_id = ?',
|
|
115
|
+
[id]
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const [userResult] = await db.execute(
|
|
119
|
+
'DELETE FROM `users` WHERE `id` = ?',
|
|
120
|
+
[id]
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
return userResult.affectedRows;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
logger.error("Error deleting user:", error);
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const request = require('supertest');
|
|
2
|
+
const url = 'http://localhost';
|
|
3
|
+
|
|
4
|
+
describe('User API', () => {
|
|
5
|
+
|
|
6
|
+
let adminAuthToken;
|
|
7
|
+
let customerAuthToken;
|
|
8
|
+
let userId;
|
|
9
|
+
let testCustomerEmail;
|
|
10
|
+
|
|
11
|
+
beforeAll(async () => {
|
|
12
|
+
// check we are not in production mode
|
|
13
|
+
if (process.env.NODE_ENV === 'production') {
|
|
14
|
+
throw new Error('Do not run tests in production mode!');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
testCustomerEmail = 'customertest13@gnar.co.uk';
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Test authenticate with email and password
|
|
21
|
+
it('POST /authenticate (as admin)', async () => {
|
|
22
|
+
const response = await request(url).post('/authenticate')
|
|
23
|
+
.set('Content-Type', 'application/json')
|
|
24
|
+
.send({
|
|
25
|
+
username: 'root@gnar.co.uk',
|
|
26
|
+
password: 'gn4rlyR00tP0rt4lP4ss'
|
|
27
|
+
});
|
|
28
|
+
console.log(response.body);
|
|
29
|
+
expect(response.status).toBe(200);
|
|
30
|
+
expect(response.body).toHaveProperty('token');
|
|
31
|
+
|
|
32
|
+
adminAuthToken = response.body.token;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Create new customer user (success no auth required)
|
|
36
|
+
it('POST /users (create new customer user no auth required)', async () => {
|
|
37
|
+
const response = await request(url).post('/users')
|
|
38
|
+
.set('Content-Type', 'application/json')
|
|
39
|
+
.send({
|
|
40
|
+
user:
|
|
41
|
+
{
|
|
42
|
+
email: testCustomerEmail,
|
|
43
|
+
password: 'password1234'
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
console.log(response.body);
|
|
47
|
+
expect(response.status).toBe(200);
|
|
48
|
+
expect(response.body.users[0].email).toBe(testCustomerEmail);
|
|
49
|
+
|
|
50
|
+
// Save the new user id
|
|
51
|
+
userId = response.body.users[0].id;
|
|
52
|
+
console.log('New user id: ' + userId);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Test authenticate with new user
|
|
56
|
+
it('POST /authenticate (as new customer user)', async () => {
|
|
57
|
+
const response = await request(url).post('/authenticate')
|
|
58
|
+
.set('Content-Type', 'application/json')
|
|
59
|
+
.send({
|
|
60
|
+
username: testCustomerEmail,
|
|
61
|
+
password: 'password1234'
|
|
62
|
+
});
|
|
63
|
+
console.log(response.body);
|
|
64
|
+
expect(response.status).toBe(200);
|
|
65
|
+
expect(response.body).toHaveProperty('token');
|
|
66
|
+
|
|
67
|
+
customerAuthToken = response.body.token;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Fetch single customer user (as customer)
|
|
71
|
+
it('GET /users/{id} (as customer)', async () => {
|
|
72
|
+
const response = await request(url).get('/users/' + userId)
|
|
73
|
+
.set('Authorization', 'Bearer ' + customerAuthToken);
|
|
74
|
+
console.log(response.body);
|
|
75
|
+
expect(response.status).toBe(200);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Fetch all users (not authorised as customer)
|
|
79
|
+
it('GET /users (not authorised as customer)', async () => {
|
|
80
|
+
const response = await request(url).get('/users')
|
|
81
|
+
.set('Authorization', 'Bearer ' + customerAuthToken);
|
|
82
|
+
console.log(response.body);
|
|
83
|
+
expect(response.status).toBe(403);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Fetch all users (success as admin)
|
|
87
|
+
it('GET /users (as admin)', async () => {
|
|
88
|
+
const response = await request(url).get('/users')
|
|
89
|
+
.set('Authorization', 'Bearer ' + adminAuthToken);
|
|
90
|
+
console.log(response.body);
|
|
91
|
+
expect(response.status).toBe(200);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Update customer user (as customer)
|
|
95
|
+
it('POST /users/{id} (as customer)', async () => {
|
|
96
|
+
const response = await request(url).post('/users/' + userId)
|
|
97
|
+
.set('Authorization', 'Bearer ' + customerAuthToken)
|
|
98
|
+
.set('Content-Type', 'application/json')
|
|
99
|
+
.send({
|
|
100
|
+
email: 'changedcustomeremail2@gnar.co.uk'
|
|
101
|
+
});
|
|
102
|
+
console.log(response.body);
|
|
103
|
+
expect(response.status).toBe(200);
|
|
104
|
+
expect(response.body.user.email).toBe('changedcustomeremail2@gnar.co.uk');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Update customer user (check cannot elevate role to admin)
|
|
108
|
+
it('POST /users/{id} (as customer)', async () => {
|
|
109
|
+
const response = await request(url).post('/users/' + userId)
|
|
110
|
+
.set('Authorization', 'Bearer ' + customerAuthToken)
|
|
111
|
+
.set('Content-Type', 'application/json')
|
|
112
|
+
.send({
|
|
113
|
+
role: 'service_admin'
|
|
114
|
+
});
|
|
115
|
+
console.log(response.body);
|
|
116
|
+
expect(response.status).toBe(403);
|
|
117
|
+
});-
|
|
118
|
+
|
|
119
|
+
// Delete customer user (as admin)
|
|
120
|
+
it('DELETE /users/{id} (as admin)', async () => {
|
|
121
|
+
const response = await request(url).delete('/users/' + userId)
|
|
122
|
+
.set('Authorization', 'Bearer ' + adminAuthToken);
|
|
123
|
+
console.log(response.body);
|
|
124
|
+
expect(response.status).toBe(200);
|
|
125
|
+
});
|
|
126
|
+
});
|
package/package.json
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gnar-engine/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Gnar Engine Development Framework CLI: Project bootstrap, scaffolder & control plane.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"gnar": "./
|
|
8
|
-
},
|
|
9
|
-
"main": "./dist/cli.js",
|
|
10
|
-
"files": ["dist"],
|
|
11
|
-
"scripts": {
|
|
12
|
-
"build": "esbuild src/cli.js --minify --bundle --format=esm --platform=node --outfile=dist/cli.js --packages=external"
|
|
7
|
+
"gnar": "./src/cli.js"
|
|
13
8
|
},
|
|
9
|
+
"main": "./src/cli.js",
|
|
14
10
|
"author": "Gnar Software Ltd.",
|
|
15
11
|
"license": "MIT",
|
|
16
12
|
"repository": {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import client from "../services/client.js";
|
|
2
|
+
|
|
3
|
+
export const agent = {
|
|
4
|
+
|
|
5
|
+
prompt: async (input, chatId) => {
|
|
6
|
+
try {
|
|
7
|
+
const response = await client.post('/agent/prompt', {
|
|
8
|
+
textInput: input,
|
|
9
|
+
chatId: chatId
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
if (response.status !== 200) {
|
|
13
|
+
throw new Error("Failed to prompt agent");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//console.log("Agent response: " + response.data);
|
|
17
|
+
|
|
18
|
+
return response.data;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
// get response message if available
|
|
21
|
+
if (error?.response?.data?.error) {
|
|
22
|
+
return {error: error.response.data.error};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {error: "Agent prompt failed: " + error};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// control/commands.js
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { agent } from './agent.client.js';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
|
|
7
|
+
export function registerAgentCommands(program) {
|
|
8
|
+
const agentCmd = new Command('agent').description('🤖 LLM Agent Commands');
|
|
9
|
+
|
|
10
|
+
agentCmd
|
|
11
|
+
.command('session')
|
|
12
|
+
.description('🤖 Prompt the Engine Agent')
|
|
13
|
+
.action(async (options) => {
|
|
14
|
+
let chatId;
|
|
15
|
+
|
|
16
|
+
while (true) {
|
|
17
|
+
const input = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'text',
|
|
20
|
+
name: 'prompt',
|
|
21
|
+
message: 'Enter your prompt (or type "exit" to quit):'
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
if (input.prompt.toLowerCase() === 'exit') {
|
|
26
|
+
console.log('Exiting Engine agent.');
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const response = await agent.prompt(input.prompt, chatId);
|
|
32
|
+
|
|
33
|
+
if (response.error) {
|
|
34
|
+
console.error('❌ ' + response.error);
|
|
35
|
+
} else if (!response.structuredResponse?.responseText) {
|
|
36
|
+
console.error('❌ Error parsing reply');
|
|
37
|
+
} else {
|
|
38
|
+
console.log(response.structuredResponse.responseText);
|
|
39
|
+
chatId = response.chatId;
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('❌ Error prompting agent:', error.message);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
program.addCommand(agentCmd);
|
|
48
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { registerProfileCommand } from './profiles/command.js';
|
|
5
|
+
import { registerDevCommands } from './dev/commands.js';
|
|
6
|
+
import { registerControlCommands } from './control/commands.js';
|
|
7
|
+
import { registerScaffolderCommands } from './scaffolder/commands.js';
|
|
8
|
+
import { registerAgentCommands } from './agent/commands.js';
|
|
9
|
+
|
|
10
|
+
// Create a new program
|
|
11
|
+
const program = new Command();
|
|
12
|
+
|
|
13
|
+
// Register CLI commands
|
|
14
|
+
registerDevCommands(program);
|
|
15
|
+
registerProfileCommand(program);
|
|
16
|
+
registerControlCommands(program);
|
|
17
|
+
registerScaffolderCommands(program);
|
|
18
|
+
registerAgentCommands(program);
|
|
19
|
+
|
|
20
|
+
// Help
|
|
21
|
+
program
|
|
22
|
+
.command('help [command]')
|
|
23
|
+
.description('❓ Display help for command');
|
|
24
|
+
|
|
25
|
+
program.addHelpText('beforeAll', `
|
|
26
|
+
G n a r E n g i n e - A powerful, AI ready microservice framework for modern applications.
|
|
27
|
+
`);
|
|
28
|
+
|
|
29
|
+
// Parse CLI input
|
|
30
|
+
program.parse(process.argv);
|