@paralect/hive 0.1.48 → 0.1.50-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/.cursor/commands/deslop.md +12 -0
  2. package/.hive/.babelrc +3 -0
  3. package/.hive/.cursor/commands/add-endpoint.md +262 -0
  4. package/.hive/.cursor/commands/add-handler.md +137 -0
  5. package/.hive/.cursor/commands/add-middleware.md +95 -0
  6. package/.hive/.cursor/commands/add-resource.md +71 -0
  7. package/.hive/.cursor/commands/add-scheduler.md +138 -0
  8. package/.hive/.cursor/commands/add-service.md +188 -0
  9. package/.hive/.cursor/skills/hive-auth/SKILL.md +134 -0
  10. package/.hive/.cursor/skills/hive-database/SKILL.md +103 -0
  11. package/.hive/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  12. package/.hive/.cursor/skills/hive-handler/SKILL.md +88 -0
  13. package/.hive/.cursor/skills/hive-mapping/SKILL.md +85 -0
  14. package/.hive/.cursor/skills/hive-middleware/SKILL.md +104 -0
  15. package/.hive/.cursor/skills/hive-overview/SKILL.md +50 -0
  16. package/.hive/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  17. package/.hive/.cursor/skills/hive-schema/SKILL.md +73 -0
  18. package/.hive/.cursor/skills/hive-service/SKILL.md +90 -0
  19. package/.hive/.dockerignore +1 -0
  20. package/.hive/Dockerfile +22 -0
  21. package/.hive/Dockerfile.dev +33 -0
  22. package/.hive/Dockerfile.prod +29 -0
  23. package/.hive/README.md +11 -0
  24. package/.hive/bin/deploy.sh +5 -0
  25. package/.hive/bin/start.sh +2 -0
  26. package/.hive/bootstrap-hive.js +118 -0
  27. package/.hive/deploy/api/Chart.yaml +6 -0
  28. package/.hive/deploy/api/staging.yaml +3 -0
  29. package/.hive/deploy/api/templates/deployment.yaml +44 -0
  30. package/.hive/deploy/api/templates/ingress.yaml +26 -0
  31. package/.hive/deploy/api/templates/service.yaml +14 -0
  32. package/.hive/deploy/script/Dockerfile +39 -0
  33. package/.hive/deploy/script/package-lock.json +1499 -0
  34. package/.hive/deploy/script/package.json +12 -0
  35. package/.hive/deploy/script/src/config.js +48 -0
  36. package/.hive/deploy/script/src/index.js +108 -0
  37. package/.hive/deploy/script/src/util.js +19 -0
  38. package/.hive/initial-data.json +176 -0
  39. package/.hive/package-lock.json +10242 -0
  40. package/.hive/package.json +98 -0
  41. package/.hive/ship_logo.png +0 -0
  42. package/.hive/src/app-config/app.js +3 -0
  43. package/.hive/src/app-config/assertEnv.js +15 -0
  44. package/.hive/src/app-config/index.js +62 -0
  45. package/.hive/src/app.js +69 -0
  46. package/.hive/src/assets/emails/components/header.mjml +13 -0
  47. package/.hive/src/assets/emails/dist/.gitkeep +0 -0
  48. package/.hive/src/assets/emails/signup-welcome.mjml +34 -0
  49. package/.hive/src/assets/emails/styles/index.mjml +77 -0
  50. package/.hive/src/autoMap/addHandlers.js +142 -0
  51. package/.hive/src/autoMap/getDependentFields.js +37 -0
  52. package/.hive/src/autoMap/mapSchema.js +99 -0
  53. package/.hive/src/autoMap/schemaMappings.js +13 -0
  54. package/.hive/src/autoMap/schemaMappings.json +3 -0
  55. package/.hive/src/bullMqBus.js +21 -0
  56. package/.hive/src/bullMqWrapper.js +23 -0
  57. package/.hive/src/db.js +52 -0
  58. package/.hive/src/emails/MyEmailComponent.jsx +14 -0
  59. package/.hive/src/emails/compiled/MyEmailComponent.js +18 -0
  60. package/.hive/src/emails/compiled/compiled/MyEmailComponent.js +18 -0
  61. package/.hive/src/helpers/db/ifUpdated.js +22 -0
  62. package/.hive/src/helpers/getMiddlewares.js +38 -0
  63. package/.hive/src/helpers/getResourceEndpoints.js +28 -0
  64. package/.hive/src/helpers/getResources.js +32 -0
  65. package/.hive/src/helpers/getSchemas.js +50 -0
  66. package/.hive/src/helpers/importHandlers.js +29 -0
  67. package/.hive/src/helpers/isZodArray.js +13 -0
  68. package/.hive/src/helpers/prettierFormat.js +8 -0
  69. package/.hive/src/helpers/schema/db.schema.js +9 -0
  70. package/.hive/src/helpers/schema/pagination.schema.js +14 -0
  71. package/.hive/src/ioEmitter.js +9 -0
  72. package/.hive/src/jsconfig.json +5 -0
  73. package/.hive/src/lib/node-mongo/.github/workflows/npm-publish.yml +32 -0
  74. package/.hive/src/lib/node-mongo/API.md +654 -0
  75. package/.hive/src/lib/node-mongo/CHANGELOG.md +98 -0
  76. package/.hive/src/lib/node-mongo/README.md +97 -0
  77. package/.hive/src/lib/node-mongo/package-lock.json +3682 -0
  78. package/.hive/src/lib/node-mongo/package.json +74 -0
  79. package/.hive/src/lib/node-mongo/src/index.js +64 -0
  80. package/.hive/src/lib/node-mongo/src/mongo-query-service.js +78 -0
  81. package/.hive/src/lib/node-mongo/src/mongo-service-error.js +15 -0
  82. package/.hive/src/lib/node-mongo/src/mongo-service.js +303 -0
  83. package/.hive/src/logger.js +43 -0
  84. package/.hive/src/middlewares/allowNoAuth.js +9 -0
  85. package/.hive/src/middlewares/attachUser.js +41 -0
  86. package/.hive/src/middlewares/global/extractUserTokens.js +15 -0
  87. package/.hive/src/middlewares/global/tryToAttachUser.js +33 -0
  88. package/.hive/src/middlewares/isAuthorized.js +18 -0
  89. package/.hive/src/middlewares/shouldExist.js +37 -0
  90. package/.hive/src/middlewares/shouldNotExist.js +19 -0
  91. package/.hive/src/middlewares/uploadFile.js +5 -0
  92. package/.hive/src/middlewares/validate.js +32 -0
  93. package/.hive/src/migrations/migration.js +8 -0
  94. package/.hive/src/migrations/migration.service.js +73 -0
  95. package/.hive/src/migrations/migrations/1.js +22 -0
  96. package/.hive/src/migrations/migrations-log/migration-log.schema.js +13 -0
  97. package/.hive/src/migrations/migrations-log/migration-log.service.js +50 -0
  98. package/.hive/src/migrations/migrations.schema.js +6 -0
  99. package/.hive/src/migrations/migrator.js +75 -0
  100. package/.hive/src/migrator.js +4 -0
  101. package/.hive/src/resources/_dev/endpoints/triggerSchedulerHandler.js +32 -0
  102. package/.hive/src/resources/health/endpoints/get.js +19 -0
  103. package/.hive/src/resources/schemaMappings/schemaMappings.schema.js +6 -0
  104. package/.hive/src/resources/tokens/methods/generateSecureToken.js +9 -0
  105. package/.hive/src/resources/tokens/methods/setToken.js +8 -0
  106. package/.hive/src/resources/tokens/methods/storeToken.js +35 -0
  107. package/.hive/src/resources/tokens/tokens.schema.js +11 -0
  108. package/.hive/src/resources/users/endpoints/getCurrentUser.js +14 -0
  109. package/.hive/src/resources/users/endpoints/getUserProfile.js +19 -0
  110. package/.hive/src/resources/users/handlers/test.js +1 -0
  111. package/.hive/src/resources/users/methods/ensureUserCreated.js +68 -0
  112. package/.hive/src/resources/users/users.schema.js +16 -0
  113. package/.hive/src/routes/index.js +172 -0
  114. package/.hive/src/routes/middlewares/attachCustomErrors.js +28 -0
  115. package/.hive/src/routes/middlewares/routeErrorHandler.js +27 -0
  116. package/.hive/src/scheduler/handlers/sendDailyReport.example.js +7 -0
  117. package/.hive/src/scheduler.js +32 -0
  118. package/.hive/src/security.util.js +38 -0
  119. package/.hive/src/services/emailService.js +15 -0
  120. package/.hive/src/services/globalTest.js +0 -0
  121. package/.hive/src/services/setCookie.js +21 -0
  122. package/.hive/src/socketIo.js +99 -0
  123. package/.hive/tsconfig.json +31 -0
  124. package/AGENTS.md +96 -0
  125. package/README.md +271 -0
  126. package/cli/helpers/docker.js +59 -0
  127. package/cli/helpers/envCheck.js +123 -0
  128. package/cli/helpers/findPort.js +32 -0
  129. package/cli/hive.js +155 -15
  130. package/package.json +1 -1
  131. package/starter/.cursor/commands/add-endpoint.md +262 -0
  132. package/starter/.cursor/commands/add-handler.md +137 -0
  133. package/starter/.cursor/commands/add-middleware.md +95 -0
  134. package/starter/.cursor/commands/add-resource.md +71 -0
  135. package/starter/.cursor/commands/add-scheduler.md +138 -0
  136. package/starter/.cursor/commands/add-service.md +188 -0
  137. package/starter/.cursor/skills/hive-auth/SKILL.md +134 -0
  138. package/starter/.cursor/skills/hive-database/SKILL.md +103 -0
  139. package/starter/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  140. package/starter/.cursor/skills/hive-handler/SKILL.md +88 -0
  141. package/starter/.cursor/skills/hive-mapping/SKILL.md +85 -0
  142. package/starter/.cursor/skills/hive-middleware/SKILL.md +104 -0
  143. package/starter/.cursor/skills/hive-overview/SKILL.md +50 -0
  144. package/starter/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  145. package/starter/.cursor/skills/hive-schema/SKILL.md +73 -0
  146. package/starter/.cursor/skills/hive-service/SKILL.md +90 -0
  147. package/starter/src/app.js +4 -3
  148. package/test-app/.cursor/commands/add-endpoint.md +262 -0
  149. package/test-app/.cursor/commands/add-handler.md +137 -0
  150. package/test-app/.cursor/commands/add-middleware.md +95 -0
  151. package/test-app/.cursor/commands/add-resource.md +71 -0
  152. package/test-app/.cursor/commands/add-scheduler.md +138 -0
  153. package/test-app/.cursor/commands/add-service.md +188 -0
  154. package/test-app/.cursor/skills/hive-auth/SKILL.md +134 -0
  155. package/test-app/.cursor/skills/hive-database/SKILL.md +103 -0
  156. package/test-app/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  157. package/test-app/.cursor/skills/hive-handler/SKILL.md +88 -0
  158. package/test-app/.cursor/skills/hive-mapping/SKILL.md +85 -0
  159. package/test-app/.cursor/skills/hive-middleware/SKILL.md +104 -0
  160. package/test-app/.cursor/skills/hive-overview/SKILL.md +50 -0
  161. package/test-app/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  162. package/test-app/.cursor/skills/hive-schema/SKILL.md +73 -0
  163. package/test-app/.cursor/skills/hive-service/SKILL.md +90 -0
  164. package/test-app/package-lock.json +8684 -0
  165. package/test-app/package.json +21 -0
