@paralect/hive 0.1.49 → 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 (145) hide show
  1. package/.hive/.babelrc +3 -0
  2. package/.hive/.cursor/commands/add-endpoint.md +262 -0
  3. package/.hive/.cursor/commands/add-handler.md +137 -0
  4. package/.hive/.cursor/commands/add-middleware.md +95 -0
  5. package/.hive/.cursor/commands/add-resource.md +71 -0
  6. package/.hive/.cursor/commands/add-scheduler.md +138 -0
  7. package/.hive/.cursor/commands/add-service.md +188 -0
  8. package/.hive/.cursor/skills/hive-auth/SKILL.md +134 -0
  9. package/.hive/.cursor/skills/hive-database/SKILL.md +103 -0
  10. package/.hive/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  11. package/.hive/.cursor/skills/hive-handler/SKILL.md +88 -0
  12. package/.hive/.cursor/skills/hive-mapping/SKILL.md +85 -0
  13. package/.hive/.cursor/skills/hive-middleware/SKILL.md +104 -0
  14. package/.hive/.cursor/skills/hive-overview/SKILL.md +50 -0
  15. package/.hive/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  16. package/.hive/.cursor/skills/hive-schema/SKILL.md +73 -0
  17. package/.hive/.cursor/skills/hive-service/SKILL.md +90 -0
  18. package/.hive/.dockerignore +1 -0
  19. package/.hive/Dockerfile +22 -0
  20. package/.hive/Dockerfile.dev +33 -0
  21. package/.hive/Dockerfile.prod +29 -0
  22. package/.hive/README.md +11 -0
  23. package/.hive/bin/deploy.sh +5 -0
  24. package/.hive/bin/start.sh +2 -0
  25. package/.hive/bootstrap-hive.js +118 -0
  26. package/.hive/deploy/api/Chart.yaml +6 -0
  27. package/.hive/deploy/api/staging.yaml +3 -0
  28. package/.hive/deploy/api/templates/deployment.yaml +44 -0
  29. package/.hive/deploy/api/templates/ingress.yaml +26 -0
  30. package/.hive/deploy/api/templates/service.yaml +14 -0
  31. package/.hive/deploy/script/Dockerfile +39 -0
  32. package/.hive/deploy/script/package-lock.json +1499 -0
  33. package/.hive/deploy/script/package.json +12 -0
  34. package/.hive/deploy/script/src/config.js +48 -0
  35. package/.hive/deploy/script/src/index.js +108 -0
  36. package/.hive/deploy/script/src/util.js +19 -0
  37. package/.hive/initial-data.json +176 -0
  38. package/.hive/package-lock.json +10242 -0
  39. package/.hive/package.json +98 -0
  40. package/.hive/ship_logo.png +0 -0
  41. package/.hive/src/app-config/app.js +3 -0
  42. package/.hive/src/app-config/assertEnv.js +15 -0
  43. package/.hive/src/app-config/index.js +62 -0
  44. package/.hive/src/app.js +69 -0
  45. package/.hive/src/assets/emails/components/header.mjml +13 -0
  46. package/.hive/src/assets/emails/dist/.gitkeep +0 -0
  47. package/.hive/src/assets/emails/signup-welcome.mjml +34 -0
  48. package/.hive/src/assets/emails/styles/index.mjml +77 -0
  49. package/.hive/src/autoMap/addHandlers.js +142 -0
  50. package/.hive/src/autoMap/getDependentFields.js +37 -0
  51. package/.hive/src/autoMap/mapSchema.js +99 -0
  52. package/.hive/src/autoMap/schemaMappings.js +13 -0
  53. package/.hive/src/autoMap/schemaMappings.json +3 -0
  54. package/.hive/src/bullMqBus.js +21 -0
  55. package/.hive/src/bullMqWrapper.js +23 -0
  56. package/.hive/src/db.js +52 -0
  57. package/.hive/src/emails/MyEmailComponent.jsx +14 -0
  58. package/.hive/src/emails/compiled/MyEmailComponent.js +18 -0
  59. package/.hive/src/emails/compiled/compiled/MyEmailComponent.js +18 -0
  60. package/.hive/src/helpers/db/ifUpdated.js +22 -0
  61. package/.hive/src/helpers/getMiddlewares.js +38 -0
  62. package/.hive/src/helpers/getResourceEndpoints.js +28 -0
  63. package/.hive/src/helpers/getResources.js +32 -0
  64. package/.hive/src/helpers/getSchemas.js +50 -0
  65. package/.hive/src/helpers/importHandlers.js +29 -0
  66. package/.hive/src/helpers/isZodArray.js +13 -0
  67. package/.hive/src/helpers/prettierFormat.js +8 -0
  68. package/.hive/src/helpers/schema/db.schema.js +9 -0
  69. package/.hive/src/helpers/schema/pagination.schema.js +14 -0
  70. package/.hive/src/ioEmitter.js +9 -0
  71. package/.hive/src/jsconfig.json +5 -0
  72. package/.hive/src/lib/node-mongo/.github/workflows/npm-publish.yml +32 -0
  73. package/.hive/src/lib/node-mongo/API.md +654 -0
  74. package/.hive/src/lib/node-mongo/CHANGELOG.md +98 -0
  75. package/.hive/src/lib/node-mongo/README.md +97 -0
  76. package/.hive/src/lib/node-mongo/package-lock.json +3682 -0
  77. package/.hive/src/lib/node-mongo/package.json +74 -0
  78. package/.hive/src/lib/node-mongo/src/index.js +64 -0
  79. package/.hive/src/lib/node-mongo/src/mongo-query-service.js +78 -0
  80. package/.hive/src/lib/node-mongo/src/mongo-service-error.js +15 -0
  81. package/.hive/src/lib/node-mongo/src/mongo-service.js +303 -0
  82. package/.hive/src/logger.js +43 -0
  83. package/.hive/src/middlewares/allowNoAuth.js +9 -0
  84. package/.hive/src/middlewares/attachUser.js +41 -0
  85. package/.hive/src/middlewares/global/extractUserTokens.js +15 -0
  86. package/.hive/src/middlewares/global/tryToAttachUser.js +33 -0
  87. package/.hive/src/middlewares/isAuthorized.js +18 -0
  88. package/.hive/src/middlewares/shouldExist.js +37 -0
  89. package/.hive/src/middlewares/shouldNotExist.js +19 -0
  90. package/.hive/src/middlewares/uploadFile.js +5 -0
  91. package/.hive/src/middlewares/validate.js +32 -0
  92. package/.hive/src/migrations/migration.js +8 -0
  93. package/.hive/src/migrations/migration.service.js +73 -0
  94. package/.hive/src/migrations/migrations/1.js +22 -0
  95. package/.hive/src/migrations/migrations-log/migration-log.schema.js +13 -0
  96. package/.hive/src/migrations/migrations-log/migration-log.service.js +50 -0
  97. package/.hive/src/migrations/migrations.schema.js +6 -0
  98. package/.hive/src/migrations/migrator.js +75 -0
  99. package/.hive/src/migrator.js +4 -0
  100. package/.hive/src/resources/_dev/endpoints/triggerSchedulerHandler.js +32 -0
  101. package/.hive/src/resources/health/endpoints/get.js +19 -0
  102. package/.hive/src/resources/schemaMappings/schemaMappings.schema.js +6 -0
  103. package/.hive/src/resources/tokens/methods/generateSecureToken.js +9 -0
  104. package/.hive/src/resources/tokens/methods/setToken.js +8 -0
  105. package/.hive/src/resources/tokens/methods/storeToken.js +35 -0
  106. package/.hive/src/resources/tokens/tokens.schema.js +11 -0
  107. package/.hive/src/resources/users/endpoints/getCurrentUser.js +14 -0
  108. package/.hive/src/resources/users/endpoints/getUserProfile.js +19 -0
  109. package/.hive/src/resources/users/handlers/test.js +1 -0
  110. package/.hive/src/resources/users/methods/ensureUserCreated.js +68 -0
  111. package/.hive/src/resources/users/users.schema.js +16 -0
  112. package/.hive/src/routes/index.js +172 -0
  113. package/.hive/src/routes/middlewares/attachCustomErrors.js +28 -0
  114. package/.hive/src/routes/middlewares/routeErrorHandler.js +27 -0
  115. package/.hive/src/scheduler/handlers/sendDailyReport.example.js +7 -0
  116. package/.hive/src/scheduler.js +32 -0
  117. package/.hive/src/security.util.js +38 -0
  118. package/.hive/src/services/emailService.js +15 -0
  119. package/.hive/src/services/globalTest.js +0 -0
  120. package/.hive/src/services/setCookie.js +21 -0
  121. package/.hive/src/socketIo.js +99 -0
  122. package/.hive/tsconfig.json +31 -0
  123. package/cli/helpers/docker.js +59 -0
  124. package/cli/helpers/envCheck.js +123 -0
  125. package/cli/helpers/findPort.js +32 -0
  126. package/cli/hive.js +84 -12
  127. package/package.json +1 -1
  128. package/test-app/.cursor/commands/add-endpoint.md +262 -0
  129. package/test-app/.cursor/commands/add-handler.md +137 -0
  130. package/test-app/.cursor/commands/add-middleware.md +95 -0
  131. package/test-app/.cursor/commands/add-resource.md +71 -0
  132. package/test-app/.cursor/commands/add-scheduler.md +138 -0
  133. package/test-app/.cursor/commands/add-service.md +188 -0
  134. package/test-app/.cursor/skills/hive-auth/SKILL.md +134 -0
  135. package/test-app/.cursor/skills/hive-database/SKILL.md +103 -0
  136. package/test-app/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  137. package/test-app/.cursor/skills/hive-handler/SKILL.md +88 -0
  138. package/test-app/.cursor/skills/hive-mapping/SKILL.md +85 -0
  139. package/test-app/.cursor/skills/hive-middleware/SKILL.md +104 -0
  140. package/test-app/.cursor/skills/hive-overview/SKILL.md +50 -0
  141. package/test-app/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  142. package/test-app/.cursor/skills/hive-schema/SKILL.md +73 -0
  143. package/test-app/.cursor/skills/hive-service/SKILL.md +90 -0
  144. package/test-app/package-lock.json +8684 -0
  145. package/test-app/package.json +21 -0
