@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.
- package/.hive/.babelrc +3 -0
- package/.hive/.cursor/commands/add-endpoint.md +262 -0
- package/.hive/.cursor/commands/add-handler.md +137 -0
- package/.hive/.cursor/commands/add-middleware.md +95 -0
- package/.hive/.cursor/commands/add-resource.md +71 -0
- package/.hive/.cursor/commands/add-scheduler.md +138 -0
- package/.hive/.cursor/commands/add-service.md +188 -0
- package/.hive/.cursor/skills/hive-auth/SKILL.md +134 -0
- package/.hive/.cursor/skills/hive-database/SKILL.md +103 -0
- package/.hive/.cursor/skills/hive-endpoint/SKILL.md +103 -0
- package/.hive/.cursor/skills/hive-handler/SKILL.md +88 -0
- package/.hive/.cursor/skills/hive-mapping/SKILL.md +85 -0
- package/.hive/.cursor/skills/hive-middleware/SKILL.md +104 -0
- package/.hive/.cursor/skills/hive-overview/SKILL.md +50 -0
- package/.hive/.cursor/skills/hive-scheduler/SKILL.md +94 -0
- package/.hive/.cursor/skills/hive-schema/SKILL.md +73 -0
- package/.hive/.cursor/skills/hive-service/SKILL.md +90 -0
- package/.hive/.dockerignore +1 -0
- package/.hive/Dockerfile +22 -0
- package/.hive/Dockerfile.dev +33 -0
- package/.hive/Dockerfile.prod +29 -0
- package/.hive/README.md +11 -0
- package/.hive/bin/deploy.sh +5 -0
- package/.hive/bin/start.sh +2 -0
- package/.hive/bootstrap-hive.js +118 -0
- package/.hive/deploy/api/Chart.yaml +6 -0
- package/.hive/deploy/api/staging.yaml +3 -0
- package/.hive/deploy/api/templates/deployment.yaml +44 -0
- package/.hive/deploy/api/templates/ingress.yaml +26 -0
- package/.hive/deploy/api/templates/service.yaml +14 -0
- package/.hive/deploy/script/Dockerfile +39 -0
- package/.hive/deploy/script/package-lock.json +1499 -0
- package/.hive/deploy/script/package.json +12 -0
- package/.hive/deploy/script/src/config.js +48 -0
- package/.hive/deploy/script/src/index.js +108 -0
- package/.hive/deploy/script/src/util.js +19 -0
- package/.hive/initial-data.json +176 -0
- package/.hive/package-lock.json +10242 -0
- package/.hive/package.json +98 -0
- package/.hive/ship_logo.png +0 -0
- package/.hive/src/app-config/app.js +3 -0
- package/.hive/src/app-config/assertEnv.js +15 -0
- package/.hive/src/app-config/index.js +62 -0
- package/.hive/src/app.js +69 -0
- package/.hive/src/assets/emails/components/header.mjml +13 -0
- package/.hive/src/assets/emails/dist/.gitkeep +0 -0
- package/.hive/src/assets/emails/signup-welcome.mjml +34 -0
- package/.hive/src/assets/emails/styles/index.mjml +77 -0
- package/.hive/src/autoMap/addHandlers.js +142 -0
- package/.hive/src/autoMap/getDependentFields.js +37 -0
- package/.hive/src/autoMap/mapSchema.js +99 -0
- package/.hive/src/autoMap/schemaMappings.js +13 -0
- package/.hive/src/autoMap/schemaMappings.json +3 -0
- package/.hive/src/bullMqBus.js +21 -0
- package/.hive/src/bullMqWrapper.js +23 -0
- package/.hive/src/db.js +52 -0
- package/.hive/src/emails/MyEmailComponent.jsx +14 -0
- package/.hive/src/emails/compiled/MyEmailComponent.js +18 -0
- package/.hive/src/emails/compiled/compiled/MyEmailComponent.js +18 -0
- package/.hive/src/helpers/db/ifUpdated.js +22 -0
- package/.hive/src/helpers/getMiddlewares.js +38 -0
- package/.hive/src/helpers/getResourceEndpoints.js +28 -0
- package/.hive/src/helpers/getResources.js +32 -0
- package/.hive/src/helpers/getSchemas.js +50 -0
- package/.hive/src/helpers/importHandlers.js +29 -0
- package/.hive/src/helpers/isZodArray.js +13 -0
- package/.hive/src/helpers/prettierFormat.js +8 -0
- package/.hive/src/helpers/schema/db.schema.js +9 -0
- package/.hive/src/helpers/schema/pagination.schema.js +14 -0
- package/.hive/src/ioEmitter.js +9 -0
- package/.hive/src/jsconfig.json +5 -0
- package/.hive/src/lib/node-mongo/.github/workflows/npm-publish.yml +32 -0
- package/.hive/src/lib/node-mongo/API.md +654 -0
- package/.hive/src/lib/node-mongo/CHANGELOG.md +98 -0
- package/.hive/src/lib/node-mongo/README.md +97 -0
- package/.hive/src/lib/node-mongo/package-lock.json +3682 -0
- package/.hive/src/lib/node-mongo/package.json +74 -0
- package/.hive/src/lib/node-mongo/src/index.js +64 -0
- package/.hive/src/lib/node-mongo/src/mongo-query-service.js +78 -0
- package/.hive/src/lib/node-mongo/src/mongo-service-error.js +15 -0
- package/.hive/src/lib/node-mongo/src/mongo-service.js +303 -0
- package/.hive/src/logger.js +43 -0
- package/.hive/src/middlewares/allowNoAuth.js +9 -0
- package/.hive/src/middlewares/attachUser.js +41 -0
- package/.hive/src/middlewares/global/extractUserTokens.js +15 -0
- package/.hive/src/middlewares/global/tryToAttachUser.js +33 -0
- package/.hive/src/middlewares/isAuthorized.js +18 -0
- package/.hive/src/middlewares/shouldExist.js +37 -0
- package/.hive/src/middlewares/shouldNotExist.js +19 -0
- package/.hive/src/middlewares/uploadFile.js +5 -0
- package/.hive/src/middlewares/validate.js +32 -0
- package/.hive/src/migrations/migration.js +8 -0
- package/.hive/src/migrations/migration.service.js +73 -0
- package/.hive/src/migrations/migrations/1.js +22 -0
- package/.hive/src/migrations/migrations-log/migration-log.schema.js +13 -0
- package/.hive/src/migrations/migrations-log/migration-log.service.js +50 -0
- package/.hive/src/migrations/migrations.schema.js +6 -0
- package/.hive/src/migrations/migrator.js +75 -0
- package/.hive/src/migrator.js +4 -0
- package/.hive/src/resources/_dev/endpoints/triggerSchedulerHandler.js +32 -0
- package/.hive/src/resources/health/endpoints/get.js +19 -0
- package/.hive/src/resources/schemaMappings/schemaMappings.schema.js +6 -0
- package/.hive/src/resources/tokens/methods/generateSecureToken.js +9 -0
- package/.hive/src/resources/tokens/methods/setToken.js +8 -0
- package/.hive/src/resources/tokens/methods/storeToken.js +35 -0
- package/.hive/src/resources/tokens/tokens.schema.js +11 -0
- package/.hive/src/resources/users/endpoints/getCurrentUser.js +14 -0
- package/.hive/src/resources/users/endpoints/getUserProfile.js +19 -0
- package/.hive/src/resources/users/handlers/test.js +1 -0
- package/.hive/src/resources/users/methods/ensureUserCreated.js +68 -0
- package/.hive/src/resources/users/users.schema.js +16 -0
- package/.hive/src/routes/index.js +172 -0
- package/.hive/src/routes/middlewares/attachCustomErrors.js +28 -0
- package/.hive/src/routes/middlewares/routeErrorHandler.js +27 -0
- package/.hive/src/scheduler/handlers/sendDailyReport.example.js +7 -0
- package/.hive/src/scheduler.js +32 -0
- package/.hive/src/security.util.js +38 -0
- package/.hive/src/services/emailService.js +15 -0
- package/.hive/src/services/globalTest.js +0 -0
- package/.hive/src/services/setCookie.js +21 -0
- package/.hive/src/socketIo.js +99 -0
- package/.hive/tsconfig.json +31 -0
- package/cli/helpers/docker.js +59 -0
- package/cli/helpers/envCheck.js +123 -0
- package/cli/helpers/findPort.js +32 -0
- package/cli/hive.js +84 -12
- package/package.json +1 -1
- package/test-app/.cursor/commands/add-endpoint.md +262 -0
- package/test-app/.cursor/commands/add-handler.md +137 -0
- package/test-app/.cursor/commands/add-middleware.md +95 -0
- package/test-app/.cursor/commands/add-resource.md +71 -0
- package/test-app/.cursor/commands/add-scheduler.md +138 -0
- package/test-app/.cursor/commands/add-service.md +188 -0
- package/test-app/.cursor/skills/hive-auth/SKILL.md +134 -0
- package/test-app/.cursor/skills/hive-database/SKILL.md +103 -0
- package/test-app/.cursor/skills/hive-endpoint/SKILL.md +103 -0
- package/test-app/.cursor/skills/hive-handler/SKILL.md +88 -0
- package/test-app/.cursor/skills/hive-mapping/SKILL.md +85 -0
- package/test-app/.cursor/skills/hive-middleware/SKILL.md +104 -0
- package/test-app/.cursor/skills/hive-overview/SKILL.md +50 -0
- package/test-app/.cursor/skills/hive-scheduler/SKILL.md +94 -0
- package/test-app/.cursor/skills/hive-schema/SKILL.md +73 -0
- package/test-app/.cursor/skills/hive-service/SKILL.md +90 -0
- package/test-app/package-lock.json +8684 -0
- package/test-app/package.json +21 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hive-middleware
|
|
3
|
+
description: How to create and use middlewares in Hive framework
|
|
4
|
+
globs:
|
|
5
|
+
- src/middlewares/*.js
|
|
6
|
+
alwaysApply: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Middlewares
|
|
10
|
+
|
|
11
|
+
Location: `/src/middlewares/{name}.js`
|
|
12
|
+
|
|
13
|
+
## Built-in Middlewares
|
|
14
|
+
|
|
15
|
+
| Name | Purpose |
|
|
16
|
+
|------|---------|
|
|
17
|
+
| `allowNoAuth` | Skip authentication |
|
|
18
|
+
| `isAuthorized` | Require authenticated user |
|
|
19
|
+
| `shouldExist` | Load resource, 404 if not found |
|
|
20
|
+
| `attachUser` | Load user from token |
|
|
21
|
+
|
|
22
|
+
## Creating Middleware
|
|
23
|
+
|
|
24
|
+
**Simple:**
|
|
25
|
+
```javascript
|
|
26
|
+
export default async (ctx, next) => {
|
|
27
|
+
// Before handler
|
|
28
|
+
if (!ctx.state.user?.isAdmin) {
|
|
29
|
+
ctx.throw(403, 'Admin only');
|
|
30
|
+
}
|
|
31
|
+
return next(); // Don't forget!
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**With parameters:**
|
|
36
|
+
```javascript
|
|
37
|
+
export default (resourceName) => async (ctx, next) => {
|
|
38
|
+
const doc = await db.services[resourceName].findOne({
|
|
39
|
+
_id: ctx.params[`${resourceName}Id`],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (!doc) ctx.throw(404, `${resourceName} not found`);
|
|
43
|
+
|
|
44
|
+
ctx.state[resourceName] = doc;
|
|
45
|
+
return next();
|
|
46
|
+
};
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**With runOrder (lower runs first):**
|
|
50
|
+
```javascript
|
|
51
|
+
const middleware = async (ctx, next) => {
|
|
52
|
+
ctx.state.isSkipAuth = true;
|
|
53
|
+
return next();
|
|
54
|
+
};
|
|
55
|
+
middleware.runOrder = -1;
|
|
56
|
+
export default middleware;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Using in Endpoints
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
// By name
|
|
63
|
+
export const middlewares = ['allowNoAuth'];
|
|
64
|
+
|
|
65
|
+
// With arguments
|
|
66
|
+
export const middlewares = [{ name: 'shouldExist', args: ['projects'] }];
|
|
67
|
+
|
|
68
|
+
// Direct import
|
|
69
|
+
import isAdmin from 'middlewares/isAdmin';
|
|
70
|
+
export const middlewares = [isAdmin];
|
|
71
|
+
|
|
72
|
+
// Factory function
|
|
73
|
+
import canEditProject from 'middlewares/canEditProject';
|
|
74
|
+
export const middlewares = [canEditProject((ctx) => ctx.params.projectId)];
|
|
75
|
+
|
|
76
|
+
// Inline
|
|
77
|
+
export const middlewares = [
|
|
78
|
+
async (ctx, next) => {
|
|
79
|
+
// Custom logic
|
|
80
|
+
return next();
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Global Middleware
|
|
86
|
+
|
|
87
|
+
Create `/src/middlewares/global.js` to run on all endpoints:
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
import isAuthorized from 'middlewares/isAuthorized';
|
|
91
|
+
import attachRootProject from 'middlewares/attachRootProject';
|
|
92
|
+
|
|
93
|
+
export default async (ctx, next) => {
|
|
94
|
+
await isAuthorized(ctx, async () => {
|
|
95
|
+
await attachRootProject(ctx, next);
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Rules
|
|
101
|
+
|
|
102
|
+
- Always call `next()` or throw
|
|
103
|
+
- Use `runOrder` to control execution order
|
|
104
|
+
- Factory functions for parameterized middlewares
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hive-overview
|
|
3
|
+
description: Hive framework structure and conventions. Apply when working with this codebase.
|
|
4
|
+
globs:
|
|
5
|
+
- src/**/*.js
|
|
6
|
+
alwaysApply: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Hive Framework Overview
|
|
10
|
+
|
|
11
|
+
Hive is a Koa-based Node.js framework with MongoDB, Zod validation, and auto-sync for embedded documents.
|
|
12
|
+
|
|
13
|
+
## Directory Structure
|
|
14
|
+
|
|
15
|
+
| Directory | Purpose | Edit? |
|
|
16
|
+
|-----------|---------|-------|
|
|
17
|
+
| `/.hive/` | Framework core | No - read only |
|
|
18
|
+
| `/src/` | Application code | Yes |
|
|
19
|
+
|
|
20
|
+
## Resources
|
|
21
|
+
|
|
22
|
+
A resource is a feature module in `/src/resources/{name}/`:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
src/resources/{name}/
|
|
26
|
+
├── {name}.schema.js # Required: DB schema
|
|
27
|
+
├── endpoints/ # API routes
|
|
28
|
+
├── handlers/ # Event listeners
|
|
29
|
+
└── methods/ # Reusable functions
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Built-in (in .hive/)
|
|
33
|
+
|
|
34
|
+
- `tokens` - Auth token storage
|
|
35
|
+
- `users` - Base user schema
|
|
36
|
+
- `db` - Database layer with services
|
|
37
|
+
|
|
38
|
+
## Key Imports
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
import db from 'db'; // Database
|
|
42
|
+
import config from 'app-config'; // Config
|
|
43
|
+
import { z } from 'zod'; // Validation
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Services Access
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
const taskService = db.services.tasks; // Auto-created from schema
|
|
50
|
+
```
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hive-scheduler
|
|
3
|
+
description: How to create scheduled jobs in Hive framework
|
|
4
|
+
globs:
|
|
5
|
+
- src/scheduler/handlers/*.js
|
|
6
|
+
alwaysApply: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Scheduler Jobs
|
|
10
|
+
|
|
11
|
+
Background jobs on cron schedules.
|
|
12
|
+
|
|
13
|
+
Location: `/src/scheduler/handlers/{jobName}.js`
|
|
14
|
+
|
|
15
|
+
## Template
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import db from 'db';
|
|
19
|
+
|
|
20
|
+
export const handler = async () => {
|
|
21
|
+
// Job logic
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const cron = '0 * * * *'; // Every hour
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Cron Patterns
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
┌─ minute (0-59)
|
|
31
|
+
│ ┌─ hour (0-23)
|
|
32
|
+
│ │ ┌─ day of month (1-31)
|
|
33
|
+
│ │ │ ┌─ month (1-12)
|
|
34
|
+
│ │ │ │ ┌─ day of week (0-6)
|
|
35
|
+
* * * * *
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Pattern | Schedule |
|
|
39
|
+
|---------|----------|
|
|
40
|
+
| `* * * * *` | Every minute |
|
|
41
|
+
| `*/5 * * * *` | Every 5 minutes |
|
|
42
|
+
| `0 * * * *` | Every hour |
|
|
43
|
+
| `0 */12 * * *` | Every 12 hours |
|
|
44
|
+
| `0 0 * * *` | Daily at midnight |
|
|
45
|
+
| `0 9 * * 1` | Mondays at 9am |
|
|
46
|
+
|
|
47
|
+
## Examples
|
|
48
|
+
|
|
49
|
+
**Sync external data:**
|
|
50
|
+
```javascript
|
|
51
|
+
import db from 'db';
|
|
52
|
+
import moment from 'moment';
|
|
53
|
+
import externalApi from 'services/externalApi';
|
|
54
|
+
|
|
55
|
+
export const handler = async () => {
|
|
56
|
+
const items = await externalApi.list({
|
|
57
|
+
updatedSince: moment().subtract(5, 'minutes').toDate(),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
for (const item of items) {
|
|
61
|
+
await db.services.items.updateOne(
|
|
62
|
+
{ externalId: item.id },
|
|
63
|
+
(doc) => ({ ...doc, ...item })
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const cron = '*/5 * * * *';
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Mark overdue:**
|
|
72
|
+
```javascript
|
|
73
|
+
import db from 'db';
|
|
74
|
+
import moment from 'moment';
|
|
75
|
+
|
|
76
|
+
export const handler = async () => {
|
|
77
|
+
await db.services.invoices.updateMany(
|
|
78
|
+
{
|
|
79
|
+
isPaid: { $ne: true },
|
|
80
|
+
isDue: { $ne: true },
|
|
81
|
+
dueOn: { $lt: new Date() },
|
|
82
|
+
},
|
|
83
|
+
(doc) => ({ ...doc, isDue: true })
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const cron = '0 */12 * * *';
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Rules
|
|
91
|
+
|
|
92
|
+
- Export both `handler` and `cron`
|
|
93
|
+
- Keep jobs idempotent (safe to re-run)
|
|
94
|
+
- Log progress for debugging
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hive-schema
|
|
3
|
+
description: How to create database schemas in Hive framework
|
|
4
|
+
globs:
|
|
5
|
+
- src/resources/**/*.schema.js
|
|
6
|
+
alwaysApply: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Creating Database Schemas
|
|
10
|
+
|
|
11
|
+
Location: `/src/resources/{name}/{name}.schema.js`
|
|
12
|
+
|
|
13
|
+
## Template
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
import dbSchema from 'helpers/schema/db.schema.js';
|
|
18
|
+
|
|
19
|
+
const schema = dbSchema.extend({
|
|
20
|
+
// Fields here
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export default schema;
|
|
24
|
+
|
|
25
|
+
export const secureFields = []; // Hidden from API responses
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Field Patterns
|
|
29
|
+
|
|
30
|
+
**Simple fields:**
|
|
31
|
+
```javascript
|
|
32
|
+
title: z.coerce.string().nullable().optional(),
|
|
33
|
+
count: z.coerce.number().nullable().optional(),
|
|
34
|
+
isActive: z.coerce.boolean().nullable().optional(),
|
|
35
|
+
dueOn: z.coerce.date().nullable().optional(),
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Reference to another document:**
|
|
39
|
+
```javascript
|
|
40
|
+
user: z
|
|
41
|
+
.object({
|
|
42
|
+
_id: z.string(),
|
|
43
|
+
fullName: z.coerce.string().nullable().optional(),
|
|
44
|
+
avatarUrl: z.coerce.string().nullable().optional(),
|
|
45
|
+
})
|
|
46
|
+
.nullable()
|
|
47
|
+
.optional(),
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Array of references:**
|
|
51
|
+
```javascript
|
|
52
|
+
managers: z
|
|
53
|
+
.array(
|
|
54
|
+
z.object({
|
|
55
|
+
_id: z.string(),
|
|
56
|
+
fullName: z.coerce.string().nullable().optional(),
|
|
57
|
+
}).nullable().optional(),
|
|
58
|
+
)
|
|
59
|
+
.nullable()
|
|
60
|
+
.optional(),
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Flexible object:**
|
|
64
|
+
```javascript
|
|
65
|
+
data: z.object({}).passthrough().nullable().optional(),
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Rules
|
|
69
|
+
|
|
70
|
+
- Always use `z.coerce` for type safety
|
|
71
|
+
- Always add `.nullable().optional()` unless required
|
|
72
|
+
- Include fields you need in references (for auto-sync)
|
|
73
|
+
- Add sensitive fields to `secureFields` array
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hive-service
|
|
3
|
+
description: How to create external services in Hive framework
|
|
4
|
+
globs:
|
|
5
|
+
- src/services/*.js
|
|
6
|
+
alwaysApply: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Services
|
|
10
|
+
|
|
11
|
+
Services wrap external APIs and utilities.
|
|
12
|
+
|
|
13
|
+
Location: `/src/services/{name}.js`
|
|
14
|
+
|
|
15
|
+
## API Client Template
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import config from 'app-config';
|
|
19
|
+
import axios from 'axios';
|
|
20
|
+
|
|
21
|
+
const client = axios.create({
|
|
22
|
+
baseURL: 'https://api.example.com',
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Bearer ${config.example.apiKey}`,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export default {
|
|
29
|
+
getItems: async (params) => {
|
|
30
|
+
const response = await client.get('/items', { params });
|
|
31
|
+
return response.data;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
createItem: async (data) => {
|
|
35
|
+
const response = await client.post('/items', data);
|
|
36
|
+
return response.data;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## SDK Wrapper Template
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
import config from 'app-config';
|
|
45
|
+
import { WebClient } from '@slack/web-api';
|
|
46
|
+
|
|
47
|
+
const client = new WebClient(config.slack.botToken);
|
|
48
|
+
|
|
49
|
+
export default {
|
|
50
|
+
client,
|
|
51
|
+
|
|
52
|
+
postMessage: async ({ channel, text }) => {
|
|
53
|
+
return client.chat.postMessage({ channel, text });
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Utility Service Template
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
import _ from 'lodash';
|
|
62
|
+
|
|
63
|
+
export const when = (condition, result, elseResult = {}) => {
|
|
64
|
+
if (_.isUndefined(condition)) return {};
|
|
65
|
+
if (!condition) return elseResult;
|
|
66
|
+
return _.isFunction(result) ? result() : result;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const base64 = {
|
|
70
|
+
encode: (obj) => Buffer.from(JSON.stringify(obj)).toString('base64'),
|
|
71
|
+
decode: (str) => JSON.parse(Buffer.from(str, 'base64').toString()),
|
|
72
|
+
};
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Using Services
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
import harvest from 'services/harvest';
|
|
79
|
+
import slackService from 'services/slack';
|
|
80
|
+
import { when } from 'services/utils';
|
|
81
|
+
|
|
82
|
+
// API calls
|
|
83
|
+
const invoices = await harvest.getInvoices({ projectId });
|
|
84
|
+
|
|
85
|
+
// SDK usage
|
|
86
|
+
await slackService.postMessage({ channel: '#general', text: 'Hello' });
|
|
87
|
+
|
|
88
|
+
// Utilities
|
|
89
|
+
const query = { ...when(status, { status }) };
|
|
90
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node_modules
|
package/.hive/Dockerfile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
FROM --platform=linux/amd64 node:16.13.1-alpine3.13 as base
|
|
2
|
+
RUN apk add --no-cache python3 py3-pip
|
|
3
|
+
|
|
4
|
+
ENV NODE_ENV=production
|
|
5
|
+
ENV APP_ENV=production
|
|
6
|
+
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
EXPOSE 3001
|
|
9
|
+
COPY ["./package*.json", "/app/"]
|
|
10
|
+
|
|
11
|
+
RUN npm set progress=false && npm config set depth 0
|
|
12
|
+
|
|
13
|
+
RUN npm set-script prepare ""
|
|
14
|
+
|
|
15
|
+
RUN npm ci --only=production --quiet
|
|
16
|
+
|
|
17
|
+
COPY ./ ./
|
|
18
|
+
|
|
19
|
+
RUN mkdir -p /project/logs
|
|
20
|
+
RUN touch /project/logs/log.txt
|
|
21
|
+
|
|
22
|
+
CMD npm start 2>&1 | tee /project/logs/log.txt
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
FROM node:16.13.1-alpine3.13 as base
|
|
2
|
+
RUN apk add --no-cache python3 py3-pip
|
|
3
|
+
|
|
4
|
+
ARG NODE_ENV=development
|
|
5
|
+
ARG APP_ENV
|
|
6
|
+
ARG PROJECT_SRC=/project
|
|
7
|
+
|
|
8
|
+
ENV NODE_ENV=$NODE_ENV
|
|
9
|
+
ENV APP_ENV=$APP_ENV
|
|
10
|
+
ENV PROJECT_SRC=$PROJECT_SRC
|
|
11
|
+
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
COPY ["./package*.json", "/app/"]
|
|
14
|
+
# Disable husky
|
|
15
|
+
RUN npm set-script prepare ""
|
|
16
|
+
|
|
17
|
+
RUN npm ci --quiet
|
|
18
|
+
COPY . ./
|
|
19
|
+
|
|
20
|
+
RUN npm run build-assets
|
|
21
|
+
|
|
22
|
+
FROM base as migrator
|
|
23
|
+
CMD npm run migrate
|
|
24
|
+
|
|
25
|
+
FROM base as scheduler
|
|
26
|
+
CMD npm run schedule-dev
|
|
27
|
+
|
|
28
|
+
FROM base as api
|
|
29
|
+
|
|
30
|
+
EXPOSE 3001
|
|
31
|
+
EXPOSE 3012
|
|
32
|
+
|
|
33
|
+
CMD npm run dev 2>&1 | tee /logs/log.txt
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
FROM node:16.13.1-alpine3.13 as base
|
|
2
|
+
RUN apk add --no-cache python3 py3-pip
|
|
3
|
+
|
|
4
|
+
ENV NODE_ENV=production
|
|
5
|
+
ENV APP_ENV=production
|
|
6
|
+
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
EXPOSE 3001
|
|
9
|
+
COPY ["./package*.json", "./.eslintrc.js", "/app/"]
|
|
10
|
+
|
|
11
|
+
RUN npm set progress=false && npm config set depth 0
|
|
12
|
+
|
|
13
|
+
RUN npm set-script prepare ""
|
|
14
|
+
|
|
15
|
+
RUN npm ci --only=production --quiet
|
|
16
|
+
|
|
17
|
+
COPY ./ ./
|
|
18
|
+
|
|
19
|
+
RUN ls /app/src/config/.env
|
|
20
|
+
|
|
21
|
+
RUN rm /app/src/config/.env
|
|
22
|
+
RUN mv /app/src/config/.env.production /app/src/config/.env
|
|
23
|
+
|
|
24
|
+
RUN cat /app/src/config/.env
|
|
25
|
+
|
|
26
|
+
RUN mkdir -p /project/logs
|
|
27
|
+
RUN touch /project/logs/log.txt
|
|
28
|
+
|
|
29
|
+
CMD npm start 2>&1 | tee /project/logs/log.txt
|
package/.hive/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
// Function to create directories recursively
|
|
5
|
+
function mkdirRecursive(dir) {
|
|
6
|
+
if (!fs.existsSync(dir)) {
|
|
7
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Function to convert JSON schema to JavaScript code
|
|
12
|
+
function convertJsonToJs(schema) {
|
|
13
|
+
let jsCode = "const Joi = require('joi');\n\n";
|
|
14
|
+
jsCode += `const ${schema.name} = Joi.object({\n`;
|
|
15
|
+
for (const [key, value] of Object.entries(schema.schema)) {
|
|
16
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
17
|
+
jsCode += ` ${key}: Joi.object({\n`;
|
|
18
|
+
for (const [subKey, subValue] of Object.entries(value)) {
|
|
19
|
+
jsCode += ` ${subKey}: ${subValue},\n`;
|
|
20
|
+
}
|
|
21
|
+
jsCode += ` }),\n`;
|
|
22
|
+
} else {
|
|
23
|
+
jsCode += ` ${key}: ${value},\n`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
jsCode += "});\n\n";
|
|
27
|
+
jsCode += `module.exports = ${schema.name};\n`;
|
|
28
|
+
return jsCode;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Function to generate endpoint code
|
|
32
|
+
function createEndpointCode(endpoint) {
|
|
33
|
+
let requestSchema = "const Joi = require('joi');\n\n";
|
|
34
|
+
requestSchema += "module.exports.requestSchema = Joi.object({\n";
|
|
35
|
+
for (const [key, value] of Object.entries(endpoint.requestSchema)) {
|
|
36
|
+
requestSchema += ` ${key}: ${value},\n`;
|
|
37
|
+
}
|
|
38
|
+
requestSchema += "});\n\n";
|
|
39
|
+
|
|
40
|
+
return `
|
|
41
|
+
${endpoint.handler}
|
|
42
|
+
|
|
43
|
+
${requestSchema}
|
|
44
|
+
module.exports.endpoint = ${JSON.stringify(endpoint.endpoint, null, 2)};
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Main function to generate the project structure
|
|
49
|
+
function generateProjectStructure(resources) {
|
|
50
|
+
resources.forEach((resource) => {
|
|
51
|
+
const resourceDir = path.join(__dirname, "src", "resources", resource.name);
|
|
52
|
+
mkdirRecursive(resourceDir);
|
|
53
|
+
|
|
54
|
+
// Create schemas directory and files
|
|
55
|
+
if (resource.schemas) {
|
|
56
|
+
const schemaDir = path.join(resourceDir);
|
|
57
|
+
mkdirRecursive(schemaDir);
|
|
58
|
+
resource.schemas.forEach((schema) => {
|
|
59
|
+
const schemaCode = convertJsonToJs(schema);
|
|
60
|
+
fs.writeFileSync(
|
|
61
|
+
path.join(schemaDir, `${schema.name.toLowerCase()}.schema.js`),
|
|
62
|
+
schemaCode
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Create endpoints directory and files
|
|
68
|
+
if (resource.endpoints) {
|
|
69
|
+
const endpointDir = path.join(resourceDir, "endpoints");
|
|
70
|
+
mkdirRecursive(endpointDir);
|
|
71
|
+
resource.endpoints.forEach((endpoint) => {
|
|
72
|
+
const endpointCode = createEndpointCode(endpoint);
|
|
73
|
+
fs.writeFileSync(
|
|
74
|
+
path.join(endpointDir, `${endpoint.name}.js`),
|
|
75
|
+
endpointCode
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Create handlers directory and files
|
|
81
|
+
if (resource.handlers) {
|
|
82
|
+
const handlerDir = path.join(resourceDir, "handlers");
|
|
83
|
+
mkdirRecursive(handlerDir);
|
|
84
|
+
resource.handlers.forEach((handler) => {
|
|
85
|
+
const handlerCode = handler.handler;
|
|
86
|
+
fs.writeFileSync(
|
|
87
|
+
path.join(handlerDir, `${handler.name}.js`),
|
|
88
|
+
handlerCode
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Create methods directory and files
|
|
94
|
+
if (resource.methods) {
|
|
95
|
+
const methodDir = path.join(resourceDir, "methods");
|
|
96
|
+
mkdirRecursive(methodDir);
|
|
97
|
+
resource.methods.forEach((method) => {
|
|
98
|
+
const methodCode = method.handler;
|
|
99
|
+
fs.writeFileSync(path.join(methodDir, `${method.name}.js`), methodCode);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Main entry point
|
|
106
|
+
const [, , jsonFilePath] = process.argv;
|
|
107
|
+
|
|
108
|
+
if (!jsonFilePath) {
|
|
109
|
+
console.error("Please provide the path to the JSON file.");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const rawData = fs.readFileSync(jsonFilePath, "utf8");
|
|
114
|
+
const { resources } = JSON.parse(rawData);
|
|
115
|
+
|
|
116
|
+
generateProjectStructure(resources);
|
|
117
|
+
|
|
118
|
+
console.log("Hive-based project structure generated successfully.");
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
kind: Deployment
|
|
2
|
+
apiVersion: apps/v1
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ .Values.service }}
|
|
5
|
+
labels:
|
|
6
|
+
app: {{ .Values.service }}
|
|
7
|
+
spec:
|
|
8
|
+
replicas: 1
|
|
9
|
+
selector:
|
|
10
|
+
matchLabels:
|
|
11
|
+
app: {{ .Values.service }}
|
|
12
|
+
template:
|
|
13
|
+
metadata:
|
|
14
|
+
labels:
|
|
15
|
+
app: {{ .Values.service }}
|
|
16
|
+
spec:
|
|
17
|
+
restartPolicy: Always
|
|
18
|
+
containers:
|
|
19
|
+
- name: {{ .Values.service }}
|
|
20
|
+
image: {{ .Values.containerRegistry }}:{{ .Values.imagesVersion }}
|
|
21
|
+
env:
|
|
22
|
+
- name: PROJECT_ID
|
|
23
|
+
value: {{ .Values.projectId }}
|
|
24
|
+
{{- range .Values.env }}
|
|
25
|
+
- name: {{ .name }}
|
|
26
|
+
value: {{ .value }}
|
|
27
|
+
{{- end }}
|
|
28
|
+
imagePullPolicy: Always
|
|
29
|
+
livenessProbe:
|
|
30
|
+
httpGet:
|
|
31
|
+
path: /health
|
|
32
|
+
port: {{ .Values.port }}
|
|
33
|
+
initialDelaySeconds: 300
|
|
34
|
+
periodSeconds: 10
|
|
35
|
+
ports:
|
|
36
|
+
- containerPort: {{ .Values.port }}
|
|
37
|
+
protocol: TCP
|
|
38
|
+
nodeSelector:
|
|
39
|
+
doks.digitalocean.com/node-pool: {{ .Values.nodePool }}
|
|
40
|
+
strategy:
|
|
41
|
+
type: RollingUpdate
|
|
42
|
+
rollingUpdate:
|
|
43
|
+
maxUnavailable: 0
|
|
44
|
+
maxSurge: 1
|