zyket 1.0.53 → 1.0.55

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 (27) hide show
  1. package/.claude-plugin/marketplace.json +16 -0
  2. package/claude-plugin/.claude-plugin/commands/event.md +29 -0
  3. package/claude-plugin/.claude-plugin/commands/guard.md +37 -0
  4. package/claude-plugin/.claude-plugin/commands/handler.md +37 -0
  5. package/claude-plugin/.claude-plugin/commands/middleware.md +28 -0
  6. package/claude-plugin/.claude-plugin/commands/model.md +40 -0
  7. package/claude-plugin/.claude-plugin/commands/route.md +42 -0
  8. package/claude-plugin/.claude-plugin/commands/schedule.md +38 -0
  9. package/claude-plugin/.claude-plugin/commands/service.md +59 -0
  10. package/claude-plugin/.claude-plugin/commands/worker.md +39 -0
  11. package/claude-plugin/.claude-plugin/plugin.json +133 -0
  12. package/claude-plugin/.claude-plugin/skills/auth.md +128 -0
  13. package/claude-plugin/.claude-plugin/skills/database.md +132 -0
  14. package/claude-plugin/.claude-plugin/skills/events.md +63 -0
  15. package/claude-plugin/.claude-plugin/skills/extensions.md +75 -0
  16. package/claude-plugin/.claude-plugin/skills/middlewares.md +97 -0
  17. package/claude-plugin/.claude-plugin/skills/overview.md +109 -0
  18. package/claude-plugin/.claude-plugin/skills/routes.md +141 -0
  19. package/claude-plugin/.claude-plugin/skills/scheduler.md +60 -0
  20. package/claude-plugin/.claude-plugin/skills/services.md +152 -0
  21. package/claude-plugin/.claude-plugin/skills/socketio.md +110 -0
  22. package/claude-plugin/.claude-plugin/skills/workers.md +88 -0
  23. package/claude-plugin/README.md +54 -0
  24. package/index.js +3 -1
  25. package/package.json +1 -1
  26. package/src/services/express/Express.js +2 -0
  27. package/src/services/express/RedirectResponse.js +9 -0
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "zyket",
3
+ "owner": {
4
+ "name": "PemaK"
5
+ },
6
+ "metadata": {
7
+ "description": "A collection of Claude plugins for building Zyket apps",
8
+ "version": "1.0.8"
9
+ },
10
+ "plugins": [
11
+ {
12
+ "name": "zyket",
13
+ "source": "./claude-plugin"
14
+ }
15
+ ]
16
+ }
@@ -0,0 +1,29 @@
1
+ # Create a Zyket Event
2
+
3
+ Create a new event file in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Events live in `src/events/`. The filename (without `.js`) is the event name used in `emit()`.
8
+
9
+ ### Template
10
+
11
+ ```js
12
+ const { Event } = require("zyket");
13
+
14
+ module.exports = class $EventName$Event extends Event {
15
+ async handle({ container, payload }) {
16
+ container.get("logger").info("$EventName$ event fired", payload);
17
+ // Your event logic here
18
+ }
19
+ };
20
+ ```
21
+
22
+ ### Steps:
23
+ 1. Create `src/events/$event-name$.js`.
24
+ 2. Implement the handler logic based on the user's description.
25
+ 3. Show the user how to emit it:
26
+ ```js
27
+ container.get("events").emitAsync("$event-name$", { ...payload });
28
+ ```
29
+ 4. Remind the user to set `DISABLE_EVENTS=false` in `.env`.
@@ -0,0 +1,37 @@
1
+ # Create a Zyket Socket.IO Guard
2
+
3
+ Create a new Socket.IO guard file in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Guards live in `src/guards/`. The filename (without `.js`) is the guard name used in handler `guards` arrays. Guards run before an event handler or connection and can block execution by throwing an error.
8
+
9
+ ### Template
10
+
11
+ ```js
12
+ const { Guard } = require("zyket");
13
+
14
+ module.exports = class $Name$Guard extends Guard {
15
+ async handle({ container, socket, io }) {
16
+ // Validate / authorize the socket
17
+ // Throw an error to block the event or connection
18
+ // e.g.:
19
+ const token = socket.handshake.auth?.token;
20
+ if (!token) throw new Error("Unauthorized");
21
+
22
+ // Attach data to socket for handlers to use
23
+ // socket.data.user = verifiedUser;
24
+ }
25
+ };
26
+ ```
27
+
28
+ ### Steps:
29
+ 1. Create `src/guards/$name$.js`.
30
+ 2. Implement the authorization logic.
31
+ 3. Show how to attach it to a handler:
32
+ ```js
33
+ module.exports = class MyHandler extends Handler {
34
+ guards = ["$name$"];
35
+ // ...
36
+ };
37
+ ```
@@ -0,0 +1,37 @@
1
+ # Create a Zyket Socket.IO Handler
2
+
3
+ Create a new Socket.IO event handler file in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Handlers live in `src/handlers/`. The filename (without `.js`) is the Socket.IO event name. The special file `connection.js` is the connection handler.
8
+
9
+ ### Event Handler Template
10
+
11
+ ```js
12
+ const { Handler } = require("zyket");
13
+
14
+ module.exports = class $EventName$Handler extends Handler {
15
+ guards = []; // optional: list guard filenames (without .js) to run first
16
+
17
+ async handle({ container, socket, data, io }) {
18
+ container.get("logger").info(`$EventName$ from ${socket.id}`, data);
19
+
20
+ // Your event handling logic here
21
+
22
+ // Return value is sent back via ack callback (if client uses acks)
23
+ return { success: true };
24
+ }
25
+ };
26
+ ```
27
+
28
+ ### Steps:
29
+ 1. Create `src/handlers/$event-name$.js`.
30
+ 2. Add guard names to the `guards` array if authorization is needed.
31
+ 3. Implement the event handling logic.
32
+ 4. Optionally show the client-side code to emit the event:
33
+ ```js
34
+ socket.emit("$event-name$", { ...data }, (response) => {
35
+ console.log(response); // { success: true }
36
+ });
37
+ ```
@@ -0,0 +1,28 @@
1
+ # Create a Zyket Middleware
2
+
3
+ Create a new Express middleware file in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Create a middleware class inside `src/middlewares/`. Middlewares must extend `Middleware` from `zyket` and implement the `handle` method.
8
+
9
+ ### Template
10
+
11
+ ```js
12
+ const { Middleware } = require("zyket");
13
+
14
+ module.exports = class $ClassName$Middleware extends Middleware {
15
+ async handle({ container, request, response, next }) {
16
+ // Your logic here
17
+ // Call next() to allow the request to continue
18
+ // Or return response.status(401).json({ success: false, message: "..." }) to block
19
+ next();
20
+ }
21
+ };
22
+ ```
23
+
24
+ ### Steps:
25
+ 1. Create `src/middlewares/$name$.js` where `$name$` describes the purpose.
26
+ 2. Implement the validation/authentication/transformation logic.
27
+ 3. Call `next()` to pass the request through, or send a response to block.
28
+ 4. Show the user how to attach it to a route.
@@ -0,0 +1,40 @@
1
+ # Create a Zyket Sequelize Model
2
+
3
+ Create a new Sequelize model file in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Models live in `src/models/`. Each file must export a **function** (not a class) that receives `{ sequelize, Sequelize, container }` and returns a Sequelize model instance.
8
+
9
+ ### Template
10
+
11
+ ```js
12
+ const { DataTypes } = require("sequelize");
13
+
14
+ module.exports = ({ sequelize, Sequelize, container }) => {
15
+ const $ModelName$ = sequelize.define("$ModelName$", {
16
+ id: {
17
+ type: DataTypes.INTEGER,
18
+ primaryKey: true,
19
+ autoIncrement: true,
20
+ },
21
+ // Add your fields here
22
+ }, {
23
+ tableName: "$table_name$",
24
+ timestamps: true,
25
+ });
26
+
27
+ $ModelName$.associate = (models) => {
28
+ // Define associations here
29
+ // $ModelName$.belongsTo(models.User, { foreignKey: "userId" });
30
+ };
31
+
32
+ return $ModelName$;
33
+ };
34
+ ```
35
+
36
+ ### Steps:
37
+ 1. Create `src/models/$ModelName$.js`.
38
+ 2. Define all columns based on the user's description.
39
+ 3. Add associations if the model relates to other models.
40
+ 4. Optionally create a migration file in `src/models/migrations/`.
@@ -0,0 +1,42 @@
1
+ # Create a Zyket Route
2
+
3
+ Create a new HTTP route file in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Given a route path or description from the user, create the appropriate file inside `src/routes/` following Zyket's file-based routing conventions.
8
+
9
+ ### File location rules:
10
+ - `/users` → `src/routes/users.js`
11
+ - `/users/:id` → `src/routes/users/[id].js`
12
+ - `/users/:id/posts` → `src/routes/users/[id]/posts.js`
13
+ - `/` (root) → `src/routes/index.js`
14
+
15
+ ### Template
16
+
17
+ ```js
18
+ const { Route } = require("zyket");
19
+
20
+ module.exports = class $ClassName$Route extends Route {
21
+ // Add middlewares if needed:
22
+ // middlewares = {
23
+ // get: [new SomeMiddleware()],
24
+ // post: [new SomeMiddleware()],
25
+ // };
26
+
27
+ async get({ container, request }) {
28
+ return {};
29
+ }
30
+
31
+ async post({ container, request }) {
32
+ return { status: 201 };
33
+ }
34
+ };
35
+ ```
36
+
37
+ ### Steps:
38
+ 1. Determine the correct file path based on the route the user wants.
39
+ 2. Identify which HTTP methods are needed (get, post, put, delete).
40
+ 3. Implement each method based on the user's described functionality.
41
+ 4. Add middlewares if the route needs authentication or validation.
42
+ 5. Use `container.get("database")` to access models, `container.get("cache")` for caching, etc.
@@ -0,0 +1,38 @@
1
+ # Create a Zyket Schedule
2
+
3
+ Create a new cron-based scheduled task in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Schedulers live in `src/schedulers/`. Each file exports a class extending `Schedule` from `zyket`. The `time` property must be a valid `node-cron` expression.
8
+
9
+ ### Template
10
+
11
+ ```js
12
+ const { Schedule } = require("zyket");
13
+
14
+ module.exports = class $Name$Schedule extends Schedule {
15
+ time = "$cron-expression$"; // e.g. "0 * * * *" for every hour
16
+
17
+ async handle({ container }) {
18
+ container.get("logger").info("Running $Name$ schedule");
19
+ // Your scheduled logic here
20
+ }
21
+ };
22
+ ```
23
+
24
+ ### Common cron expressions
25
+
26
+ | Pattern | Meaning |
27
+ |---|---|
28
+ | `* * * * *` | Every minute |
29
+ | `0 * * * *` | Every hour |
30
+ | `0 0 * * *` | Every day at midnight |
31
+ | `0 9 * * 1` | Every Monday at 9:00 |
32
+ | `*/5 * * * *` | Every 5 minutes |
33
+
34
+ ### Steps:
35
+ 1. Create `src/schedulers/$name$.js`.
36
+ 2. Set `time` to the appropriate cron expression.
37
+ 3. Implement the recurring task logic.
38
+ 4. Remind the user to set `DISABLE_SCHEDULER=false` in `.env`.
@@ -0,0 +1,59 @@
1
+ # Create a Zyket Custom Service
2
+
3
+ Create a new custom service in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Custom services extend the `Service` base class and are registered in the `Kernel` constructor. They are booted once at startup and accessible anywhere via `container.get("serviceName")`.
8
+
9
+ ### Template
10
+
11
+ ```js
12
+ // src/services/$name$.js
13
+ const { Service } = require("zyket");
14
+
15
+ module.exports = class $Name$Service extends Service {
16
+ #container;
17
+
18
+ constructor(container) {
19
+ super("$name$"); // Must match the registration name
20
+ this.#container = container;
21
+ }
22
+
23
+ async boot() {
24
+ // Initialize any connections, clients, etc.
25
+ this.#container.get("logger").info("$Name$Service booted");
26
+ }
27
+
28
+ // Add your service methods here
29
+ };
30
+ ```
31
+
32
+ ### Registration
33
+
34
+ ```js
35
+ // index.js
36
+ const { Kernel } = require("zyket");
37
+ const $Name$Service = require("./src/services/$name$");
38
+
39
+ const kernel = new Kernel({
40
+ services: [
41
+ ["$name$", $Name$Service, ["@service_container"]],
42
+ ],
43
+ });
44
+
45
+ kernel.boot();
46
+ ```
47
+
48
+ ### Usage
49
+
50
+ ```js
51
+ const service = container.get("$name$");
52
+ ```
53
+
54
+ ### Steps:
55
+ 1. Create `src/services/$name$.js`.
56
+ 2. Implement the `boot()` method for initialization.
57
+ 3. Add the service methods.
58
+ 4. Register it in `index.js` with a unique name.
59
+ 5. Use `"@service_container"` in the args array to inject the DI container.
@@ -0,0 +1,39 @@
1
+ # Create a Zyket BullMQ Worker
2
+
3
+ Create a new BullMQ worker file in the Zyket project.
4
+
5
+ ## Instructions
6
+
7
+ Workers live in `src/workers/`. Each file must export a class extending `Worker` from `zyket`.
8
+
9
+ ### Template
10
+
11
+ ```js
12
+ const { Worker } = require("zyket");
13
+
14
+ module.exports = class $WorkerName$Worker extends Worker {
15
+ queueName = "$queue-name$"; // Must match a name in the QUEUES env var
16
+
17
+ async handle({ container, job }) {
18
+ const data = job.data;
19
+ container.get("logger").info(`Processing job ${job.id}`, data);
20
+
21
+ // Your job logic here
22
+
23
+ return { success: true };
24
+ }
25
+ };
26
+ ```
27
+
28
+ ### Steps:
29
+ 1. Create `src/workers/$worker-name$.js`.
30
+ 2. Set `queueName` to the appropriate queue name.
31
+ 3. Implement the job processing logic.
32
+ 4. Remind the user to:
33
+ - Add `DISABLE_BULLMQ=false` to `.env`
34
+ - Add the queue name to `QUEUES` in `.env` (e.g. `QUEUES=emails,notifications`)
35
+ - Set `CACHE_URL` in `.env`
36
+ 5. Show how to dispatch a job:
37
+ ```js
38
+ await container.get("queues").addJob("$queue-name$", "job-name", { ...data });
39
+ ```
@@ -0,0 +1,133 @@
1
+ {
2
+ "name": "zyket",
3
+ "description": "Comprehensive skills for building Zyket backends.",
4
+ "version": "1.0.8",
5
+ "author": {
6
+ "name": "PemaK"
7
+ },
8
+ "homepage": "https://zyket.com",
9
+ "repository": "https://github.com/PemaK/zyket-claude",
10
+ "keywords": [
11
+ "zyket",
12
+ "backend",
13
+ "admin",
14
+ "node.js",
15
+ "headless",
16
+ "api",
17
+ "database",
18
+ "authentication",
19
+ "authorization",
20
+ "file management",
21
+ "email",
22
+ "notifications",
23
+ "analytics",
24
+ "logging",
25
+ "testing",
26
+ "deployment",
27
+ "security"
28
+ ],
29
+ "skills": [
30
+ {
31
+ "name": "zyket-overview",
32
+ "description": "Overview of the Zyket framework, its architecture and project structure",
33
+ "file": "skills/overview.md"
34
+ },
35
+ {
36
+ "name": "zyket-routes",
37
+ "description": "How to create and configure Express HTTP routes in Zyket",
38
+ "file": "skills/routes.md"
39
+ },
40
+ {
41
+ "name": "zyket-middlewares",
42
+ "description": "How to create Express middlewares in Zyket",
43
+ "file": "skills/middlewares.md"
44
+ },
45
+ {
46
+ "name": "zyket-database",
47
+ "description": "How to define Sequelize models and run database migrations in Zyket",
48
+ "file": "skills/database.md"
49
+ },
50
+ {
51
+ "name": "zyket-events",
52
+ "description": "How to create and emit events in Zyket",
53
+ "file": "skills/events.md"
54
+ },
55
+ {
56
+ "name": "zyket-workers",
57
+ "description": "How to create BullMQ workers and manage job queues in Zyket",
58
+ "file": "skills/workers.md"
59
+ },
60
+ {
61
+ "name": "zyket-scheduler",
62
+ "description": "How to create cron-based scheduled tasks in Zyket",
63
+ "file": "skills/scheduler.md"
64
+ },
65
+ {
66
+ "name": "zyket-socketio",
67
+ "description": "How to create Socket.IO handlers and guards in Zyket",
68
+ "file": "skills/socketio.md"
69
+ },
70
+ {
71
+ "name": "zyket-auth",
72
+ "description": "How to set up authentication using better-auth in Zyket",
73
+ "file": "skills/auth.md"
74
+ },
75
+ {
76
+ "name": "zyket-services",
77
+ "description": "How to use built-in services (cache, S3, logger) and create custom services in Zyket",
78
+ "file": "skills/services.md"
79
+ },
80
+ {
81
+ "name": "zyket-extensions",
82
+ "description": "How to create and use extensions in Zyket",
83
+ "file": "skills/extensions.md"
84
+ }
85
+ ],
86
+ "commands": [
87
+ {
88
+ "name": "route",
89
+ "description": "Create a new HTTP route",
90
+ "file": "commands/route.md"
91
+ },
92
+ {
93
+ "name": "middleware",
94
+ "description": "Create a new Express middleware",
95
+ "file": "commands/middleware.md"
96
+ },
97
+ {
98
+ "name": "model",
99
+ "description": "Create a new Sequelize model",
100
+ "file": "commands/model.md"
101
+ },
102
+ {
103
+ "name": "event",
104
+ "description": "Create a new event",
105
+ "file": "commands/event.md"
106
+ },
107
+ {
108
+ "name": "worker",
109
+ "description": "Create a new BullMQ worker",
110
+ "file": "commands/worker.md"
111
+ },
112
+ {
113
+ "name": "schedule",
114
+ "description": "Create a new cron schedule",
115
+ "file": "commands/schedule.md"
116
+ },
117
+ {
118
+ "name": "handler",
119
+ "description": "Create a new Socket.IO event handler",
120
+ "file": "commands/handler.md"
121
+ },
122
+ {
123
+ "name": "guard",
124
+ "description": "Create a new Socket.IO guard",
125
+ "file": "commands/guard.md"
126
+ },
127
+ {
128
+ "name": "service",
129
+ "description": "Create a new custom service",
130
+ "file": "commands/service.md"
131
+ }
132
+ ]
133
+ }
@@ -0,0 +1,128 @@
1
+ # Zyket – Authentication (better-auth)
2
+
3
+ Zyket uses [better-auth](https://better-auth.com) for authentication. It only supports **PostgreSQL** as the database dialect.
4
+
5
+ ## Requirements
6
+
7
+ ```env
8
+ DATABASE_URL=postgresql://user:password@localhost:5432/mydb
9
+ DATABASE_DIALECT=postgresql
10
+ CACHE_URL=redis://localhost:6379 # required for session secondary storage
11
+ ```
12
+
13
+ ## Creating an Auth Service
14
+
15
+ Create a custom service that extends `AuthService`:
16
+
17
+ ```js
18
+ // src/services/auth.js
19
+ const { AuthService } = require("zyket");
20
+
21
+ module.exports = class MyAuth extends AuthService {
22
+ // Add extra better-auth plugins
23
+ get plugins() {
24
+ return [];
25
+ }
26
+
27
+ // Add social providers (Google, GitHub, etc.)
28
+ get socialProviders() {
29
+ return {
30
+ google: {
31
+ clientId: process.env.GOOGLE_CLIENT_ID,
32
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
33
+ },
34
+ };
35
+ }
36
+
37
+ // Extra fields on the user table
38
+ get userAdditionalFields() {
39
+ return {
40
+ role: {
41
+ type: "string",
42
+ defaultValue: "user",
43
+ input: false, // cannot be set by user on sign-up
44
+ },
45
+ };
46
+ }
47
+
48
+ // Email hooks (implement or throw to disable)
49
+ async sendResetPasswordEmail({ user, url, token }, request) {
50
+ // Send email with the reset URL
51
+ }
52
+
53
+ async sendVerificationEmail({ user, url, token }, request) {
54
+ // Send email with the verification URL
55
+ }
56
+
57
+ async sendInvitationEmail(data) {
58
+ // Send org invitation email
59
+ }
60
+
61
+ async allowUserToCreateOrganization(user) {
62
+ return user.role === "admin"; // only admins can create orgs
63
+ }
64
+ };
65
+ ```
66
+
67
+ ## Registering the Auth Service
68
+
69
+ ```js
70
+ // index.js
71
+ const { Kernel } = require("zyket");
72
+ const MyAuth = require("./src/services/auth");
73
+
74
+ const kernel = new Kernel({
75
+ services: [
76
+ ["auth", MyAuth, ["@service_container"]],
77
+ ],
78
+ });
79
+
80
+ kernel.boot();
81
+ ```
82
+
83
+ ## Endpoints Provided
84
+
85
+ All better-auth REST endpoints are mounted at `/api/auth/*`. This includes:
86
+
87
+ - `POST /api/auth/sign-up/email`
88
+ - `POST /api/auth/sign-in/email`
89
+ - `POST /api/auth/sign-out`
90
+ - `POST /api/auth/forget-password`
91
+ - `POST /api/auth/reset-password`
92
+ - `GET /api/auth/session`
93
+ - `GET /api/auth/verify-email`
94
+ - Social provider OAuth flows (`/api/auth/sign-in/:provider`)
95
+ - Admin routes (`/api/auth/admin/...`)
96
+ - Organization routes (`/api/auth/organization/...`)
97
+
98
+ ## Verifying Sessions in Routes
99
+
100
+ Use the `auth` property on the service or use `better-auth/node` token utilities:
101
+
102
+ ```js
103
+ // src/middlewares/auth.js
104
+ const { Middleware } = require("zyket");
105
+
106
+ module.exports = class AuthMiddleware extends Middleware {
107
+ async handle({ container, request, response, next }) {
108
+ const auth = container.get("auth").client;
109
+ const session = await auth.api.getSession({ headers: request.headers });
110
+ if (!session) {
111
+ return response.status(401).json({ success: false, message: "Unauthorized" });
112
+ }
113
+ request.user = session.user;
114
+ next();
115
+ }
116
+ };
117
+ ```
118
+
119
+ ## Built-in Plugins Included
120
+
121
+ The base `AuthService` always includes:
122
+ - `admin` – admin panel routes + `banUser`, `unbanUser`, `listUsers`, etc.
123
+ - `bearer` – Bearer token support (for API use)
124
+ - `organization` – multi-tenancy / organisations
125
+
126
+ ## Cookie Configuration
127
+
128
+ Cookies are configured for cross-subdomain, `SameSite=none`, `Secure=true` by default (suitable for separate frontend/backend domains).