@@ -0,0 +1,172 @@
1
+ import _ from "lodash";
2
+ import getResources from "helpers/getResources";
3
+ import getMiddlewares from "helpers/getMiddlewares";
4
+ import getResourceEndpoints from "helpers/getResourceEndpoints";
5
+ import mount from "koa-mount";
6
+ import Router from "@koa/router";
7
+ import validate from "middlewares/validate";
8
+ import db from "db";
9
+ import tryToAttachUser from "middlewares/global/tryToAttachUser";
10
+ import attachCustomErrors from "./middlewares/attachCustomErrors";
11
+ import routeErrorHandler from "./middlewares/routeErrorHandler";
12
+ import isAuthorized from "middlewares/isAuthorized";
13
+ import config from 'app-config';
14
+
15
+ const requestLogService = db.createService("_request_logs");
16
+
17
+ const logRequestToMongo = async (ctx, next) => {
18
+ const startedOn = new Date();
19
+
20
+ const saveLog = async ({ error = null } = {}) => {
21
+ if (ctx.state.isSkipLog) {
22
+ return;
23
+ }
24
+
25
+ if (ctx.state.resourceName && ctx.state.endpoint) {
26
+ const requestLog = {
27
+ isSuccess: true,
28
+ request: {
29
+ url: ctx.originalUrl,
30
+ method: ctx.request.method,
31
+ query: ctx.query,
32
+ body: ctx.request.body,
33
+ params: ctx.params,
34
+ headers: ctx.headers,
35
+ },
36
+ response: {
37
+ status: ctx.status,
38
+ body: ctx.body,
39
+ },
40
+ resourceName: ctx.state.resourceName,
41
+ endpoint: ctx.state.endpoint,
42
+ time: new Date() - startedOn,
43
+ };
44
+ if (error) {
45
+ requestLog.isSuccess = false;
46
+ requestLog.error = {
47
+ message: error.message,
48
+ stack: error.stack,
49
+ };
50
+ }
51
+ await requestLogService.create(requestLog);
52
+ }
53
+ };
54
+
55
+ try {
56
+ await next();
57
+
58
+ await saveLog({ error: ctx.state.error });
59
+
60
+ } catch (err) {
61
+ await saveLog({ error: err });
62
+ throw err;
63
+ }
64
+ };
65
+
66
+ export default async (app) => {
67
+ app.use(logRequestToMongo);
68
+ app.use(attachCustomErrors);
69
+ app.use(routeErrorHandler);
70
+ app.use(tryToAttachUser);
71
+
72
+ const [resources, allMiddlewares] = await Promise.all([getResources(), getMiddlewares()]);
73
+
74
+ await Promise.all(_.map(resources, async ({ name: resourceName }) => {
75
+ const resourceRouter = new Router();
76
+ const globalRouter = new Router();
77
+ const endpoints = await Promise.all((await getResourceEndpoints(resourceName))
78
+ .map(async ({ file: endpointFile, name }) => {
79
+ let endpointDef = (await import(endpointFile));
80
+
81
+ if (!endpointDef.endpoint) {
82
+ console.log('missing endpoint for', name);
83
+ }
84
+ endpointDef.endpoint.name = name;
85
+
86
+ return {
87
+ endpoint: endpointDef.endpoint,
88
+ requestSchema: endpointDef.requestSchema,
89
+ middlewares: endpointDef.middlewares,
90
+ handler: endpointDef.handler,
91
+ };
92
+ })
93
+ .sort((e) => {
94
+ e.endpoint = e.endpoint || { method: "get", url: "/" };
95
+ const url = e.endpoint.url || e.endpoint.absoluteUrl;
96
+ if (url.includes("/:")) {
97
+ return 1;
98
+ }
99
+ return -1;
100
+ }));
101
+
102
+ endpoints.forEach(({ endpoint, requestSchema, middlewares = [], handler }) => {
103
+ let targetRouter;
104
+ console.log('[routes] Register endpoint', resourceName, endpoint?.method || 'GET', endpoint?.url);
105
+
106
+ let url = endpoint.absoluteUrl || endpoint.url;
107
+
108
+ if (url.startsWith("$HOST/")) {
109
+ url = url.replace("$HOST", "");
110
+ targetRouter = globalRouter;
111
+ } else if (endpoint.absoluteUrl) {
112
+ targetRouter = globalRouter;
113
+ } else {
114
+ targetRouter = resourceRouter;
115
+ }
116
+
117
+ const globalMiddleware = allMiddlewares.find(m => m.name === 'global');
118
+
119
+ if (globalMiddleware) {
120
+ globalMiddleware.runOrder = 0;
121
+ middlewares.unshift(globalMiddleware.fn);
122
+ }
123
+
124
+ middlewares = middlewares.map(middleware => {
125
+ if (_.isString(middleware)) {
126
+ if (!allMiddlewares.find(m => m.name === middleware)) {
127
+ throw new Error(`Middleware ${middleware} not found`);
128
+ }
129
+
130
+ middleware = allMiddlewares.find(m => m.name === middleware).fn;
131
+ } else if (middleware?.name && middleware?.args) {
132
+ if (!allMiddlewares.find(m => m.name === middleware.name)) {
133
+ throw new Error(`Middleware ${middleware.name} not found`);
134
+ };
135
+ middleware = allMiddlewares.find(m => m.name === middleware.name).fn(...middleware.args);
136
+ }
137
+
138
+ return middleware;
139
+ }).map(middleware => {
140
+ middleware.runOrder = _.isNumber(middleware.runOrder) ? middleware.runOrder : 1;
141
+ return middleware;
142
+ });
143
+
144
+
145
+ if (config._hive.isRequireAuthAllEndpoints) {
146
+ isAuthorized.runOrder = 0;
147
+ middlewares.unshift(isAuthorized);
148
+ }
149
+
150
+ targetRouter[endpoint.method?.toLowerCase() || "get"](
151
+ url,
152
+ async (ctx, next) => {
153
+ ctx.state.resourceName = resourceName;
154
+ ctx.state.endpoint = endpoint;
155
+ await next();
156
+ },
157
+ validate(requestSchema),
158
+ ..._.sortBy(middlewares, m => m.runOrder),
159
+ async ctx => {
160
+ const result = await handler(ctx);
161
+
162
+ if (!ctx.body) {
163
+ ctx.body = result || { isOk: true };
164
+ }
165
+ }
166
+ );
167
+ });
168
+
169
+ app.use(globalRouter.routes());
170
+ app.use(mount(`/${resourceName}`, resourceRouter.routes()));
171
+ }));
172
+ };
@@ -0,0 +1,28 @@
1
+ import _ from 'lodash';
2
+
3
+ const formatError = (customError) => {
4
+ const errors = {};
5
+
6
+ Object.keys(customError).forEach((key) => {
7
+ errors[key] = _.isArray(customError[key])
8
+ ? customError[key]
9
+ : [customError[key]];
10
+ });
11
+
12
+ return errors;
13
+ };
14
+
15
+ const attachCustomErrors = async (ctx, next) => {
16
+ ctx.throwError = (message) => ctx.throw(500, { message });
17
+ ctx.assertError = (condition, message) =>
18
+ ctx.assert(condition, 500, { message });
19
+
20
+ ctx.throwClientError = (errors) =>
21
+ ctx.throw(400, { errors: formatError(errors) });
22
+ ctx.assertClientError = (condition, errors) =>
23
+ ctx.assert(condition, 400, { errors: formatError(errors) });
24
+
25
+ await next();
26
+ };
27
+
28
+ export default attachCustomErrors;
@@ -0,0 +1,27 @@
1
+ import logger from 'logger';
2
+
3
+ const routeErrorHandler = async (ctx, next) => {
4
+ try {
5
+ await next();
6
+ } catch (error) {
7
+ console.log("Route Error", error, error.stack);
8
+
9
+ const clientError = error.errors;
10
+ const serverError = { global: error.message };
11
+
12
+ const errors = clientError || serverError;
13
+
14
+ logger.error(errors);
15
+
16
+ if (serverError && (error.status === 500 || !error.status) && process.env.APP_ENV === "production") {
17
+ serverError.global = "Something went wrong";
18
+ }
19
+
20
+ ctx.state.error = error;
21
+
22
+ ctx.status = error.status || 500;
23
+ ctx.body = { errors };
24
+ }
25
+ };
26
+
27
+ export default routeErrorHandler;
@@ -0,0 +1,7 @@
1
+ import moment from 'moment';
2
+
3
+ export const cron = "* * * * *";
4
+
5
+ export const handler = () => {
6
+ const yesterday = moment().add(-1, "day").toDate();
7
+ };
@@ -0,0 +1,32 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import moment from 'moment';
4
+ import schedule from 'node-schedule';
5
+ import requireDir from 'require-dir';
6
+
7
+ export default () => {
8
+ const paths = [path.resolve(__dirname, './scheduler/handlers')];
9
+ if (process.env.HIVE_SRC) {
10
+ paths.push(path.resolve(process.env.HIVE_SRC, './scheduler/handlers'))
11
+ }
12
+
13
+ paths.forEach((pathName) => {
14
+ if (fs.existsSync(pathName)) {
15
+ requireDir(pathName, {
16
+ mapValue: (handler, handlerName) => {
17
+ console.log(
18
+ `[scheduler] Registering handler ${handlerName} with cron ${handler.cron}`
19
+ );
20
+
21
+ schedule.scheduleJob(handler.cron, () => {
22
+ console.log(
23
+ `[scheduler] ${moment().format()} executing ${handlerName} with cron ${handler.cron
24
+ }`
25
+ );
26
+ handler.handler();
27
+ });
28
+ },
29
+ });
30
+ }
31
+ });
32
+ }
@@ -0,0 +1,38 @@
1
+ import crypto from 'crypto';
2
+ import bcrypt from 'bcryptjs';
3
+ import util from 'util';
4
+
5
+ const randomBytes = util.promisify(crypto.randomBytes, crypto);
6
+ const bcryptHash = util.promisify(bcrypt.hash, bcrypt);
7
+ const compare = util.promisify(bcrypt.compare, bcrypt);
8
+
9
+ /**
10
+ * @desc Generates random string, useful for creating secure tokens
11
+ *
12
+ * @return {string} - random string
13
+ */
14
+ export const generateSecureToken = async (tokenLength = 48) => {
15
+ const buf = await randomBytes(tokenLength);
16
+ return buf.toString("hex");
17
+ };
18
+
19
+ /**
20
+ * @desc Generate hash from any string. Could be used to generate a hash from password
21
+ *
22
+ * @param text {string} - a text to produce hash from
23
+ * @return {Promise} - a hash from input text
24
+ */
25
+ export const getHash = (text) => {
26
+ return bcryptHash(text, 10);
27
+ };
28
+
29
+ /**
30
+ * @desc Compares if text and hash are equal
31
+ *
32
+ * @param text {string} - a text to compare with hash
33
+ * @param hash {string} - a hash to compare with text
34
+ * @return {Promise} - are hash and text equal
35
+ */
36
+ export const compareTextWithHash = (text, hash) => {
37
+ return compare(text, hash);
38
+ };
@@ -0,0 +1,15 @@
1
+ import config from 'app-config';
2
+ import nodemailer from 'nodemailer';
3
+
4
+ config.assert('smtp');
5
+
6
+ export default {
7
+ sendEmail: async ({ to, subject, html }) => {
8
+ const transporter = nodemailer.createTransport(config.smtp)
9
+
10
+ return await transporter.sendMail({
11
+ from: config.smtp.fromEmail,
12
+ to, subject, html
13
+ })
14
+ }
15
+ };
File without changes
@@ -0,0 +1,21 @@
1
+ import psl from 'psl';
2
+ import url from 'url';
3
+ import { env } from 'app-config';
4
+ import { webUri } from 'app-config';
5
+
6
+ let cookiesDomain;
7
+
8
+ if (webUri) {
9
+ const parsedUrl = url.parse(webUri);
10
+ const parsed = psl.parse(parsedUrl.hostname);
11
+ cookiesDomain = parsed.domain;
12
+ }
13
+
14
+ export default (ctx, { name, value }, options = {}) => {
15
+ ctx.cookies.set(name, value, {
16
+ domain: '',
17
+ expires: new Date(Date.now() + 10 * 365 * 24 * 60 * 60 * 1000),
18
+ httpOnly: false,
19
+ ...options,
20
+ });
21
+ };
@@ -0,0 +1,99 @@
1
+ import db from 'db';
2
+ import { Server } from 'socket.io';
3
+ import { createClient } from 'redis';
4
+ import { createAdapter } from '@socket.io/redis-adapter';
5
+ import config from 'app-config';
6
+ import logger from 'logger';
7
+
8
+ export default (server) => {
9
+ const io = new Server(server);
10
+
11
+ const pubClient = createClient({ url: config.redis.url });
12
+ const subClient = pubClient.duplicate();
13
+
14
+ io.adapter(createAdapter(pubClient, subClient));
15
+
16
+ const getCookie = (cookieString, name) => {
17
+ const value = `; ${cookieString}`;
18
+ const parts = value.split(`; ${name}=`);
19
+
20
+ if (parts.length === 2) {
21
+ return parts.pop().split(";").shift();
22
+ }
23
+
24
+ return null;
25
+ };
26
+
27
+ // #TODO get user using accessToken
28
+ const getUserData = async (socket) => {
29
+ const accessToken = getCookie(
30
+ socket.handshake.headers.cookie,
31
+ "access_token"
32
+ ) || '';
33
+
34
+ console.log('socket: cookie access token', accessToken[0], accessToken[1], accessToken[2]);
35
+
36
+ let tokenDoc = null;
37
+
38
+ if (!accessToken) {
39
+ logger.info(
40
+ "Note: socket io anonymous auth. Add user authentication in socketIoService"
41
+ );
42
+ } else {
43
+ tokenDoc = await db.services.tokens.findOne({ token: accessToken });
44
+ }
45
+
46
+ return {
47
+ _id: tokenDoc?.user?._id || "anonymous",
48
+ };
49
+ };
50
+
51
+ io.use(async (socket, next) => {
52
+ const userData = await getUserData(socket);
53
+
54
+ if (userData) {
55
+ // eslint-disable-next-line no-param-reassign
56
+ socket.handshake.data = {
57
+ userId: userData.userId,
58
+ };
59
+
60
+ return next();
61
+ }
62
+
63
+ return next(new Error("token is invalid"));
64
+ });
65
+
66
+ function checkAccessToRoom(roomId, data) {
67
+ let result = false;
68
+ const [roomType, id] = roomId.split("-");
69
+
70
+ switch (roomType) {
71
+ case "user":
72
+ result = id === data.userId;
73
+ break;
74
+ default:
75
+ result = true;
76
+ }
77
+
78
+ return result;
79
+ }
80
+
81
+ io.on("connection", (client) => {
82
+ client.on("subscribe", (roomId) => {
83
+ const { userId } = client.handshake.data;
84
+ // const hasAccessToRoom = checkAccessToRoom(roomId, { userId });
85
+
86
+ const hasAccessToRoom = true;
87
+
88
+ if (hasAccessToRoom) {
89
+ client.join(roomId);
90
+ }
91
+ });
92
+
93
+ client.on("unsubscribe", (roomId) => {
94
+ client.leave(roomId);
95
+ });
96
+ });
97
+
98
+ console.log(`Socket.io server is started on app instance`);
99
+ };
@@ -0,0 +1,31 @@
1
+ {
2
+ "compilerOptions": {
3
+
4
+ // Treat files as modules even if it doesn't use import/export
5
+ "moduleDetection": "force",
6
+
7
+ // Ignore module structure
8
+ "module": "Preserve",
9
+
10
+ // Allow JSON modules to be imported
11
+ "resolveJsonModule": true,
12
+
13
+ // Allow JS files to be imported from TS and vice versa
14
+ "allowJs": true,
15
+
16
+ // Use correct ESM import behavior
17
+ "esModuleInterop": true,
18
+
19
+ // Disallow features that require cross-file awareness
20
+ "isolatedModules": true,
21
+
22
+ "baseUrl": "src",
23
+ "paths": {
24
+ "*": ["*"]
25
+ },
26
+ },
27
+ "include": [
28
+ "src/**/*",
29
+ ".hive/**/*"
30
+ ]
31
+ }
package/AGENTS.md ADDED
@@ -0,0 +1,96 @@
1
+ # AGENTS.md
2
+
3
+ ## Agent Persona
4
+
5
+ You are a **Hive framework developer** — building tools for engineers who are pissed off about the complexity of modern technology. Hive lets them build, iterate, and grow products faster.
6
+
7
+ **Your mindset:**
8
+ - Prioritize product outcomes over technical purity
9
+ - Minimize boilerplate and cognitive overhead
10
+ - Challenge complexity — if it doesn't serve the user, remove it
11
+ - Less code = better outcome
12
+
13
+ ---
14
+
15
+ ## What is Hive
16
+
17
+ Hive is a Koa-based Node.js framework with MongoDB, Zod validation, and auto-sync for embedded documents. It provides:
18
+
19
+ - **Resource pattern** — convention-based feature modules with schemas, endpoints, handlers
20
+ - **Auto-sync** — embedded document references stay in sync automatically
21
+ - **CLI** — `hive run`, `hive prepare`, `hive deploy`, `hive install`
22
+
23
+ ---
24
+
25
+ ## Repository Structure
26
+
27
+ ```
28
+ /
29
+ ├── cli/ # Hive CLI (commander.js)
30
+ │ ├── hive.js # CLI entry point
31
+ │ └── helpers/ # CLI utilities
32
+ ├── starter/ # Framework core (copied to .hive/ on run)
33
+ │ ├── src/ # Framework source
34
+ │ │ ├── app.js # Server bootstrap
35
+ │ │ ├── db.js # Database layer
36
+ │ │ ├── routes/ # Route registration
37
+ │ │ ├── middlewares/ # Built-in middlewares
38
+ │ │ ├── helpers/ # Internal helpers
39
+ │ │ ├── resources/ # Built-in resources (users, tokens, health)
40
+ │ │ ├── autoMap/ # Auto-sync system
41
+ │ │ └── scheduler/ # Cron job system
42
+ │ └── .cursor/skills/ # Cursor skills for projects using Hive
43
+ └── package.json
44
+ ```
45
+
46
+ ---
47
+
48
+ ## How It Works
49
+
50
+ 1. User runs `npx hive run ./src` from their project
51
+ 2. CLI copies `starter/` to `.hive/` in user's project
52
+ 3. Framework loads user's code from `HIVE_SRC` env var
53
+ 4. Schemas, endpoints, handlers merge at runtime
54
+
55
+ **Key mechanism:** User code in `/src/` extends framework code in `/.hive/`. The framework reads from `process.env.HIVE_SRC` to find user schemas, endpoints, handlers, and config.
56
+
57
+ ---
58
+
59
+ ## Development
60
+
61
+ ```bash
62
+ # Test CLI locally (from repo root)
63
+ node cli/hive.js run ./path/to/test-project/src
64
+
65
+ # The starter/ folder IS the framework
66
+ # Changes here affect all projects using Hive
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Boundaries
72
+
73
+ | Location | What it is | Editable |
74
+ |----------|-----------|----------|
75
+ | `cli/` | CLI tools | ✅ Yes |
76
+ | `starter/` | Framework core | ✅ Yes |
77
+ | `starter/.cursor/skills/` | Cursor skills for end-users | ✅ Yes |
78
+ | User's `/src/` | User code (not in this repo) | N/A |
79
+ | User's `/.hive/` | Auto-generated, never edit | N/A |
80
+
81
+ ---
82
+
83
+ ## When Editing Skills
84
+
85
+ Skills in `starter/.cursor/skills/` are documentation for projects **using** Hive. Each skill:
86
+ - Has a `SKILL.md` with frontmatter (name, description, globs)
87
+ - Teaches Cursor how to write code for Hive projects
88
+ - Should be concise and pattern-focused
89
+
90
+ ---
91
+
92
+ ## Philosophy
93
+
94
+ > Technology should solve people's issues, not create new weird ones.
95
+
96
+ When in doubt: simpler is better. Challenge unnecessary complexity.