@donkeylabs/cli 2.0.14 → 2.0.16
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/package.json +1 -1
- package/src/commands/config.ts +610 -0
- package/src/commands/deploy-enhanced.ts +354 -0
- package/src/commands/deploy.ts +204 -0
- package/src/commands/generate.ts +11 -13
- package/src/commands/init-enhanced.ts +1994 -0
- package/src/deployment/manager.ts +356 -0
- package/src/index.ts +47 -19
- package/templates/starter/.env.example +0 -44
- package/templates/starter/.gitignore.template +0 -4
- package/templates/starter/donkeylabs.config.ts +0 -6
- package/templates/starter/package.json +0 -21
- package/templates/starter/src/index.ts +0 -54
- package/templates/starter/src/plugins/stats/index.ts +0 -105
- package/templates/starter/src/routes/health/handlers/ping.ts +0 -22
- package/templates/starter/src/routes/health/index.ts +0 -19
- package/templates/starter/tsconfig.json +0 -27
- package/templates/sveltekit-app/.env.example +0 -59
- package/templates/sveltekit-app/README.md +0 -103
- package/templates/sveltekit-app/bun.lock +0 -683
- package/templates/sveltekit-app/donkeylabs.config.ts +0 -12
- package/templates/sveltekit-app/package.json +0 -38
- package/templates/sveltekit-app/src/app.css +0 -40
- package/templates/sveltekit-app/src/app.html +0 -12
- package/templates/sveltekit-app/src/hooks.server.ts +0 -4
- package/templates/sveltekit-app/src/lib/components/ui/badge/badge.svelte +0 -30
- package/templates/sveltekit-app/src/lib/components/ui/badge/index.ts +0 -3
- package/templates/sveltekit-app/src/lib/components/ui/button/button.svelte +0 -48
- package/templates/sveltekit-app/src/lib/components/ui/button/index.ts +0 -9
- package/templates/sveltekit-app/src/lib/components/ui/card/card-content.svelte +0 -18
- package/templates/sveltekit-app/src/lib/components/ui/card/card-description.svelte +0 -18
- package/templates/sveltekit-app/src/lib/components/ui/card/card-footer.svelte +0 -18
- package/templates/sveltekit-app/src/lib/components/ui/card/card-header.svelte +0 -18
- package/templates/sveltekit-app/src/lib/components/ui/card/card-title.svelte +0 -18
- package/templates/sveltekit-app/src/lib/components/ui/card/card.svelte +0 -21
- package/templates/sveltekit-app/src/lib/components/ui/card/index.ts +0 -21
- package/templates/sveltekit-app/src/lib/components/ui/index.ts +0 -4
- package/templates/sveltekit-app/src/lib/components/ui/input/index.ts +0 -2
- package/templates/sveltekit-app/src/lib/components/ui/input/input.svelte +0 -20
- package/templates/sveltekit-app/src/lib/permissions.ts +0 -213
- package/templates/sveltekit-app/src/lib/utils/index.ts +0 -6
- package/templates/sveltekit-app/src/routes/+layout.svelte +0 -8
- package/templates/sveltekit-app/src/routes/+page.server.ts +0 -25
- package/templates/sveltekit-app/src/routes/+page.svelte +0 -680
- package/templates/sveltekit-app/src/routes/workflows/+page.server.ts +0 -23
- package/templates/sveltekit-app/src/routes/workflows/+page.svelte +0 -522
- package/templates/sveltekit-app/src/server/events.ts +0 -28
- package/templates/sveltekit-app/src/server/index.ts +0 -124
- package/templates/sveltekit-app/src/server/plugins/auth/auth.test.ts +0 -377
- package/templates/sveltekit-app/src/server/plugins/auth/index.ts +0 -815
- package/templates/sveltekit-app/src/server/plugins/auth/migrations/001_create_users.ts +0 -25
- package/templates/sveltekit-app/src/server/plugins/auth/migrations/002_create_sessions.ts +0 -32
- package/templates/sveltekit-app/src/server/plugins/auth/migrations/003_create_refresh_tokens.ts +0 -33
- package/templates/sveltekit-app/src/server/plugins/auth/migrations/004_create_passkeys.ts +0 -60
- package/templates/sveltekit-app/src/server/plugins/auth/schema.ts +0 -65
- package/templates/sveltekit-app/src/server/plugins/demo/index.ts +0 -262
- package/templates/sveltekit-app/src/server/plugins/email/email.test.ts +0 -369
- package/templates/sveltekit-app/src/server/plugins/email/index.ts +0 -411
- package/templates/sveltekit-app/src/server/plugins/email/migrations/001_create_email_tokens.ts +0 -33
- package/templates/sveltekit-app/src/server/plugins/email/schema.ts +0 -24
- package/templates/sveltekit-app/src/server/plugins/permissions/index.ts +0 -1048
- package/templates/sveltekit-app/src/server/plugins/permissions/migrations/001_create_tenants.ts +0 -63
- package/templates/sveltekit-app/src/server/plugins/permissions/migrations/002_create_roles.ts +0 -90
- package/templates/sveltekit-app/src/server/plugins/permissions/migrations/003_create_resource_grants.ts +0 -50
- package/templates/sveltekit-app/src/server/plugins/permissions/permissions.test.ts +0 -566
- package/templates/sveltekit-app/src/server/plugins/permissions/schema.ts +0 -67
- package/templates/sveltekit-app/src/server/plugins/workflow-demo/index.ts +0 -198
- package/templates/sveltekit-app/src/server/routes/auth/auth.schemas.ts +0 -66
- package/templates/sveltekit-app/src/server/routes/auth/handlers/login.handler.ts +0 -18
- package/templates/sveltekit-app/src/server/routes/auth/handlers/logout.handler.ts +0 -16
- package/templates/sveltekit-app/src/server/routes/auth/handlers/me.handler.ts +0 -20
- package/templates/sveltekit-app/src/server/routes/auth/handlers/refresh.handler.ts +0 -17
- package/templates/sveltekit-app/src/server/routes/auth/handlers/register.handler.ts +0 -19
- package/templates/sveltekit-app/src/server/routes/auth/handlers/update-profile.handler.ts +0 -21
- package/templates/sveltekit-app/src/server/routes/auth/index.ts +0 -73
- package/templates/sveltekit-app/src/server/routes/demo.ts +0 -464
- package/templates/sveltekit-app/src/server/routes/example/example.schemas.ts +0 -22
- package/templates/sveltekit-app/src/server/routes/example/handlers/greet.handler.ts +0 -21
- package/templates/sveltekit-app/src/server/routes/example/index.ts +0 -28
- package/templates/sveltekit-app/src/server/routes/permissions/index.ts +0 -248
- package/templates/sveltekit-app/src/server/routes/tenants/index.ts +0 -339
- package/templates/sveltekit-app/static/robots.txt +0 -3
- package/templates/sveltekit-app/svelte.config.ts +0 -17
- package/templates/sveltekit-app/tsconfig.json +0 -20
- package/templates/sveltekit-app/vite.config.ts +0 -12
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { Kysely } from "kysely";
|
|
2
|
-
|
|
3
|
-
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
-
await db.schema
|
|
5
|
-
.createTable("users")
|
|
6
|
-
.ifNotExists()
|
|
7
|
-
.addColumn("id", "text", (col) => col.primaryKey())
|
|
8
|
-
.addColumn("email", "text", (col) => col.notNull().unique())
|
|
9
|
-
.addColumn("password_hash", "text", (col) => col.notNull())
|
|
10
|
-
.addColumn("name", "text")
|
|
11
|
-
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
12
|
-
.addColumn("updated_at", "text", (col) => col.notNull())
|
|
13
|
-
.execute();
|
|
14
|
-
|
|
15
|
-
await db.schema
|
|
16
|
-
.createIndex("idx_users_email")
|
|
17
|
-
.ifNotExists()
|
|
18
|
-
.on("users")
|
|
19
|
-
.column("email")
|
|
20
|
-
.execute();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function down(db: Kysely<any>): Promise<void> {
|
|
24
|
-
await db.schema.dropTable("users").ifExists().execute();
|
|
25
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { Kysely } from "kysely";
|
|
2
|
-
|
|
3
|
-
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
-
await db.schema
|
|
5
|
-
.createTable("sessions")
|
|
6
|
-
.ifNotExists()
|
|
7
|
-
.addColumn("id", "text", (col) => col.primaryKey())
|
|
8
|
-
.addColumn("user_id", "text", (col) =>
|
|
9
|
-
col.notNull().references("users.id").onDelete("cascade")
|
|
10
|
-
)
|
|
11
|
-
.addColumn("expires_at", "text", (col) => col.notNull())
|
|
12
|
-
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
13
|
-
.execute();
|
|
14
|
-
|
|
15
|
-
await db.schema
|
|
16
|
-
.createIndex("idx_sessions_user_id")
|
|
17
|
-
.ifNotExists()
|
|
18
|
-
.on("sessions")
|
|
19
|
-
.column("user_id")
|
|
20
|
-
.execute();
|
|
21
|
-
|
|
22
|
-
await db.schema
|
|
23
|
-
.createIndex("idx_sessions_expires_at")
|
|
24
|
-
.ifNotExists()
|
|
25
|
-
.on("sessions")
|
|
26
|
-
.column("expires_at")
|
|
27
|
-
.execute();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export async function down(db: Kysely<any>): Promise<void> {
|
|
31
|
-
await db.schema.dropTable("sessions").ifExists().execute();
|
|
32
|
-
}
|
package/templates/sveltekit-app/src/server/plugins/auth/migrations/003_create_refresh_tokens.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { Kysely } from "kysely";
|
|
2
|
-
|
|
3
|
-
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
-
await db.schema
|
|
5
|
-
.createTable("refresh_tokens")
|
|
6
|
-
.ifNotExists()
|
|
7
|
-
.addColumn("id", "text", (col) => col.primaryKey())
|
|
8
|
-
.addColumn("user_id", "text", (col) =>
|
|
9
|
-
col.notNull().references("users.id").onDelete("cascade")
|
|
10
|
-
)
|
|
11
|
-
.addColumn("token_hash", "text", (col) => col.notNull())
|
|
12
|
-
.addColumn("expires_at", "text", (col) => col.notNull())
|
|
13
|
-
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
14
|
-
.execute();
|
|
15
|
-
|
|
16
|
-
await db.schema
|
|
17
|
-
.createIndex("idx_refresh_tokens_user_id")
|
|
18
|
-
.ifNotExists()
|
|
19
|
-
.on("refresh_tokens")
|
|
20
|
-
.column("user_id")
|
|
21
|
-
.execute();
|
|
22
|
-
|
|
23
|
-
await db.schema
|
|
24
|
-
.createIndex("idx_refresh_tokens_expires_at")
|
|
25
|
-
.ifNotExists()
|
|
26
|
-
.on("refresh_tokens")
|
|
27
|
-
.column("expires_at")
|
|
28
|
-
.execute();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export async function down(db: Kysely<any>): Promise<void> {
|
|
32
|
-
await db.schema.dropTable("refresh_tokens").ifExists().execute();
|
|
33
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import type { Kysely } from "kysely";
|
|
2
|
-
|
|
3
|
-
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
-
// Passkey credentials (WebAuthn)
|
|
5
|
-
await db.schema
|
|
6
|
-
.createTable("passkeys")
|
|
7
|
-
.ifNotExists()
|
|
8
|
-
.addColumn("id", "text", (col) => col.primaryKey())
|
|
9
|
-
.addColumn("user_id", "text", (col) =>
|
|
10
|
-
col.notNull().references("users.id").onDelete("cascade")
|
|
11
|
-
)
|
|
12
|
-
.addColumn("credential_id", "text", (col) => col.notNull().unique())
|
|
13
|
-
.addColumn("public_key", "text", (col) => col.notNull()) // Base64 encoded
|
|
14
|
-
.addColumn("counter", "integer", (col) => col.notNull().defaultTo(0))
|
|
15
|
-
.addColumn("device_type", "text") // platform, cross-platform
|
|
16
|
-
.addColumn("backed_up", "integer", (col) => col.notNull().defaultTo(0))
|
|
17
|
-
.addColumn("transports", "text") // JSON array
|
|
18
|
-
.addColumn("name", "text") // User-friendly name
|
|
19
|
-
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
20
|
-
.addColumn("last_used_at", "text")
|
|
21
|
-
.execute();
|
|
22
|
-
|
|
23
|
-
await db.schema
|
|
24
|
-
.createIndex("idx_passkeys_user_id")
|
|
25
|
-
.ifNotExists()
|
|
26
|
-
.on("passkeys")
|
|
27
|
-
.column("user_id")
|
|
28
|
-
.execute();
|
|
29
|
-
|
|
30
|
-
await db.schema
|
|
31
|
-
.createIndex("idx_passkeys_credential_id")
|
|
32
|
-
.ifNotExists()
|
|
33
|
-
.on("passkeys")
|
|
34
|
-
.column("credential_id")
|
|
35
|
-
.execute();
|
|
36
|
-
|
|
37
|
-
// Passkey challenges (temporary storage)
|
|
38
|
-
await db.schema
|
|
39
|
-
.createTable("passkey_challenges")
|
|
40
|
-
.ifNotExists()
|
|
41
|
-
.addColumn("id", "text", (col) => col.primaryKey())
|
|
42
|
-
.addColumn("challenge", "text", (col) => col.notNull())
|
|
43
|
-
.addColumn("user_id", "text") // Null for registration
|
|
44
|
-
.addColumn("type", "text", (col) => col.notNull()) // registration, authentication
|
|
45
|
-
.addColumn("expires_at", "text", (col) => col.notNull())
|
|
46
|
-
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
47
|
-
.execute();
|
|
48
|
-
|
|
49
|
-
await db.schema
|
|
50
|
-
.createIndex("idx_passkey_challenges_expires_at")
|
|
51
|
-
.ifNotExists()
|
|
52
|
-
.on("passkey_challenges")
|
|
53
|
-
.column("expires_at")
|
|
54
|
-
.execute();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export async function down(db: Kysely<any>): Promise<void> {
|
|
58
|
-
await db.schema.dropTable("passkey_challenges").ifExists().execute();
|
|
59
|
-
await db.schema.dropTable("passkeys").ifExists().execute();
|
|
60
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file was generated by kysely-codegen.
|
|
3
|
-
* Please do not edit it manually.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ColumnType } from "kysely";
|
|
7
|
-
|
|
8
|
-
export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
|
|
9
|
-
? ColumnType<S, I | undefined, U>
|
|
10
|
-
: ColumnType<T, T | undefined, T>;
|
|
11
|
-
|
|
12
|
-
export interface PasskeyChallenges {
|
|
13
|
-
challenge: string;
|
|
14
|
-
created_at: Generated<string>;
|
|
15
|
-
expires_at: string;
|
|
16
|
-
id: string | null;
|
|
17
|
-
type: string;
|
|
18
|
-
user_id: string | null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface Passkeys {
|
|
22
|
-
backed_up: Generated<number>;
|
|
23
|
-
counter: Generated<number>;
|
|
24
|
-
created_at: Generated<string>;
|
|
25
|
-
credential_id: string;
|
|
26
|
-
device_type: string | null;
|
|
27
|
-
id: string | null;
|
|
28
|
-
last_used_at: string | null;
|
|
29
|
-
name: string | null;
|
|
30
|
-
public_key: string;
|
|
31
|
-
transports: string | null;
|
|
32
|
-
user_id: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface RefreshTokens {
|
|
36
|
-
created_at: Generated<string>;
|
|
37
|
-
expires_at: string;
|
|
38
|
-
id: string | null;
|
|
39
|
-
token_hash: string;
|
|
40
|
-
user_id: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface Sessions {
|
|
44
|
-
created_at: Generated<string>;
|
|
45
|
-
expires_at: string;
|
|
46
|
-
id: string | null;
|
|
47
|
-
user_id: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface Users {
|
|
51
|
-
created_at: Generated<string>;
|
|
52
|
-
email: string;
|
|
53
|
-
id: string | null;
|
|
54
|
-
name: string | null;
|
|
55
|
-
password_hash: string;
|
|
56
|
-
updated_at: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface DB {
|
|
60
|
-
passkey_challenges: PasskeyChallenges;
|
|
61
|
-
passkeys: Passkeys;
|
|
62
|
-
refresh_tokens: RefreshTokens;
|
|
63
|
-
sessions: Sessions;
|
|
64
|
-
users: Users;
|
|
65
|
-
}
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
// Demo plugin with all core service integrations
|
|
2
|
-
import { createPlugin } from "@donkeylabs/server";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// Random event messages for SSE demo
|
|
6
|
-
const eventMessages = [
|
|
7
|
-
"User logged in",
|
|
8
|
-
"New order placed",
|
|
9
|
-
"Payment received",
|
|
10
|
-
"Item shipped",
|
|
11
|
-
"Review submitted",
|
|
12
|
-
"Comment added",
|
|
13
|
-
"File uploaded",
|
|
14
|
-
"Task completed",
|
|
15
|
-
"Alert triggered",
|
|
16
|
-
"Sync finished",
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export const demoPlugin = createPlugin.define({
|
|
21
|
-
name: "demo",
|
|
22
|
-
service: async (ctx) => {
|
|
23
|
-
let counter = 0;
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
// Counter
|
|
27
|
-
getCounter: () => counter,
|
|
28
|
-
increment: () => ++counter,
|
|
29
|
-
decrement: () => --counter,
|
|
30
|
-
reset: () => { counter = 0; return counter; },
|
|
31
|
-
|
|
32
|
-
// Cache helpers
|
|
33
|
-
cacheSet: async (key: string, value: any, ttl?: number) => {
|
|
34
|
-
await ctx.core.cache.set(key, value, ttl);
|
|
35
|
-
return { success: true };
|
|
36
|
-
},
|
|
37
|
-
cacheGet: async (key: string) => {
|
|
38
|
-
const value = await ctx.core.cache.get(key);
|
|
39
|
-
const exists = await ctx.core.cache.has(key);
|
|
40
|
-
return { value, exists };
|
|
41
|
-
},
|
|
42
|
-
cacheDelete: async (key: string) => {
|
|
43
|
-
await ctx.core.cache.delete(key);
|
|
44
|
-
return { success: true };
|
|
45
|
-
},
|
|
46
|
-
cacheKeys: async () => {
|
|
47
|
-
const keys = await ctx.core.cache.keys();
|
|
48
|
-
return { keys, size: keys.length };
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
// Jobs helpers
|
|
52
|
-
enqueueJob: async (name: string, data: any, delay?: number) => {
|
|
53
|
-
let jobId: string;
|
|
54
|
-
if (delay && delay > 0) {
|
|
55
|
-
const runAt = new Date(Date.now() + delay);
|
|
56
|
-
jobId = await ctx.core.jobs.schedule(name, data, runAt);
|
|
57
|
-
} else {
|
|
58
|
-
jobId = await ctx.core.jobs.enqueue(name, data);
|
|
59
|
-
}
|
|
60
|
-
return { jobId };
|
|
61
|
-
},
|
|
62
|
-
getJobStats: async () => {
|
|
63
|
-
const pending = await ctx.core.jobs.getByName("demo-job", "pending");
|
|
64
|
-
const running = await ctx.core.jobs.getByName("demo-job", "running");
|
|
65
|
-
const completed = await ctx.core.jobs.getByName("demo-job", "completed");
|
|
66
|
-
return {
|
|
67
|
-
pending: pending.length,
|
|
68
|
-
running: running.length,
|
|
69
|
-
completed: completed.length,
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
// Cron helpers
|
|
74
|
-
getCronTasks: () => ctx.core.cron.list().map(t => ({
|
|
75
|
-
id: t.id,
|
|
76
|
-
name: t.name,
|
|
77
|
-
expression: t.expression,
|
|
78
|
-
enabled: t.enabled,
|
|
79
|
-
lastRun: t.lastRun?.toISOString(),
|
|
80
|
-
nextRun: t.nextRun?.toISOString(),
|
|
81
|
-
})),
|
|
82
|
-
|
|
83
|
-
// Rate limiter helpers
|
|
84
|
-
checkRateLimit: async (key: string, limit: number, window: number) => {
|
|
85
|
-
return ctx.core.rateLimiter.check(key, limit, window);
|
|
86
|
-
},
|
|
87
|
-
resetRateLimit: async (key: string) => {
|
|
88
|
-
await ctx.core.rateLimiter.reset(key);
|
|
89
|
-
return { success: true };
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
// Events helpers (internal pub/sub)
|
|
93
|
-
emitEvent: async (event: string, data: any) => {
|
|
94
|
-
await ctx.core.events.emit(event, data);
|
|
95
|
-
return { success: true };
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
// SSE broadcast
|
|
99
|
-
broadcast: (channel: string, event: string, data: any) => {
|
|
100
|
-
ctx.core.sse.broadcast(channel, event, data);
|
|
101
|
-
return { success: true };
|
|
102
|
-
},
|
|
103
|
-
getSSEClients: () => ({
|
|
104
|
-
total: ctx.core.sse.getClients().length,
|
|
105
|
-
byChannel: ctx.core.sse.getClientsByChannel("events").length,
|
|
106
|
-
}),
|
|
107
|
-
|
|
108
|
-
// Audit helpers - compliance and tracking
|
|
109
|
-
auditLog: async (action: string, resource: string, resourceId?: string, metadata?: Record<string, any>) => {
|
|
110
|
-
const id = await ctx.core.audit.log({
|
|
111
|
-
action,
|
|
112
|
-
actor: "demo-user", // In real apps, get from auth context
|
|
113
|
-
resource,
|
|
114
|
-
resourceId,
|
|
115
|
-
metadata,
|
|
116
|
-
});
|
|
117
|
-
return { id };
|
|
118
|
-
},
|
|
119
|
-
auditQuery: async (filters: { action?: string; resource?: string; limit?: number }) => {
|
|
120
|
-
const entries = await ctx.core.audit.query({
|
|
121
|
-
action: filters.action,
|
|
122
|
-
resource: filters.resource,
|
|
123
|
-
limit: filters.limit ?? 10,
|
|
124
|
-
});
|
|
125
|
-
return {
|
|
126
|
-
entries: entries.map(e => ({
|
|
127
|
-
id: e.id,
|
|
128
|
-
timestamp: e.timestamp.toISOString(),
|
|
129
|
-
action: e.action,
|
|
130
|
-
actor: e.actor,
|
|
131
|
-
resource: e.resource,
|
|
132
|
-
resourceId: e.resourceId,
|
|
133
|
-
metadata: e.metadata,
|
|
134
|
-
})),
|
|
135
|
-
};
|
|
136
|
-
},
|
|
137
|
-
auditGetByResource: async (resource: string, resourceId: string) => {
|
|
138
|
-
const entries = await ctx.core.audit.getByResource(resource, resourceId);
|
|
139
|
-
return {
|
|
140
|
-
entries: entries.map(e => ({
|
|
141
|
-
id: e.id,
|
|
142
|
-
timestamp: e.timestamp.toISOString(),
|
|
143
|
-
action: e.action,
|
|
144
|
-
actor: e.actor,
|
|
145
|
-
metadata: e.metadata,
|
|
146
|
-
})),
|
|
147
|
-
};
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
// WebSocket helpers - bidirectional real-time communication
|
|
151
|
-
wsBroadcast: (channel: string, event: string, data: any) => {
|
|
152
|
-
ctx.core.websocket.broadcast(channel, event, data);
|
|
153
|
-
return { success: true };
|
|
154
|
-
},
|
|
155
|
-
wsBroadcastAll: (event: string, data: any) => {
|
|
156
|
-
ctx.core.websocket.broadcastAll(event, data);
|
|
157
|
-
return { success: true };
|
|
158
|
-
},
|
|
159
|
-
wsGetClients: (channel?: string) => {
|
|
160
|
-
const allClients = ctx.core.websocket.getClients();
|
|
161
|
-
// Filter by channel if provided
|
|
162
|
-
const clients = channel
|
|
163
|
-
? allClients.filter((c) => c.channels.includes(channel))
|
|
164
|
-
: allClients;
|
|
165
|
-
return {
|
|
166
|
-
count: clients.length,
|
|
167
|
-
clients,
|
|
168
|
-
};
|
|
169
|
-
},
|
|
170
|
-
wsGetClientCount: (channel?: string) => {
|
|
171
|
-
return { count: ctx.core.websocket.getClientCount(channel) };
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
},
|
|
175
|
-
init: async (ctx) => {
|
|
176
|
-
// Register job handler for demo
|
|
177
|
-
ctx.core.jobs.register("demo-job", async (data) => {
|
|
178
|
-
ctx.core.logger.info("Demo job executed", { data });
|
|
179
|
-
// Broadcast job completion via SSE
|
|
180
|
-
ctx.core.sse.broadcast("events", "job-completed", {
|
|
181
|
-
id: Date.now(),
|
|
182
|
-
message: `Job completed: ${data.message || "No message"}`,
|
|
183
|
-
timestamp: new Date().toISOString(),
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// Schedule cron job to broadcast SSE events every 5 seconds
|
|
188
|
-
ctx.core.cron.schedule("*/5 * * * * *", () => {
|
|
189
|
-
const message = eventMessages[Math.floor(Math.random() * eventMessages.length)];
|
|
190
|
-
ctx.core.sse.broadcast("events", "cron-event", {
|
|
191
|
-
id: Date.now(),
|
|
192
|
-
message,
|
|
193
|
-
timestamp: new Date().toISOString(),
|
|
194
|
-
source: "cron",
|
|
195
|
-
});
|
|
196
|
-
}, { name: "sse-broadcaster" });
|
|
197
|
-
|
|
198
|
-
// Listen for internal events and broadcast to SSE
|
|
199
|
-
ctx.core.events.on("demo.*", (data) => {
|
|
200
|
-
ctx.core.sse.broadcast("events", "internal-event", {
|
|
201
|
-
id: Date.now(),
|
|
202
|
-
message: `Internal event: ${JSON.stringify(data)}`,
|
|
203
|
-
timestamp: new Date().toISOString(),
|
|
204
|
-
source: "events",
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// WebSocket message handler - echo messages back and broadcast to channel
|
|
209
|
-
ctx.core.websocket.onMessage(async (clientId, event, data) => {
|
|
210
|
-
ctx.core.logger.info("WebSocket message received", { clientId, event, data });
|
|
211
|
-
|
|
212
|
-
// Echo the message back to the sender
|
|
213
|
-
if (event === "echo") {
|
|
214
|
-
ctx.core.websocket.send(clientId, "echo-reply", {
|
|
215
|
-
original: data,
|
|
216
|
-
timestamp: new Date().toISOString(),
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Broadcast to a channel if requested
|
|
221
|
-
if (event === "broadcast" && data?.channel) {
|
|
222
|
-
ctx.core.websocket.broadcast(data.channel, "ws-broadcast", {
|
|
223
|
-
from: clientId,
|
|
224
|
-
message: data.message,
|
|
225
|
-
timestamp: new Date().toISOString(),
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Log WebSocket activity to audit trail
|
|
230
|
-
await ctx.core.audit.log({
|
|
231
|
-
action: "websocket.message",
|
|
232
|
-
actor: clientId,
|
|
233
|
-
resource: "websocket",
|
|
234
|
-
resourceId: event,
|
|
235
|
-
metadata: { event, dataSize: JSON.stringify(data).length },
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
// Audit important events for compliance tracking
|
|
240
|
-
ctx.core.events.on("job.completed", async (data: any) => {
|
|
241
|
-
await ctx.core.audit.log({
|
|
242
|
-
action: "job.completed",
|
|
243
|
-
actor: "system",
|
|
244
|
-
resource: "job",
|
|
245
|
-
resourceId: data.jobId,
|
|
246
|
-
metadata: { name: data.name },
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
ctx.core.events.on("workflow.completed", async (data: any) => {
|
|
251
|
-
await ctx.core.audit.log({
|
|
252
|
-
action: "workflow.completed",
|
|
253
|
-
actor: "system",
|
|
254
|
-
resource: "workflow",
|
|
255
|
-
resourceId: data.instanceId,
|
|
256
|
-
metadata: { workflowName: data.workflowName },
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
ctx.core.logger.info("Demo plugin initialized with all core services (including audit & websocket)");
|
|
261
|
-
},
|
|
262
|
-
});
|