miqro.js 0.1.2 → 0.1.4
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/LICENSE +21 -0
- package/README.md +57 -27
- package/dist/cli.js +77 -31
- package/dist/index.d.ts +1 -1
- package/dist/index.js +54 -24
- package/dist/types.d.ts +15 -4
- package/package.json +3 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 qnton
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
# Miqro
|
|
2
2
|
|
|
3
3
|
A minimal, high-performance microservice engine built on [Bun](https://bun.sh/) and [Hono](https://hono.dev/).
|
|
4
|
-
Designed to process webhooks and run scheduled cron jobs utilizing file-based workflow configurations.
|
|
4
|
+
Designed to process webhooks and run scheduled cron jobs utilizing file-based workflow configurations with first-class TypeScript support and Zod validation.
|
|
5
|
+
|
|
6
|
+
## Key Features
|
|
7
|
+
|
|
8
|
+
- **High Performance:** Powered by Bun and Hono.
|
|
9
|
+
- **Developer Friendly:** Built-in CLI for scaffolding and development.
|
|
10
|
+
- **Zod Validation:** Automatic request validation for your webhooks.
|
|
11
|
+
- **Security First:** Simple API Key and Bearer Token authentication.
|
|
12
|
+
- **Scheduled Jobs:** Native support for cron-based workflows.
|
|
13
|
+
- **Middleware Support:** Easily extend the engine with Hono middleware.
|
|
14
|
+
- **Single File Builds:** Bundle your entire project into a single executable artifact.
|
|
5
15
|
|
|
6
16
|
## Quick Start
|
|
7
17
|
|
|
@@ -11,7 +21,7 @@ bunx miqro.js init
|
|
|
11
21
|
bun add miqro.js
|
|
12
22
|
```
|
|
13
23
|
|
|
14
|
-
This creates a `miqro.config.ts`, a `workflows/` directory,
|
|
24
|
+
This creates a `miqro.config.ts`, a `workflows/` directory, and configures your environment.
|
|
15
25
|
|
|
16
26
|
Start the development server with hot-reloading:
|
|
17
27
|
```bash
|
|
@@ -20,46 +30,57 @@ bun run dev
|
|
|
20
30
|
|
|
21
31
|
## Commands
|
|
22
32
|
|
|
23
|
-
- `miqro
|
|
24
|
-
- `miqro
|
|
25
|
-
- `miqro
|
|
26
|
-
- `miqro
|
|
33
|
+
- `miqro init`: Scaffolds a new project.
|
|
34
|
+
- `miqro dev`: Starts the engine in development mode with hot-reloading.
|
|
35
|
+
- `miqro start`: Starts the engine for production.
|
|
36
|
+
- `miqro build`: Compiles your project into a single standalone file at `./dist/index.js`.
|
|
27
37
|
|
|
28
38
|
## Configuration
|
|
29
39
|
|
|
30
|
-
The engine is configured via `miqro.config.ts
|
|
40
|
+
The engine is configured via `miqro.config.ts`:
|
|
31
41
|
|
|
32
42
|
```typescript
|
|
33
|
-
// miqro.config.ts
|
|
34
43
|
import type { MiqroConfig } from 'miqro.js';
|
|
35
44
|
|
|
36
45
|
export default {
|
|
37
46
|
port: 3000,
|
|
38
|
-
workflowsDir: './workflows',
|
|
47
|
+
workflowsDir: './workflows',
|
|
48
|
+
middleware: [
|
|
49
|
+
async (c, next) => {
|
|
50
|
+
console.log(`[${c.req.method}] ${c.req.url}`);
|
|
51
|
+
await next();
|
|
52
|
+
}
|
|
53
|
+
]
|
|
39
54
|
} satisfies MiqroConfig;
|
|
40
55
|
```
|
|
41
56
|
|
|
42
57
|
## Workflows
|
|
43
58
|
|
|
44
|
-
|
|
45
|
-
Miqro automatically discovers `.ts` or `.js` module exports and registers them.
|
|
59
|
+
### Webhook Workflow with Validation
|
|
46
60
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Webhooks respond to `POST /{id}`. Authentication supports `none`, `apiKey`, or `bearer`.
|
|
61
|
+
Webhooks respond to `POST /{id}`. Use **Zod** to validate your payloads and get full type safety in your execution logic.
|
|
50
62
|
|
|
51
63
|
```typescript
|
|
52
|
-
|
|
53
|
-
import type { Workflow } from
|
|
64
|
+
import { z } from "zod";
|
|
65
|
+
import type { Workflow } from "miqro.js";
|
|
54
66
|
|
|
55
67
|
export default {
|
|
56
68
|
config: {
|
|
57
69
|
id: 'process-payment',
|
|
58
70
|
name: 'Payment Webhook',
|
|
59
|
-
auth: { type: 'apiKey', key: process.env.API_KEY || 'secret' }
|
|
71
|
+
auth: { type: 'apiKey', key: process.env.API_KEY || 'secret' },
|
|
72
|
+
schema: z.object({
|
|
73
|
+
amount: z.number().positive(),
|
|
74
|
+
currency: z.string().length(3),
|
|
75
|
+
customerEmail: z.string().email(),
|
|
76
|
+
})
|
|
60
77
|
},
|
|
61
|
-
execute: async (payload
|
|
62
|
-
|
|
78
|
+
execute: async (payload, context) => {
|
|
79
|
+
// payload is automatically typed based on the schema!
|
|
80
|
+
console.log(`Processing ${payload.amount} ${payload.currency} for ${payload.customerEmail}`);
|
|
81
|
+
|
|
82
|
+
// access request metadata via context
|
|
83
|
+
console.log(`User Agent: ${context.headers['user-agent']}`);
|
|
63
84
|
}
|
|
64
85
|
} satisfies Workflow;
|
|
65
86
|
```
|
|
@@ -69,18 +90,27 @@ export default {
|
|
|
69
90
|
If a workflow config provides a `schedule` property (a valid Cron string), it will be executed automatically.
|
|
70
91
|
|
|
71
92
|
```typescript
|
|
72
|
-
// workflows/example-cron.ts
|
|
73
93
|
import type { Workflow } from 'miqro.js';
|
|
74
94
|
|
|
75
95
|
export default {
|
|
76
96
|
config: {
|
|
77
|
-
id: '
|
|
78
|
-
name: '
|
|
79
|
-
auth: { type: 'none' },
|
|
80
|
-
schedule: '0
|
|
97
|
+
id: 'daily-cleanup',
|
|
98
|
+
name: 'Database Cleanup',
|
|
99
|
+
auth: { type: 'none' },
|
|
100
|
+
schedule: '0 0 * * *' // Runs every night at midnight
|
|
81
101
|
},
|
|
82
|
-
execute: async () => {
|
|
83
|
-
console.log(`Running
|
|
102
|
+
execute: async (payload, context) => {
|
|
103
|
+
console.log(`Running scheduled cleanup for ${context.name}...`);
|
|
84
104
|
}
|
|
85
105
|
} satisfies Workflow;
|
|
86
|
-
```
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Execution Context
|
|
109
|
+
|
|
110
|
+
The `execute` function receives a `MiqroContext` object providing access to:
|
|
111
|
+
|
|
112
|
+
- `workflowId`: The ID of the current workflow.
|
|
113
|
+
- `name`: The display name of the workflow.
|
|
114
|
+
- `params`: Route parameters.
|
|
115
|
+
- `query`: URL query parameters.
|
|
116
|
+
- `headers`: HTTP Request headers.
|
package/dist/cli.js
CHANGED
|
@@ -2939,7 +2939,14 @@ async function loadWorkflows(workflowsDir) {
|
|
|
2939
2939
|
import_node_cron.default.schedule(workflow.config.schedule, () => {
|
|
2940
2940
|
console.log(`[Cron] Executing scheduled workflow: ${workflow.config.id}`);
|
|
2941
2941
|
const payload = { source: "cron", timestamp: Date.now() };
|
|
2942
|
-
|
|
2942
|
+
const context = {
|
|
2943
|
+
workflowId: workflow.config.id,
|
|
2944
|
+
name: workflow.config.name,
|
|
2945
|
+
params: {},
|
|
2946
|
+
query: {},
|
|
2947
|
+
headers: {}
|
|
2948
|
+
};
|
|
2949
|
+
workflow.execute(payload, context);
|
|
2943
2950
|
});
|
|
2944
2951
|
console.log(`[Miqro] Scheduled workflow '${workflow.config.id}' with cron: '${workflow.config.schedule}'`);
|
|
2945
2952
|
}
|
|
@@ -2961,7 +2968,14 @@ async function startMiqroCore(config, staticWorkflows) {
|
|
|
2961
2968
|
import_node_cron.default.schedule(workflow.config.schedule, () => {
|
|
2962
2969
|
console.log(`[Cron] Executing scheduled workflow: ${workflow.config.id}`);
|
|
2963
2970
|
const payload = { source: "cron", timestamp: Date.now() };
|
|
2964
|
-
|
|
2971
|
+
const context = {
|
|
2972
|
+
workflowId: workflow.config.id,
|
|
2973
|
+
name: workflow.config.name,
|
|
2974
|
+
params: {},
|
|
2975
|
+
query: {},
|
|
2976
|
+
headers: {}
|
|
2977
|
+
};
|
|
2978
|
+
workflow.execute(payload, context);
|
|
2965
2979
|
});
|
|
2966
2980
|
console.log(`[Miqro] Scheduled workflow '${workflow.config.id}' with cron: '${workflow.config.schedule}'`);
|
|
2967
2981
|
}
|
|
@@ -2969,6 +2983,11 @@ async function startMiqroCore(config, staticWorkflows) {
|
|
|
2969
2983
|
}
|
|
2970
2984
|
const app = new Hono2;
|
|
2971
2985
|
app.use("*", logger());
|
|
2986
|
+
if (config.middleware) {
|
|
2987
|
+
for (const mw of config.middleware) {
|
|
2988
|
+
app.use("*", mw);
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2972
2991
|
app.get("/health", (c) => c.json({
|
|
2973
2992
|
status: "ok",
|
|
2974
2993
|
uptime: process.uptime(),
|
|
@@ -2976,34 +2995,45 @@ async function startMiqroCore(config, staticWorkflows) {
|
|
|
2976
2995
|
}));
|
|
2977
2996
|
app.post("/:workflowId", async (c) => {
|
|
2978
2997
|
try {
|
|
2979
|
-
const payload = await c.req.json();
|
|
2980
2998
|
const workflowId = c.req.param("workflowId");
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2999
|
+
const workflow = workflows[workflowId];
|
|
3000
|
+
if (!workflow) {
|
|
3001
|
+
return c.json({ error: `Workflow '${workflowId}' not found` }, 404);
|
|
3002
|
+
}
|
|
3003
|
+
const authHeader = c.req.header("Authorization");
|
|
3004
|
+
const { auth } = workflow.config;
|
|
3005
|
+
if (auth.type === "apiKey") {
|
|
3006
|
+
const apiKey = c.req.header("x-api-key") || c.req.query("apiKey");
|
|
3007
|
+
if (apiKey !== auth.key) {
|
|
3008
|
+
return c.json({ error: "Unauthorized: Invalid API Key" }, 401);
|
|
2985
3009
|
}
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
const apiKey = c.req.header("x-api-key") || c.req.query("apiKey");
|
|
2990
|
-
if (apiKey !== auth.key) {
|
|
2991
|
-
return c.json({ error: "Unauthorized: Invalid API Key" }, 401);
|
|
2992
|
-
}
|
|
2993
|
-
} else if (auth.type === "bearer") {
|
|
2994
|
-
if (!authHeader || !authHeader.startsWith(`Bearer ${auth.token}`)) {
|
|
2995
|
-
return c.json({ error: "Unauthorized: Invalid Bearer token" }, 401);
|
|
2996
|
-
}
|
|
3010
|
+
} else if (auth.type === "bearer") {
|
|
3011
|
+
if (!authHeader || !authHeader.startsWith(`Bearer ${auth.token}`)) {
|
|
3012
|
+
return c.json({ error: "Unauthorized: Invalid Bearer token" }, 401);
|
|
2997
3013
|
}
|
|
2998
|
-
await workflow.execute(payload);
|
|
2999
|
-
return c.json({
|
|
3000
|
-
status: "success",
|
|
3001
|
-
message: `Workflow '${workflowId}' executed`
|
|
3002
|
-
});
|
|
3003
3014
|
}
|
|
3015
|
+
let payload = await c.req.json();
|
|
3016
|
+
if (workflow.config.schema) {
|
|
3017
|
+
const result = workflow.config.schema.safeParse(payload);
|
|
3018
|
+
if (!result.success) {
|
|
3019
|
+
return c.json({
|
|
3020
|
+
error: "Validation Failed",
|
|
3021
|
+
details: result.error.format()
|
|
3022
|
+
}, 400);
|
|
3023
|
+
}
|
|
3024
|
+
payload = result.data;
|
|
3025
|
+
}
|
|
3026
|
+
const context = {
|
|
3027
|
+
workflowId: workflow.config.id,
|
|
3028
|
+
name: workflow.config.name,
|
|
3029
|
+
params: c.req.param(),
|
|
3030
|
+
query: c.req.query(),
|
|
3031
|
+
headers: c.req.header()
|
|
3032
|
+
};
|
|
3033
|
+
await workflow.execute(payload, context);
|
|
3004
3034
|
return c.json({
|
|
3005
3035
|
status: "success",
|
|
3006
|
-
message:
|
|
3036
|
+
message: `Workflow '${workflowId}' executed`
|
|
3007
3037
|
});
|
|
3008
3038
|
} catch (error) {
|
|
3009
3039
|
console.error("[Miqro Webhook Error]", error);
|
|
@@ -3061,18 +3091,25 @@ export default {
|
|
|
3061
3091
|
}
|
|
3062
3092
|
const sampleWorkflowPath = resolve(workflowsPath, "sample.ts");
|
|
3063
3093
|
if (!existsSync(sampleWorkflowPath)) {
|
|
3064
|
-
const sampleWorkflow = `import
|
|
3094
|
+
const sampleWorkflow = `import { z } from "zod";
|
|
3095
|
+
import type { Workflow } from "miqro.js";
|
|
3096
|
+
|
|
3097
|
+
const schema = z.object({
|
|
3098
|
+
message: z.string().min(1),
|
|
3099
|
+
});
|
|
3065
3100
|
|
|
3066
3101
|
export default {
|
|
3067
3102
|
config: {
|
|
3068
3103
|
id: "hello-world",
|
|
3069
3104
|
name: "Hello World Workflow",
|
|
3070
3105
|
auth: { type: "none" },
|
|
3106
|
+
schema,
|
|
3071
3107
|
},
|
|
3072
|
-
execute: async (payload
|
|
3073
|
-
console.log("Hello from Miqro!", payload);
|
|
3108
|
+
execute: async (payload, context) => {
|
|
3109
|
+
console.log("Hello from Miqro!", payload.message);
|
|
3110
|
+
console.log("Context workflow ID:", context.workflowId);
|
|
3074
3111
|
},
|
|
3075
|
-
} satisfies Workflow
|
|
3112
|
+
} satisfies Workflow<z.infer<typeof schema>>;
|
|
3076
3113
|
`;
|
|
3077
3114
|
await writeFile(sampleWorkflowPath, sampleWorkflow);
|
|
3078
3115
|
}
|
|
@@ -3081,6 +3118,13 @@ export default {
|
|
|
3081
3118
|
const pkgContent = {
|
|
3082
3119
|
name: "miqro-project",
|
|
3083
3120
|
type: "module",
|
|
3121
|
+
dependencies: {
|
|
3122
|
+
"miqro.js": "^0.1.3",
|
|
3123
|
+
zod: "^3.24.1"
|
|
3124
|
+
},
|
|
3125
|
+
devDependencies: {
|
|
3126
|
+
"@types/bun": "latest"
|
|
3127
|
+
},
|
|
3084
3128
|
scripts: {
|
|
3085
3129
|
dev: "miqro dev",
|
|
3086
3130
|
start: "miqro start",
|
|
@@ -3102,7 +3146,8 @@ export default {
|
|
|
3102
3146
|
noEmit: true,
|
|
3103
3147
|
strict: true,
|
|
3104
3148
|
skipLibCheck: true,
|
|
3105
|
-
allowSyntheticDefaultImports: true
|
|
3149
|
+
allowSyntheticDefaultImports: true,
|
|
3150
|
+
types: ["bun-types"]
|
|
3106
3151
|
}
|
|
3107
3152
|
};
|
|
3108
3153
|
await writeFile(tsconfigPath, JSON.stringify(tsconfigContent, null, 2));
|
|
@@ -3110,7 +3155,7 @@ export default {
|
|
|
3110
3155
|
console.log("\u2705 Created miqro.config.ts and workflows directory with a sample.");
|
|
3111
3156
|
console.log(`
|
|
3112
3157
|
\uD83D\uDC49 Next steps:`);
|
|
3113
|
-
console.log(" 1. Run: bun
|
|
3158
|
+
console.log(" 1. Run: bun install");
|
|
3114
3159
|
console.log(" 2. Run: bun run dev");
|
|
3115
3160
|
process.exit(0);
|
|
3116
3161
|
}
|
|
@@ -3134,7 +3179,8 @@ export default {
|
|
|
3134
3179
|
console.log("\uD83D\uDD04 Starting Miqro in DEV mode (hot-reloading enabled)...");
|
|
3135
3180
|
Bun.spawn(["bun", "--watch", Bun.argv[1], "start"], {
|
|
3136
3181
|
stdout: "inherit",
|
|
3137
|
-
stderr: "inherit"
|
|
3182
|
+
stderr: "inherit",
|
|
3183
|
+
cwd: process.cwd()
|
|
3138
3184
|
});
|
|
3139
3185
|
} else if (command === "start") {
|
|
3140
3186
|
console.log("\uD83D\uDE80 Starting Miqro...");
|
package/dist/index.d.ts
CHANGED
|
@@ -14,4 +14,4 @@ export declare function startMiqro(config: MiqroConfig): Promise<{
|
|
|
14
14
|
port: string | number;
|
|
15
15
|
fetch: (request: Request, Env?: unknown, executionCtx?: import("hono").ExecutionContext) => Response | Promise<Response>;
|
|
16
16
|
}>;
|
|
17
|
-
export type { AuthConfig, Workflow, WorkflowConfig } from "./types";
|
|
17
|
+
export type { AuthConfig, MiqroConfig, Workflow, WorkflowConfig, } from "./types";
|
package/dist/index.js
CHANGED
|
@@ -2938,7 +2938,14 @@ async function loadWorkflows(workflowsDir) {
|
|
|
2938
2938
|
import_node_cron.default.schedule(workflow.config.schedule, () => {
|
|
2939
2939
|
console.log(`[Cron] Executing scheduled workflow: ${workflow.config.id}`);
|
|
2940
2940
|
const payload = { source: "cron", timestamp: Date.now() };
|
|
2941
|
-
|
|
2941
|
+
const context = {
|
|
2942
|
+
workflowId: workflow.config.id,
|
|
2943
|
+
name: workflow.config.name,
|
|
2944
|
+
params: {},
|
|
2945
|
+
query: {},
|
|
2946
|
+
headers: {}
|
|
2947
|
+
};
|
|
2948
|
+
workflow.execute(payload, context);
|
|
2942
2949
|
});
|
|
2943
2950
|
console.log(`[Miqro] Scheduled workflow '${workflow.config.id}' with cron: '${workflow.config.schedule}'`);
|
|
2944
2951
|
}
|
|
@@ -2960,7 +2967,14 @@ async function startMiqroCore(config, staticWorkflows) {
|
|
|
2960
2967
|
import_node_cron.default.schedule(workflow.config.schedule, () => {
|
|
2961
2968
|
console.log(`[Cron] Executing scheduled workflow: ${workflow.config.id}`);
|
|
2962
2969
|
const payload = { source: "cron", timestamp: Date.now() };
|
|
2963
|
-
|
|
2970
|
+
const context = {
|
|
2971
|
+
workflowId: workflow.config.id,
|
|
2972
|
+
name: workflow.config.name,
|
|
2973
|
+
params: {},
|
|
2974
|
+
query: {},
|
|
2975
|
+
headers: {}
|
|
2976
|
+
};
|
|
2977
|
+
workflow.execute(payload, context);
|
|
2964
2978
|
});
|
|
2965
2979
|
console.log(`[Miqro] Scheduled workflow '${workflow.config.id}' with cron: '${workflow.config.schedule}'`);
|
|
2966
2980
|
}
|
|
@@ -2968,6 +2982,11 @@ async function startMiqroCore(config, staticWorkflows) {
|
|
|
2968
2982
|
}
|
|
2969
2983
|
const app = new Hono2;
|
|
2970
2984
|
app.use("*", logger());
|
|
2985
|
+
if (config.middleware) {
|
|
2986
|
+
for (const mw of config.middleware) {
|
|
2987
|
+
app.use("*", mw);
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2971
2990
|
app.get("/health", (c) => c.json({
|
|
2972
2991
|
status: "ok",
|
|
2973
2992
|
uptime: process.uptime(),
|
|
@@ -2975,34 +2994,45 @@ async function startMiqroCore(config, staticWorkflows) {
|
|
|
2975
2994
|
}));
|
|
2976
2995
|
app.post("/:workflowId", async (c) => {
|
|
2977
2996
|
try {
|
|
2978
|
-
const payload = await c.req.json();
|
|
2979
2997
|
const workflowId = c.req.param("workflowId");
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2998
|
+
const workflow = workflows[workflowId];
|
|
2999
|
+
if (!workflow) {
|
|
3000
|
+
return c.json({ error: `Workflow '${workflowId}' not found` }, 404);
|
|
3001
|
+
}
|
|
3002
|
+
const authHeader = c.req.header("Authorization");
|
|
3003
|
+
const { auth } = workflow.config;
|
|
3004
|
+
if (auth.type === "apiKey") {
|
|
3005
|
+
const apiKey = c.req.header("x-api-key") || c.req.query("apiKey");
|
|
3006
|
+
if (apiKey !== auth.key) {
|
|
3007
|
+
return c.json({ error: "Unauthorized: Invalid API Key" }, 401);
|
|
2984
3008
|
}
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
const apiKey = c.req.header("x-api-key") || c.req.query("apiKey");
|
|
2989
|
-
if (apiKey !== auth.key) {
|
|
2990
|
-
return c.json({ error: "Unauthorized: Invalid API Key" }, 401);
|
|
2991
|
-
}
|
|
2992
|
-
} else if (auth.type === "bearer") {
|
|
2993
|
-
if (!authHeader || !authHeader.startsWith(`Bearer ${auth.token}`)) {
|
|
2994
|
-
return c.json({ error: "Unauthorized: Invalid Bearer token" }, 401);
|
|
2995
|
-
}
|
|
3009
|
+
} else if (auth.type === "bearer") {
|
|
3010
|
+
if (!authHeader || !authHeader.startsWith(`Bearer ${auth.token}`)) {
|
|
3011
|
+
return c.json({ error: "Unauthorized: Invalid Bearer token" }, 401);
|
|
2996
3012
|
}
|
|
2997
|
-
await workflow.execute(payload);
|
|
2998
|
-
return c.json({
|
|
2999
|
-
status: "success",
|
|
3000
|
-
message: `Workflow '${workflowId}' executed`
|
|
3001
|
-
});
|
|
3002
3013
|
}
|
|
3014
|
+
let payload = await c.req.json();
|
|
3015
|
+
if (workflow.config.schema) {
|
|
3016
|
+
const result = workflow.config.schema.safeParse(payload);
|
|
3017
|
+
if (!result.success) {
|
|
3018
|
+
return c.json({
|
|
3019
|
+
error: "Validation Failed",
|
|
3020
|
+
details: result.error.format()
|
|
3021
|
+
}, 400);
|
|
3022
|
+
}
|
|
3023
|
+
payload = result.data;
|
|
3024
|
+
}
|
|
3025
|
+
const context = {
|
|
3026
|
+
workflowId: workflow.config.id,
|
|
3027
|
+
name: workflow.config.name,
|
|
3028
|
+
params: c.req.param(),
|
|
3029
|
+
query: c.req.query(),
|
|
3030
|
+
headers: c.req.header()
|
|
3031
|
+
};
|
|
3032
|
+
await workflow.execute(payload, context);
|
|
3003
3033
|
return c.json({
|
|
3004
3034
|
status: "success",
|
|
3005
|
-
message:
|
|
3035
|
+
message: `Workflow '${workflowId}' executed`
|
|
3006
3036
|
});
|
|
3007
3037
|
} catch (error) {
|
|
3008
3038
|
console.error("[Miqro Webhook Error]", error);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "hono";
|
|
2
|
+
import type { z } from "zod";
|
|
1
3
|
export type AuthConfig = {
|
|
2
4
|
type: "none";
|
|
3
5
|
} | {
|
|
@@ -7,18 +9,27 @@ export type AuthConfig = {
|
|
|
7
9
|
type: "bearer";
|
|
8
10
|
token: string;
|
|
9
11
|
};
|
|
10
|
-
export interface
|
|
12
|
+
export interface MiqroContext {
|
|
13
|
+
workflowId: string;
|
|
14
|
+
name: string;
|
|
15
|
+
params: Record<string, string>;
|
|
16
|
+
query: Record<string, string | string[]>;
|
|
17
|
+
headers: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
export interface WorkflowConfig<T = unknown> {
|
|
11
20
|
id: string;
|
|
12
21
|
name: string;
|
|
13
22
|
description?: string;
|
|
14
23
|
auth: AuthConfig;
|
|
15
24
|
schedule?: string;
|
|
25
|
+
schema?: z.ZodType<T>;
|
|
16
26
|
}
|
|
17
|
-
export interface Workflow {
|
|
18
|
-
config: WorkflowConfig
|
|
19
|
-
execute: (payload:
|
|
27
|
+
export interface Workflow<T = unknown> {
|
|
28
|
+
config: WorkflowConfig<T>;
|
|
29
|
+
execute: (payload: T, context: MiqroContext) => Promise<void> | void;
|
|
20
30
|
}
|
|
21
31
|
export interface MiqroConfig {
|
|
22
32
|
workflowsDir: string;
|
|
23
33
|
port?: number;
|
|
34
|
+
middleware?: MiddlewareHandler[];
|
|
24
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "miqro.js",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Minimal, high-performance microservice engine.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"hono": "^4.12.2",
|
|
33
|
-
"node-cron": "^4.2.1"
|
|
33
|
+
"node-cron": "^4.2.1",
|
|
34
|
+
"zod": "^4.3.6"
|
|
34
35
|
}
|
|
35
36
|
}
|