@@ -0,0 +1,37 @@
1
+ import db from 'db';
2
+
3
+ function singularize(word) {
4
+ const endings = {
5
+ ves: 'fe',
6
+ ies: 'y',
7
+ i: 'us',
8
+ zes: 'ze',
9
+ ses: 's',
10
+ es: 'e',
11
+ s: '',
12
+ };
13
+ return word.replace(
14
+ new RegExp(`(${Object.keys(endings).join('|')})$`),
15
+ (r) => endings[r]
16
+ );
17
+ }
18
+
19
+ export default (
20
+ resourceName,
21
+ {
22
+ criteria = (ctx) => ({ _id: ctx.params[`${singularize(resourceName)}Id`] }),
23
+ ctxName = resourceName,
24
+ } = {}
25
+ ) => {
26
+ return async (ctx, next) => {
27
+ const doc = await db.services[resourceName].findOne(criteria(ctx));
28
+ ctx.state[ctxName] = doc;
29
+ ctx.state[singularize(resourceName)] = doc;
30
+
31
+ if (!doc) {
32
+ ctx.throw(404, { message: `${resourceName} not found` });
33
+ } else {
34
+ await next();
35
+ }
36
+ };
37
+ };
@@ -0,0 +1,19 @@
1
+ import _ from 'lodash';
2
+ import db from 'db';
3
+
4
+ export default (
5
+ resourceName,
6
+ { criteria = (ctx) => ({ name: ctx.validatedData.name }) } = {}
7
+ ) => {
8
+ return async (ctx, next) => {
9
+ const doc = await db.services[resourceName].findOne(criteria(ctx));
10
+
11
+ if (doc) {
12
+ ctx.throw(400, {
13
+ message: `${_.capitalize(resourceName)} already exists`,
14
+ });
15
+ } else {
16
+ await next();
17
+ }
18
+ };
19
+ };
@@ -0,0 +1,5 @@
1
+ import multer from '@koa/multer';
2
+
3
+ const storage = multer.memoryStorage();
4
+
5
+ export default multer({ storage });
@@ -0,0 +1,32 @@
1
+
2
+ const formatError = (zodError) => {
3
+ const errors = {};
4
+
5
+ zodError.issues.forEach((error) => {
6
+ const key = error.path.join('.');
7
+
8
+ if (!errors[key]) {
9
+ errors[key] = [];
10
+ }
11
+
12
+ (errors[key]).push(error.message);
13
+ });
14
+
15
+ return errors;
16
+ };
17
+
18
+ const validate = (schema) => async (ctx, next) => {
19
+ const result = await schema.passthrough().safeParseAsync({
20
+ ...(ctx.request.body),
21
+ ...ctx.query,
22
+ ...ctx.params,
23
+ });
24
+
25
+ if (!result.success) ctx.throw(400, { clientErrors: formatError(result.error) });
26
+
27
+ ctx.validatedData = result.data;
28
+
29
+ await next();
30
+ };
31
+
32
+ export default validate;
@@ -0,0 +1,8 @@
1
+ class Migration {
2
+ constructor(version, description) {
3
+ this.version = version;
4
+ this.description = description;
5
+ }
6
+ }
7
+
8
+ export default Migration;
@@ -0,0 +1,73 @@
1
+ import db from "db";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import _ from "lodash";
5
+ import validateSchema from "./migrations.schema";
6
+
7
+ const service = db.createService("__migrationVersion", {
8
+ validate: validateSchema,
9
+ });
10
+
11
+ const migrationsPath = path.join(__dirname, "migrations");
12
+
13
+ const _id = "migration_version";
14
+
15
+ const getMigrationNames = () =>
16
+ new Promise((resolve, reject) => {
17
+ fs.readdir(migrationsPath, (err, files) => {
18
+ if (err) {
19
+ reject(err);
20
+ return;
21
+ }
22
+ resolve(files);
23
+ });
24
+ });
25
+
26
+ service.getCurrentMigrationVersion = () =>
27
+ service.findOne({ _id }).then((doc) => {
28
+ if (!doc) {
29
+ return 0;
30
+ }
31
+ return doc.version;
32
+ });
33
+
34
+ service.getMigrations = () => {
35
+ let migrations = null;
36
+ return getMigrationNames()
37
+ .then((names) => {
38
+ migrations = names.map((name) => {
39
+ const migrationPath = path.join(migrationsPath, name);
40
+ // eslint-disable-next-line import/no-dynamic-require, global-require
41
+ // return require(migrationPath);
42
+ });
43
+ return migrations;
44
+ })
45
+ .catch((err) => {
46
+ throw err;
47
+ });
48
+ };
49
+
50
+ service.setNewMigrationVersion = (version) =>
51
+ service.atomic.findOneAndUpdate(
52
+ { _id },
53
+ {
54
+ $set: {
55
+ version,
56
+ },
57
+ $setOnInsert: {
58
+ _id,
59
+ },
60
+ },
61
+ { upsert: true }
62
+ );
63
+
64
+ service.promiseLimit = (documents = [], limit, operator) => {
65
+ const chunks = _.chunk(documents, limit);
66
+ return chunks.reduce((init, chunk) => {
67
+ return init.then(() => {
68
+ return Promise.all(chunk.map((c) => operator(c)));
69
+ });
70
+ }, Promise.resolve());
71
+ };
72
+
73
+ export default service;
@@ -0,0 +1,22 @@
1
+ import Migration from 'migrations/migration';
2
+ // const migrationService = require('migrations/migration.service');
3
+ //
4
+ // const userService = require('resources/user/user.service');
5
+
6
+ const migration = new Migration(1, "Example");
7
+
8
+ migration.migrate = async () => {
9
+ // const userIds = await userService.distinct('_id', {
10
+ // isEmailVerified: true,
11
+ // });
12
+ //
13
+ // await migrationService.promiseLimit(userIds, 50, (userId) => userService.updateOne(
14
+ // { _id: userId },
15
+ // (old) => ({
16
+ // ...old,
17
+ // isEmailVerified: false,
18
+ // }),
19
+ // ));
20
+ };
21
+
22
+ export default migration;
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ import dbSchema from 'helpers/schema/db.schema';
3
+
4
+ export default dbSchema.extend({
5
+ startTime: z.date(),
6
+ finishTime: z.date().optional(),
7
+ status: z.string(),
8
+ error: z.string().optional(),
9
+ errorStack: z.string().optional(),
10
+ duration: z.string().optional(),
11
+ migrationVersion: z.number(),
12
+ });
13
+
@@ -0,0 +1,50 @@
1
+ import db from 'db';
2
+ import validateSchema from './migration-log.schema.js';
3
+
4
+ const service = db.createService("__migrationLog", {
5
+ validate: validateSchema,
6
+ });
7
+
8
+ service.startMigrationLog = (_id, startTime, migrationVersion) => {
9
+ return service.atomic.findOneAndUpdate(
10
+ { _id },
11
+ {
12
+ $set: {
13
+ migrationVersion,
14
+ startTime,
15
+ status: "running",
16
+ },
17
+ $setOnInsert: {
18
+ _id,
19
+ },
20
+ },
21
+ { upsert: true }
22
+ );
23
+ };
24
+
25
+ service.failMigrationLog = (_id, finishTime, err) =>
26
+ service.atomic.update(
27
+ { _id },
28
+ {
29
+ $set: {
30
+ finishTime,
31
+ status: "failed",
32
+ error: err.message,
33
+ errorStack: err.stack,
34
+ },
35
+ }
36
+ );
37
+
38
+ service.finishMigrationLog = (_id, finishTime, duration) =>
39
+ service.atomic.update(
40
+ { _id },
41
+ {
42
+ $set: {
43
+ finishTime,
44
+ status: "completed",
45
+ duration,
46
+ },
47
+ }
48
+ );
49
+
50
+ export default service;
@@ -0,0 +1,6 @@
1
+ import { z } from 'zod';
2
+ import dbSchema from 'helpers/schema/db.schema';
3
+
4
+ export default dbSchema.extend({
5
+ version: z.number(),
6
+ });
@@ -0,0 +1,75 @@
1
+ import 'moment-duration-format';
2
+ import moment from 'moment';
3
+ import logger from 'logger';
4
+ import migrationLogService from './migrations-log/migration-log.service';
5
+ import migrationService from './migration.service';
6
+
7
+ const migrator = {};
8
+
9
+ const run = async (migrations, curVersion) => {
10
+ const newMigrations = migrations
11
+ .filter((migration) => migration.version > curVersion)
12
+ .sort((a, b) => a.version - b.version);
13
+
14
+ if (!newMigrations.length) {
15
+ logger.info(`No new migrations found, stopping the process.
16
+ Current database version is ${curVersion}`);
17
+ return;
18
+ }
19
+
20
+ let migrationLogId;
21
+ let migration;
22
+ let lastMigrationVersion;
23
+
24
+ try {
25
+ for (migration of newMigrations) {
26
+ //eslint-disable-line
27
+ migrationLogId = migrationService.generateId();
28
+ const startTime = new Date();
29
+ await migrationLogService.startMigrationLog(
30
+ migrationLogId,
31
+ startTime,
32
+ migration.version
33
+ ); //eslint-disable-line
34
+ logger.info(
35
+ `Migration #${migration.version} is running: ${migration.description}`
36
+ );
37
+ await migration.migrate(); //eslint-disable-line
38
+
39
+ lastMigrationVersion = migration.version;
40
+ await migrationService.setNewMigrationVersion(migration.version); //eslint-disable-line
41
+ const finishTime = new Date();
42
+ const duration = moment
43
+ .duration(finishTime - startTime)
44
+ .format("h [hrs], m [min], s [sec], S [ms]");
45
+
46
+ await migrationLogService.finishMigrationLog(
47
+ migrationLogId,
48
+ finishTime,
49
+ duration
50
+ ); //eslint-disable-line
51
+ logger.info(
52
+ `Database has been updated to the version #${migration.version}`
53
+ );
54
+ logger.info(`Time of migration #${migration.version}: ${duration}`);
55
+ }
56
+ logger.info(`All migrations has been finished, stopping the process.
57
+ Current database version is: ${lastMigrationVersion}`);
58
+ } catch (err) {
59
+ logger.error(`Failed to update migration to version ${migration.version}`);
60
+ logger.error(err);
61
+ await migrationLogService.failMigrationLog(migrationLogId, new Date(), err);
62
+ throw err;
63
+ }
64
+ };
65
+
66
+ migrator.exec = async () => {
67
+ const [migrations, currentVersion] = await Promise.all([
68
+ migrationService.getMigrations(),
69
+ migrationService.getCurrentMigrationVersion(),
70
+ ]);
71
+ await run(migrations, currentVersion);
72
+ process.exit(0);
73
+ };
74
+
75
+ export default migrator;
@@ -0,0 +1,4 @@
1
+ import appModulePath from "app-module-path";
2
+ import migrator from "migrations/migrator";
3
+ appModulePath.addPath(__dirname);
4
+ migrator.exec();
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+
3
+ export const endpoint = {
4
+ method: "put",
5
+ url: "/trigger-scheduler-handler",
6
+ };
7
+
8
+ export const requestSchema = z.object({
9
+ name: z.string(),
10
+ });
11
+
12
+ export const handler = async (ctx) => {
13
+ const { name } = ctx.validatedData;
14
+
15
+ const schedulerHandler = await (import(`${process.env.HIVE_SRC}/scheduler/handlers/${name}`));
16
+
17
+ try {
18
+ const data = await schedulerHandler.handler();
19
+
20
+ ctx.body = {
21
+ ok: true,
22
+ data,
23
+ };
24
+ } catch (err) {
25
+ ctx.body = {
26
+ ok: false,
27
+ err: err.message,
28
+ };
29
+ }
30
+ };
31
+
32
+ export const middlewares = ['allowNoAuth'];
@@ -0,0 +1,19 @@
1
+ import { render } from '@react-email/render';
2
+ import { MyEmailComponent } from 'emails/compiled/MyEmailComponent';
3
+ import React from 'react';
4
+
5
+ export const handler = (ctx) => {
6
+ const emailHtml = render(React.createElement(MyEmailComponent, { name: 'test' }));
7
+
8
+ ctx.body = emailHtml;
9
+ ctx.status = 200;
10
+ };
11
+
12
+ export const endpoint = {
13
+ method: "get",
14
+ url: "/",
15
+ };
16
+
17
+ export default {
18
+ handler, endpoint
19
+ }
@@ -0,0 +1,6 @@
1
+ import { z } from 'zod';
2
+ import dbSchema from 'helpers/schema/db.schema';
3
+
4
+ export default dbSchema.extend({
5
+ mappings: z.object({}),
6
+ });
@@ -0,0 +1,9 @@
1
+ import crypto from 'crypto';
2
+ import util from 'util';
3
+
4
+ const randomBytes = util.promisify(crypto.randomBytes, crypto);
5
+
6
+ export default async (tokenLength = 32) => {
7
+ const buf = await randomBytes(tokenLength);
8
+ return buf.toString('hex');
9
+ };
@@ -0,0 +1,8 @@
1
+ import db from 'db';
2
+ const tokenService = db.services.tokens;
3
+
4
+ export default async () => {
5
+ const { results } = await tokenService.aggregate([]);
6
+
7
+ return results;
8
+ };
@@ -0,0 +1,35 @@
1
+ import db from 'db';
2
+ import crypto from 'crypto';
3
+ import util from 'util';
4
+
5
+ const randomBytes = util.promisify(crypto.randomBytes, crypto);
6
+
7
+ import setCookie from 'services/setCookie';
8
+
9
+ const tokenService = db.services.tokens;
10
+
11
+ const generateSecureToken = async (tokenLength = 32) => {
12
+ const buf = await randomBytes(tokenLength);
13
+ return buf.toString('hex');
14
+ };
15
+
16
+ export default async (ctx, { userId, metadata = null }) => {
17
+ const token = await generateSecureToken();
18
+ const otp = await generateSecureToken();
19
+
20
+ await tokenService.create({
21
+ token,
22
+ user: {
23
+ _id: userId,
24
+ },
25
+ otp,
26
+ ...(metadata ? { metadata } : {})
27
+ });
28
+
29
+ setCookie(ctx, { name: 'access_token', value: token });
30
+
31
+ return {
32
+ token,
33
+ otp,
34
+ };
35
+ };
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ import dbSchema from 'helpers/schema/db.schema';
3
+
4
+ export default dbSchema.extend({
5
+ user: z.object({
6
+ _id: z.string(),
7
+ }),
8
+ token: z.string(),
9
+ otp: z.string().nullable().optional(),
10
+ metadata: z.object({}).optional()
11
+ });
@@ -0,0 +1,14 @@
1
+ import { z } from 'zod';
2
+ import isAuthorized from 'middlewares/isAuthorized';
3
+
4
+ export const handler = async (ctx) => {
5
+ ctx.body = ctx.state.user;
6
+ };
7
+
8
+ export const middlewares = [isAuthorized];
9
+ export const requestSchema = z.object({});
10
+
11
+ export const endpoint = {
12
+ method: "GET",
13
+ url: "/me",
14
+ };
@@ -0,0 +1,19 @@
1
+ import { z } from 'zod';
2
+ import db from 'db';
3
+
4
+ const userService = db.services.users;
5
+
6
+ export const handler = async (ctx) => {
7
+ const { userId } = ctx.params;
8
+ const user = await userService.findOne({ _id: userId });
9
+ ctx.body = user;
10
+ };
11
+
12
+ export const requestSchema = z.object({
13
+ userId: z.string(),
14
+ });
15
+
16
+ export const endpoint = {
17
+ method: "GET",
18
+ url: "/profile/:userId",
19
+ };
@@ -0,0 +1 @@
1
+ console.log('hello from handler');
@@ -0,0 +1,68 @@
1
+ import db from 'db';
2
+ import _ from 'lodash';
3
+ import slug from 'slug';
4
+
5
+ const userService = db.services.users;
6
+
7
+ const formatUsername = ({ username, fullName, email }) => {
8
+ return (
9
+ username ||
10
+ fullName ? slug(`${fullName.split(' ')[0]} ${fullName.split(' ')[1] || ''}`, '.') : email?.split('@')[0]
11
+ );
12
+ };
13
+
14
+ const createUserAccount = async (userData) => {
15
+ let username = formatUsername({ fullName: userData.fullName, email: userData.email });
16
+
17
+ if (await userService.exists({ username })) {
18
+ username += _.random(1000, 9999);
19
+ }
20
+
21
+ const user = await userService.create({
22
+ fullName: userData.fullName,
23
+ username,
24
+ email: userData.email,
25
+ isEmailVerified: true,
26
+ avatarUrl: userData.avatarUrl,
27
+ oauth: userData.oauth,
28
+ });
29
+
30
+ return user;
31
+ };
32
+
33
+ const ensureUserCreated = async (userData) => {
34
+ const user = await userService.findOne({ email: userData.email });
35
+
36
+ if (user) {
37
+ if (userData.oauth) {
38
+ const changedUser = await userService.updateOne(
39
+ { _id: user._id },
40
+ (old) => {
41
+ const newUser = old;
42
+ newUser.oauth = old.oauth || {};
43
+ newUser.oauth = {
44
+ ...newUser.oauth,
45
+ ...userData.oauth
46
+ }
47
+ newUser.isEmailVerified = true;
48
+
49
+ return newUser;
50
+ }
51
+ );
52
+
53
+ return { user: changedUser, isNew: false };
54
+ } else {
55
+ return { user, isNew: false };
56
+ }
57
+ }
58
+
59
+ return {
60
+ user: await createUserAccount(userData),
61
+ isNew: true,
62
+ };
63
+ };
64
+
65
+ export default async (userData) => {
66
+ const { user, isNew } = await ensureUserCreated(userData);
67
+ return user;
68
+ };
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod';
2
+ import dbSchema from 'helpers/schema/db.schema';
3
+
4
+ const users = dbSchema.extend({
5
+ email: z.string().email(),
6
+ fullName: z.string(),
7
+ avatarUrl: z.string().url().optional(),
8
+
9
+ password: z.string(),
10
+
11
+ oauth: z.object({
12
+ google: z.object({}),
13
+ }).optional(),
14
+ });
15
+
16
+ export default users;