@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,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hive-handler
|
|
3
|
+
description: How to create event handlers in Hive framework
|
|
4
|
+
globs:
|
|
5
|
+
- src/resources/**/handlers/*.js
|
|
6
|
+
alwaysApply: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Creating Event Handlers
|
|
10
|
+
|
|
11
|
+
Handlers react to database events automatically.
|
|
12
|
+
|
|
13
|
+
Location: `/src/resources/{name}/handlers/{handlerName}.js`
|
|
14
|
+
|
|
15
|
+
## Template
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import db from 'db';
|
|
19
|
+
|
|
20
|
+
const myService = db.services.myResource;
|
|
21
|
+
|
|
22
|
+
myService.on('created', async ({ doc }) => {
|
|
23
|
+
// Handle creation
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
myService.on('updated', async ({ doc, prevDoc }) => {
|
|
27
|
+
// Handle update
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
myService.on('removed', async ({ doc }) => {
|
|
31
|
+
// Handle removal
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Events
|
|
36
|
+
|
|
37
|
+
| Event | Payload | Trigger |
|
|
38
|
+
|-------|---------|---------|
|
|
39
|
+
| `created` | `{ doc }` | After `service.create()` |
|
|
40
|
+
| `updated` | `{ doc, prevDoc }` | After `service.updateOne/Many()` |
|
|
41
|
+
| `removed` | `{ doc }` | After `service.remove()` |
|
|
42
|
+
|
|
43
|
+
## Common Patterns
|
|
44
|
+
|
|
45
|
+
**Create related record:**
|
|
46
|
+
```javascript
|
|
47
|
+
taskService.on('created', async ({ doc }) => {
|
|
48
|
+
await eventService.create({
|
|
49
|
+
type: 'task.created',
|
|
50
|
+
data: { task: doc },
|
|
51
|
+
project: doc.project,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Update parent on child change:**
|
|
57
|
+
```javascript
|
|
58
|
+
docService.on('created', async ({ doc }) => {
|
|
59
|
+
if (doc.role === 'case-study') {
|
|
60
|
+
await projectService.updateOne(
|
|
61
|
+
{ _id: doc.project._id },
|
|
62
|
+
(p) => ({ ...p, caseStudy: doc })
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**React to specific field change:**
|
|
69
|
+
```javascript
|
|
70
|
+
import ifUpdated from 'helpers/db/ifUpdated';
|
|
71
|
+
|
|
72
|
+
taskService.on('updated', ifUpdated(['status'], async ({ doc, prevDoc }) => {
|
|
73
|
+
// Only runs when status changed
|
|
74
|
+
}));
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Cleanup on delete:**
|
|
78
|
+
```javascript
|
|
79
|
+
docService.on('removed', async ({ doc }) => {
|
|
80
|
+
await eventService.remove({ 'data.doc._id': doc._id });
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Rules
|
|
85
|
+
|
|
86
|
+
- Keep handlers fast (don't block response)
|
|
87
|
+
- Use `atomic.update` for silent bulk updates (no events)
|
|
88
|
+
- Use `ifUpdated` helper to filter field changes
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hive-mapping
|
|
3
|
+
description: Schema mappings for auto-syncing embedded documents
|
|
4
|
+
globs:
|
|
5
|
+
- src/autoMap/schemaMappings.json
|
|
6
|
+
alwaysApply: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Schema Mappings
|
|
10
|
+
|
|
11
|
+
Auto-sync embedded references when source documents change.
|
|
12
|
+
|
|
13
|
+
Location: `/src/autoMap/schemaMappings.json`
|
|
14
|
+
|
|
15
|
+
## How It Works
|
|
16
|
+
|
|
17
|
+
1. You embed document references in schemas (e.g., `user: { _id, fullName }`)
|
|
18
|
+
2. You register the mapping in `schemaMappings.json`
|
|
19
|
+
3. When source document updates, all referencing documents sync automatically
|
|
20
|
+
|
|
21
|
+
## Config Format
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"tasks": {
|
|
26
|
+
"user": {
|
|
27
|
+
"schema": "users"
|
|
28
|
+
},
|
|
29
|
+
"project": {
|
|
30
|
+
"schema": "projects"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Means: In `tasks` collection, fields `user` and `project` reference `users` and `projects` collections.
|
|
37
|
+
|
|
38
|
+
## Example
|
|
39
|
+
|
|
40
|
+
**Schema with embedded reference:**
|
|
41
|
+
```javascript
|
|
42
|
+
// tasks.schema.js
|
|
43
|
+
project: z
|
|
44
|
+
.object({
|
|
45
|
+
_id: z.string(),
|
|
46
|
+
name: z.coerce.string().nullable().optional(),
|
|
47
|
+
logoUrl: z.coerce.string().nullable().optional(),
|
|
48
|
+
})
|
|
49
|
+
.nullable()
|
|
50
|
+
.optional(),
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Mapping config:**
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"tasks": {
|
|
57
|
+
"project": {
|
|
58
|
+
"schema": "projects"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Result:** When project's `name` or `logoUrl` changes, all tasks with that project update automatically.
|
|
65
|
+
|
|
66
|
+
## Adding New Mapping
|
|
67
|
+
|
|
68
|
+
1. Define embedded reference in schema (include fields to sync)
|
|
69
|
+
2. Add entry to `schemaMappings.json`:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"yourResource": {
|
|
74
|
+
"fieldName": {
|
|
75
|
+
"schema": "sourceSchema"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Rules
|
|
82
|
+
|
|
83
|
+
- Only fields defined in the embedded object shape are synced
|
|
84
|
+
- Works for both single references and arrays
|
|
85
|
+
- Changes sync on source document `updated` event
|
|
@@ -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
|
+
```
|